diff --git a/.hgtags b/.hgtags index b771281cb21018816b26cb6535c71457e1baec03..fbce080e7b2ba96654446f111ab61215fb5cfd40 100644 --- a/.hgtags +++ b/.hgtags @@ -188,3 +188,11 @@ ddfe863807617f21f6d75216bed144c791f5cab1 OpenOLAT 11.4.2 f0de363ab794a6e0d6f4d6da57f460503d5dfa91 OpenOLAT 11.5.0 dda2b6a8c3454872516fac37667698425802fc97 OpenOLAT 11.5.1 355d21cc46068ffa18c18c479efa6d402cb484ec OpenOLAT 11.5.2 +0e8d6b8d69a92131e4b38e9117e09fb297eef38e OpenOLAT 11.5.3 +614f0f09f5a7a915a3a364e3f5641e9179dc7735 OpenOLAT 12.0.0 +03f92c40a74397b179cce2b4b2d3346c29a20e64 OpenOLAT 12.0.1 +9266c599d0a13634e44724540a37fb4161e29f98 OpenOLAT 11.5.4 +15761fa18b4b2eebe3e4592e4289527989c7f256 OpenOLAT 12.0.2 +cd13b2d55dde9f3f3ba9f31e10f9d02493740891 OpenOLAT 12.1.0 +cd13b2d55dde9f3f3ba9f31e10f9d02493740891 OpenOLAT 12.1.0 +90e4eea2b8b7c50c8f89e9c52174a51010cf375f OpenOLAT 12.1.0 diff --git a/pom.xml b/pom.xml index 01fefe5c488391afe35688a49e02a3c159e766ab..306e36702a39de98226113b36d134c70b411ad7e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.openolat</groupId> <artifactId>openolat-lms</artifactId> - <version>12.0-SNAPSHOT</version> + <version>12.2-SNAPSHOT</version> <packaging>war</packaging> <name>OpenOLAT LMS</name> <url>http://www.openolat.org</url> @@ -62,7 +62,7 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <targetJdk>1.8</targetJdk> - <org.springframework.version>3.2.18.RELEASE</org.springframework.version> + <org.springframework.version>4.3.10.RELEASE</org.springframework.version> <org.hibernate.version>5.2.10.Final</org.hibernate.version> <com.sun.jersey.version>1.19.4</com.sun.jersey.version> <jackson.version>1.9.2</jackson.version> @@ -71,7 +71,7 @@ <org.infinispan.version>8.2.5.Final</org.infinispan.version> <lucene.version>4.8.0</lucene.version> <version.selenium>3.4.0</version.selenium> - <version.drone>2.2.0</version.drone> + <version.drone>2.3.1</version.drone> <activemq.version>5.11.1</activemq.version> <qtiworks.version>1.0.4</qtiworks.version> @@ -269,6 +269,13 @@ <include>${basedir}/target/jquery/tinymce4/tinymce/plugins/olatmovieviewer/plugin.min.js</include> </includes> </aggregation> + <aggregation> + <output>${basedir}/src/main/webapp/static/js/tinymce4/tinymce/plugins/olatcharcount/plugin.min.js</output> + <removeIncluded>false</removeIncluded> + <includes> + <include>${basedir}/target/jquery/tinymce4/tinymce/plugins/olatcharcount/plugin.min.js</include> + </includes> + </aggregation> <aggregation> <output>${basedir}/src/main/webapp/static/js/tinymce4/tinymce/plugins/olatsmileys/plugin.min.js</output> <removeIncluded>false</removeIncluded> @@ -1298,7 +1305,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> - <version>1.7</version> + <version>1.8</version> <executions> <!-- Copy the notice.txt file --> <execution> @@ -1316,18 +1323,18 @@ </execution> <!-- Download tomcat for integration test --> <execution> - <phase>pre-integration-test</phase> - <goals> - <goal>run</goal> - </goals> - <configuration> - <tasks> - <mkdir dir="${project.build.directory}/downloads" /> - <get src="http://nexus.openolat.org/nexus/content/repositories/openolat/org/apache/tomcat/apache-tomcat-arq/8.0.24/apache-tomcat-arq-8.0.24.zip" dest="${project.build.directory}/downloads" verbose="true" skipexisting="true" /> - <unzip src="${project.build.directory}/downloads/apache-tomcat-arq-8.0.24.zip" dest="${project.build.directory}/arq-apache-tomcat-8.0.24" /> - </tasks> - </configuration> - </execution> + <phase>pre-integration-test</phase> + <goals> + <goal>run</goal> + </goals> + <configuration> + <target> + <mkdir dir="${project.build.directory}/downloads" /> + <get src="https://nexus.openolat.org/nexus/content/repositories/openolat/org/apache/tomcat/apache-tomcat-arq/8.0.24/apache-tomcat-arq-8.0.24.zip" dest="${project.build.directory}/downloads" verbose="true" skipexisting="true" /> + <unzip src="${project.build.directory}/downloads/apache-tomcat-arq-8.0.24.zip" dest="${project.build.directory}/arq-apache-tomcat-8.0.24" /> + </target> + </configuration> + </execution> </executions> </plugin> <!-- Unit tests --> @@ -1342,6 +1349,7 @@ <systemPropertyVariables> <java.io.tmpdir>${project.build.directory}/olatdata</java.io.tmpdir> </systemPropertyVariables> + <trimStackTrace>false</trimStackTrace> <testNGArtifactName>none:none</testNGArtifactName> <includes> <include>org/olat/test/AllTestsJunit4.java</include> @@ -1360,7 +1368,7 @@ <skipTests>${skipSeleniumTests}</skipTests> <reuseForks>false</reuseForks> <argLine>-Xmx512m -Xms256m -Djava.awt.headless=true</argLine> - + <trimStackTrace>false</trimStackTrace> <systemPropertyVariables> <profile>${test.env}</profile> <test.env.db.name>${test.env.db.name}</test.env.db.name> @@ -2296,7 +2304,7 @@ <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> - <version>1.8.6</version> + <version>2.2.3</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> @@ -2574,7 +2582,7 @@ <dependency> <groupId>org.jboss.arquillian.graphene</groupId> <artifactId>graphene-webdriver</artifactId> - <version>2.2.1</version> + <version>2.3.1</version> <type>pom</type> <scope>test</scope> </dependency> @@ -2644,7 +2652,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-report-plugin</artifactId> - <version>2.19.1</version> + <version>2.20</version> </plugin> </plugins> </reporting> diff --git a/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml b/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml index 548ddfc686c3c551048fb2c5f60fa0824465d87d..35e4bd045d5432eaa96db7e1fddddb15979f6818 100644 --- a/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml +++ b/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml @@ -64,9 +64,9 @@ <!-- ################################## --> <!-- # VIRTUAL CLASSROOM SERVICE JOBS # --> <!-- ################################## --> - <bean id="adobeCleanupJob" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="adobeCleanupJob" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail"> - <bean class="org.springframework.scheduling.quartz.JobDetailBean"> + <bean class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="de.bps.course.nodes.vc.provider.adobe.AdobeConnectCleanupJob" /> <property name="jobDataAsMap"> <map> diff --git a/src/main/java/de/bps/olat/portal/links/LinksPortletRunController.java b/src/main/java/de/bps/olat/portal/links/LinksPortletRunController.java index eb8e42aecf4fb6b8228dceb605d3fc2a0c23f64a..209120917e9057e10f060615dbad70a103f1d262 100644 --- a/src/main/java/de/bps/olat/portal/links/LinksPortletRunController.java +++ b/src/main/java/de/bps/olat/portal/links/LinksPortletRunController.java @@ -38,8 +38,8 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.id.UserConstants; -import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -58,6 +58,9 @@ public class LinksPortletRunController extends BasicController { private Link backLink; private DialogBoxController delLinkCtrl; + @Autowired + private I18nModule i18nModule; + protected LinksPortletRunController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); @@ -76,9 +79,9 @@ public class LinksPortletRunController extends BasicController { } private void initOrUpdatePortletView(UserRequest ureq){ - String lang = I18nManager.getInstance().getLocaleKey(ureq.getLocale()); + String lang = i18nModule.getLocaleKey(ureq.getLocale()); if (lang == null) { - lang = I18nManager.getInstance().getLocaleKey(I18nModule.getDefaultLocale()); + lang = i18nModule.getLocaleKey(I18nModule.getDefaultLocale()); } // fxdiff: compare with language-base not with variant... int underlinePos = lang.indexOf("_"); @@ -199,7 +202,7 @@ public class LinksPortletRunController extends BasicController { } } else if (linkName.contains(LINKADD)){ // add a link to institution: - PortletLink newLink = new PortletLink("", "", "", I18nManager.getInstance().getLocaleKey(ureq.getLocale()), "", null); + PortletLink newLink = new PortletLink("", "", "", i18nModule.getLocaleKey(ureq.getLocale()), "", null); // find institution and port in link! String institution = link.getCommand().substring(LINKADD.length()); PortletInstitution inst = LinksPortlet.getContent().get(institution); diff --git a/src/main/java/de/bps/onyx/plugin/OnyxResultManager.java b/src/main/java/de/bps/onyx/plugin/OnyxResultManager.java index 554afe0087f39fed67ac1be4c0d673163d6d1c24..d025cd096e1e9a7f363f44d0bfad5614a0604511 100644 --- a/src/main/java/de/bps/onyx/plugin/OnyxResultManager.java +++ b/src/main/java/de/bps/onyx/plugin/OnyxResultManager.java @@ -53,6 +53,7 @@ import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.ims.qti.QTIResultSet; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import de.bps.webservices.clients.onyxreporter.OnyxReporterConnector; @@ -194,7 +195,7 @@ public class OnyxResultManager { ScoreEvaluation sc = OnyxModule.getUserScoreEvaluationFromQtiResult(userCourseEnvironment.getCourseEnvironment().getCourseResourceableId(), node, bestResultConfigured, qtiResultSet.getIdentity()); if(node instanceof AssessableCourseNode){ - ((AssessableCourseNode) node).updateUserScoreEvaluation(sc, userCourseEnvironment, qtiResultSet.getIdentity(), false); + ((AssessableCourseNode) node).updateUserScoreEvaluation(sc, userCourseEnvironment, qtiResultSet.getIdentity(), false, Role.coach); } } else { diff --git a/src/main/java/de/bps/onyx/plugin/_spring/onyxContext.xml b/src/main/java/de/bps/onyx/plugin/_spring/onyxContext.xml index a2d626a2e08a3af500d76fa9b933e0b03641deb1..8f8f2d6ba8056f982ab61363c09aed0b414b6c74 100644 --- a/src/main/java/de/bps/onyx/plugin/_spring/onyxContext.xml +++ b/src/main/java/de/bps/onyx/plugin/_spring/onyxContext.xml @@ -6,13 +6,13 @@ http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- update job for onyx results --> -<bean id="updateQtiResultsTriggerOnyx" class="org.springframework.scheduling.quartz.CronTriggerBean"> +<bean id="updateQtiResultsTriggerOnyx" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="updateOnyxResults.${onyx.update.results.job}" /> <property name="cronExpression" value="0 0 2 * * ?"/><!-- 2am, daily --> <property name="startDelay" value="90000" /> </bean> -<bean id="updateOnyxResults.enabled" class="org.springframework.scheduling.quartz.JobDetailBean"> +<bean id="updateOnyxResults.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="de.bps.jobs.UpdateOnyxResults" /> <property name="jobDataAsMap"> <map> @@ -21,7 +21,7 @@ </property> </bean> -<bean id="updateOnyxResults.disabled" class="org.springframework.scheduling.quartz.JobDetailBean"> +<bean id="updateOnyxResults.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- NOTE: reusing the notifications.DummyJob here --> <property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" /> </bean> diff --git a/src/main/java/de/bps/onyx/plugin/run/OnyxRunController.java b/src/main/java/de/bps/onyx/plugin/run/OnyxRunController.java index 8e03bf8b5f4b17f06efb17b6a375e688f48886f2..0ffbba6e302d5ef1b03836a4f934c0787d1d14a3 100644 --- a/src/main/java/de/bps/onyx/plugin/run/OnyxRunController.java +++ b/src/main/java/de/bps/onyx/plugin/run/OnyxRunController.java @@ -72,6 +72,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.fileresource.FileResourceManager; import org.olat.ims.qti.QTIResultSet; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import de.bps.onyx.plugin.OnyxModule; @@ -569,7 +570,7 @@ public class OnyxRunController extends BasicController { //now increase attempts; if an exception occurred before, this will be not reached if (currentState != TestState.CANCELED) { AssessmentManager am = course.getCourseEnvironment().getAssessmentManager(); - am.incrementNodeAttempts(courseNode, student, userCourseEnv); + am.incrementNodeAttempts(courseNode, student, userCourseEnv, Role.user); } } else { assessmentId = resultSet.getAssessmentID(); diff --git a/src/main/java/de/bps/onyx/plugin/run/_i18n/LocalStrings_pt_BR.properties b/src/main/java/de/bps/onyx/plugin/run/_i18n/LocalStrings_pt_BR.properties index 5cc5c4015d06f5c041a70d60b38ff54e67b41bdc..d05b450ace0e82065156a237bafba8d9a19845ec 100644 --- a/src/main/java/de/bps/onyx/plugin/run/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/de/bps/onyx/plugin/run/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Fri Jun 23 15:07:24 CEST 2017 +#Tue Sep 19 20:29:40 CEST 2017 Intro.surv=Pressione Iniciar para come\u00E7ar com o question\u00E1rio assessment.notfullyassessed=A avalia\u00E7\u00E3o para este teste ainda est\u00E1 incompleta. <br/>O teste cont\u00E9m tarefas com avalia\u00E7\u00F5es pendentes, estas ser\u00E3o avaliadas manualmente mais tarde e usadas para recalcular a avalia\u00E7\u00E3o do teste. assessment.state=Status diff --git a/src/main/java/de/bps/onyx/plugin/wsserver/ReturnWSService.java b/src/main/java/de/bps/onyx/plugin/wsserver/ReturnWSService.java index 96e00d5e33b572ae874bea287d78f67247af3b49..0a2177e53a2bcc3c61456eaef23be61545ce67fb 100644 --- a/src/main/java/de/bps/onyx/plugin/wsserver/ReturnWSService.java +++ b/src/main/java/de/bps/onyx/plugin/wsserver/ReturnWSService.java @@ -51,6 +51,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.ims.qti.QTIResultManager; import org.olat.ims.qti.QTIResultSet; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import de.bps.onyx.plugin.OnyxResultManager; @@ -221,7 +222,7 @@ public class ReturnWSService { } ScoreEvaluation scoreEvaluation = new ScoreEvaluation(qtiResultSet.getScore(), qtiResultSet.getIsPassed(), status, Boolean.TRUE, qtiResultSet.getFullyAssessed(), qtiResultSet.getAssessmentID()); - am.saveScoreEvaluation((AssessableCourseNode)courseNode, null, assessedIdentity, scoreEvaluation, userCourseEnvironment, false); + am.saveScoreEvaluation((AssessableCourseNode)courseNode, null, assessedIdentity, scoreEvaluation, userCourseEnvironment, false, Role.coach); CoreSpringFactory.getImpl(AssessmentNotificationsHandler.class).markPublisherNews(assessedIdentity, resourceId); } diff --git a/src/main/java/org/olat/_spring/mainContext.xml b/src/main/java/org/olat/_spring/mainContext.xml index 9f281a42f91f42cbd438ab468aaabba805ee34a9..a9f827a6f326f12fd9521ea06e34ad8b313e1398 100644 --- a/src/main/java/org/olat/_spring/mainContext.xml +++ b/src/main/java/org/olat/_spring/mainContext.xml @@ -8,7 +8,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - <context:component-scan base-package="org.olat.note,org.olat.social,org.olat.commons.memberlist" /> + <context:component-scan base-package="org.olat.note,org.olat.social,org.olat.commons.memberlist,org.olat.commons.info" /> <import resource="classpath:/org/olat/core/util/threadlog/_spring/threadlogCorecontext.xml"/> <import resource="classpath:/org/olat/core/_spring/mainCorecontext.xml"/> @@ -24,7 +24,6 @@ <import resource="classpath:/org/olat/basesecurity/_spring/baseSecurityContext.xml"/> <import resource="classpath:/org/olat/collaboration/_spring/collaborationToolsContext.xml"/> <import resource="classpath:/org/olat/commons/calendar/_spring/calendarContext.xml"/> - <import resource="classpath:/org/olat/commons/info/_spring/infoMessageContext.xml"/> <import resource="classpath:/org/olat/commons/servlets/_spring/staticContext.xml"/> <import resource="classpath:/org/olat/course/_spring/courseContext.xml"/> diff --git a/src/main/java/org/olat/admin/jmx/DumpJMXJob.java b/src/main/java/org/olat/admin/jmx/DumpJMXJob.java deleted file mode 100644 index 37f992d83953631844b324520e75ad067f4eebb8..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/DumpJMXJob.java +++ /dev/null @@ -1,67 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.admin.jmx; - -import java.util.List; - -import org.olat.core.CoreSpringFactory; -import org.olat.core.commons.services.scheduler.JobWithDB; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; - - -/** - * Description:<br> - * a job which regularly dumps jmx data to the log - * - * @author Felix Jost - */ -public class DumpJMXJob extends JobWithDB { - - @Override - public void executeWithDB(JobExecutionContext context) - throws JobExecutionException { - - boolean enabled = context.getMergedJobDataMap().getBooleanFromString("enabled"); - if (enabled) { - JMXManager jmxManager = CoreSpringFactory.getImpl(JMXManager.class); - String[] keys = context.getMergedJobDataMap().getKeys(); - // loop over all - for (int i = 0; i < keys.length; i++) { - String key = keys[i]; - if (key.endsWith("Bean")) { - // ok, key is a bean name => dump this bean - String beanName = context.getMergedJobDataMap().getString(key); - List<String> jmxDumpList = jmxManager.dumpJmx(beanName); - StringBuilder buf = new StringBuilder(); - for (String jmxDump : jmxDumpList) { - buf.append(jmxDump).append(";"); - } - log.info(key + ":" + buf.toString()); - } - } - } - } -} diff --git a/src/main/java/org/olat/admin/jmx/JMXInfoController.java b/src/main/java/org/olat/admin/jmx/JMXInfoController.java deleted file mode 100644 index 72fb79aa1929bd2432e7ae15923a8f8c3faf77c3..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/JMXInfoController.java +++ /dev/null @@ -1,82 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.admin.jmx; - -import java.util.List; - -import org.olat.core.CoreSpringFactory; -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.panel.Panel; -import org.olat.core.gui.components.velocity.VelocityContainer; -import org.olat.core.gui.control.Event; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.control.controller.BasicController; - -/** - * Description:<br> - * Dump the JMX context and show the output - * - * <P> - * Initial Date: 01.10.2007 <br> - * @author Felix Jost, http://www.goodsolutions.ch - */ -public class JMXInfoController extends BasicController { - - private final JMXManager jmxManager; - - /** - * @param ureq - * @param wControl - */ - public JMXInfoController(UserRequest ureq, WindowControl wControl) { - super(ureq, wControl); - - jmxManager = CoreSpringFactory.getImpl(JMXManager.class); - if (!jmxManager.isActive()) { - showError("nojmx"); - putInitialPanel(new Panel("empty")); - return; - } - - VelocityContainer mainVc = createVelocityContainer("jmxmain"); - List<String> jmxres = jmxManager.dumpJmx("org.olat.core.commons.modules.bc:name=FilesInfoMBean"); - mainVc.contextPut("jmxlist", jmxres); - String htmlRes = jmxManager.dumpAll(); - mainVc.contextPut("jmxdump", htmlRes); - - putInitialPanel(mainVc); - } - - @Override - protected void doDispose() { - // - } - - @Override - protected void event(UserRequest ureq, Component source, Event event) { - // - } -} \ No newline at end of file diff --git a/src/main/java/org/olat/admin/jmx/_content/jmxmain.html b/src/main/java/org/olat/admin/jmx/_content/jmxmain.html deleted file mode 100644 index 5aedafb495a2b4ffa7e2884b4a876e839e09cd3e..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_content/jmxmain.html +++ /dev/null @@ -1,9 +0,0 @@ -<h3>JMX values (v0.1!)</h3> -<ul> -#foreach ($entry in $jmxlist) - <li>$entry</li> -#end -</ul> - -<h4>jmx dump</h4> -$jmxdump diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_ar.properties deleted file mode 100644 index 9fd32e9c67c9da55e1bf6cd22890d90c968b2a0b..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_ar.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Feb 22 10:58:21 CET 2010 -nojmx=(cf. olat_config.xml)JMX \u0644\u0645 \u064A\u062A\u0645 \u062A\u0646\u0634\u064A\u0637 \u0648\u062D\u062F\u0629 diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_bg.properties deleted file mode 100644 index 102cfb744e7395ece3c56e1d3d8b8f90465d1341..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_bg.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon May 25 22:31:24 CEST 2009 -nojmx=\u041C\u043E\u0434\u0443\u043B\u044A\u0442 JMX \u043D\u0435 \u0435 \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u0430\u043D (\u0432\u0438\u0436\u0442\u0435 olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_cs.properties deleted file mode 100644 index e5dede890cd1a9c3c846f2c0394890f47b23c45c..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_cs.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:54:13 CET 2009 -nojmx=JMX modul nen\u00ED aktivov\u00E1n (olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_de.properties deleted file mode 100644 index 72a22e440649e5b7fdb684b9990c0cfe2d431192..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_de.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:54:03 CET 2009 -nojmx=JMX Modul ist nicht aktiviert (vgl olat.local.properies) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_el.properties deleted file mode 100644 index 47c84a178ef6b3a181fc23ae144849de7d98f93f..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_el.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:54:15 CET 2009 -nojmx=\u03A4\u03BF module JMX \u03B4\u03B5\u03BD \u03B5\u03AF\u03BD\u03B1\u03B9 \u03B5\u03BD\u03B5\u03C1\u03B3\u03BF\u03C0\u03BF\u03B9\u03B7\u03BC\u03AD\u03BD\u03BF (\u03B4\u03B5\u03AF\u03C4\u03B5 \u03C3\u03C4\u03BF olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_en.properties deleted file mode 100644 index 4b5cc6ef31537b97f6acd4d9bf6f5906d1f2dd78..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_en.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Feb 01 17:38:46 CET 2010 -nojmx=JMX module not activated (cf. olat.local.properties) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_es.properties deleted file mode 100644 index 073b8f5e8b8a2f868df679fdc976f99185462d39..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_es.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:54:20 CET 2009 -nojmx=JMX m\u00F3dulo no activado (Ver olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_fr.properties deleted file mode 100644 index 22b702c4a42894b1c911803cf798d02c758ab849..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_fr.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:54:07 CET 2009 -nojmx=Le module JMX n'est pas activ\u00E9 (voir olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_it.properties deleted file mode 100644 index 58114baccc68a5be0277edf026aaf71327f235c7..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_it.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:54:09 CET 2009 -nojmx=Il modulo JMX non \u00E8 attivato (cfr. olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_jp.properties deleted file mode 100644 index a908ee574fb0e2059891b50598e905793b3081a6..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_jp.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Fri Jul 17 19:44:42 CEST 2009 -nojmx=JMX\u30E2\u30B8\u30E5\u30FC\u30EB\u306F\u6709\u52B9\u5316\u3055\u308C\u3066\u3044\u307E\u305B\u3093 (olat_config.xml\u3092\u3054\u89A7\u304F\u3060\u3055\u3044)\u3002 diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_nl_NL.properties deleted file mode 100644 index 85d8c43c8ff4aee1147f428d92abcf76fd806ad0..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_nl_NL.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Thu Sep 08 16:42:42 CEST 2011 -nojmx=JMX module noet geactiveerd (cf. olat.local.properties) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_pl.properties deleted file mode 100644 index a2b9a5d79656c4909502a350584d2a28a455dfbe..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_pl.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:54:16 CET 2009 -nojmx=Modu\u0142 KMX nie jest aktywny (zabacz\: olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_pt_BR.properties deleted file mode 100644 index 0df6adbe7f7d05c3b9bd7e0abc729631e3372a4c..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_pt_BR.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:53:59 CET 2009 -nojmx=JMX Module n\u00E3o est\u00E1 ativado (ver olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_ru.properties deleted file mode 100644 index 6702a3ba651affbc217055bf666f3bd2e121cdb9..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_ru.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Thu Sep 24 01:47:31 CEST 2009 -nojmx=\u041C\u043E\u0434\u0443\u043B\u044C JMX \u0434\u0435\u0437\u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D (\u0441\u043C\u043E\u0442\u0440\u0438 olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_sq.properties deleted file mode 100644 index ca842e1b82a9e04241591e4625013dd16e2b7017..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_sq.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:54:11 CET 2009 -nojmx=Moduli JMX nuk \u00EBsht\u00EB aktiv (shikoni olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_zh_CN.properties deleted file mode 100644 index 6c4ce01ead7cf8eadc9688b29d158c25d1ab365c..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_zh_CN.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Sun Dec 20 07:08:47 CET 2009 -nojmx=JMX \u6A21\u5F0F\u672A\u542F\u52A8(\u53C2\u89C1olat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_zh_TW.properties deleted file mode 100644 index 3db6f0759c926f16111b4edc9e88e53f651f76ed..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/_i18n/LocalStrings_zh_TW.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Mar 02 09:54:05 CET 2009 -nojmx=JMX \u6A21\u7D44\u672A\u555F\u7528(\u6AA2\u8996\u4E00\u4E0Bolat_config.xml) diff --git a/src/main/java/org/olat/admin/jmx/_spring/jmxContext.xml b/src/main/java/org/olat/admin/jmx/_spring/jmxContext.xml index 6550f052a7c8150a821a2293de38191cfd760c0a..4bac2b5f7f12f485d192729eb59d1673f0fd62ac 100644 --- a/src/main/java/org/olat/admin/jmx/_spring/jmxContext.xml +++ b/src/main/java/org/olat/admin/jmx/_spring/jmxContext.xml @@ -16,39 +16,5 @@ <bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean" lazy-init="true"> <property name="port" value="${jmx.rmi.port}"/> </bean> - - <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false" > - <property name="beans"> - <map> - <entry key="org.olat.admin.jmx.datasources:name=ThreadAndControllerInfo"> - <bean class="org.olat.admin.jmx.datasources.ThreadAndControllerInfo" /> - </entry> - <entry key="org.olat.admin:name=AdminModule" value-ref="adminModule" /> - <entry key="org.olat.core.commons.modules.bc:name=FilesInfoMBean" > - <ref bean="org.olat.core.commons.modules.bc.FilesInfoMBean"/> - </entry> - </map> - </property> - <property name="server" ref="org.springframework.jmx.support.MBeanServerFactoryBean"/> - </bean> - -<!-- DISABLE JMX CONNECTOR - <bean id="serverConnector" - class="org.springframework.jmx.support.ConnectorServerFactoryBean" depends-on="registry"> - <property name="objectName" value="connector:name=rmi"/> - <property name="serviceUrl" - value="service:jmx:rmi://localhost/jndi/rmi://localhost:${jmx.rmi.port}/olat_connector"/> - <property name="daemon" value="true"/> - <property name="environment"> ---> - <!-- the following is only valid when the sun jmx implementation is used --> -<!-- DISABLE JMX CONNECTOR - <map> - <entry key="jmx.remote.x.password.file" value="/usr/local/opt/java/jre/lib/management/jmxremote.password"/> - <entry key="jmx.remote.x.access.file" value="/usr/local/opt/java/jre/lib/management/jmxremote.access"/> - </map> - </property> - </bean> ---> </beans> diff --git a/src/main/java/org/olat/admin/jmx/datasources/ThreadAndControllerInfo.java b/src/main/java/org/olat/admin/jmx/datasources/ThreadAndControllerInfo.java deleted file mode 100644 index ed6dfab9c52f107f108fdbc984e4ae5d359342de..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/admin/jmx/datasources/ThreadAndControllerInfo.java +++ /dev/null @@ -1,67 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.admin.jmx.datasources; - -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryMXBean; - -import org.olat.admin.sysinfo.manager.SessionStatsManager; -import org.olat.core.CoreSpringFactory; -import org.olat.core.gui.control.DefaultController; -import org.olat.core.util.session.UserSessionManager; - -/** - * Description:<br> - * TODO: - * - * <P> - * Initial Date: 02.10.2007 <br> - * @author Felix Jost, http://www.goodsolutions.ch - */ -public class ThreadAndControllerInfo { - private static MemoryMXBean mbean = ManagementFactory.getMemoryMXBean(); - - public int getConcurrentThreads() { - return CoreSpringFactory.getImpl(SessionStatsManager.class).getConcurrentCounter(); - } - - public int getControllerCount() { - return DefaultController.getControllerCount(); - } - - public int getAuthenticatedNodeUsersCount() { - return CoreSpringFactory.getImpl(UserSessionManager.class).getNumberOfAuthenticatedUserSessions(); - } - - public long getMemoryHeapUsageKB() { - return mbean.getHeapMemoryUsage().getUsed() / 1024; - } - - public long getThreadCount() { - ThreadGroup tg = Thread.currentThread().getThreadGroup(); - return tg.activeCount(); - } - -} diff --git a/src/main/java/org/olat/admin/notifications/NotificationsEmailAdminController.java b/src/main/java/org/olat/admin/notifications/NotificationsEmailAdminController.java index 2e33fbdee0dcf8689b6f5129e1deee7017ed1ef2..958f10a11d48b2e30f9af9741057460d613cf7fd 100644 --- a/src/main/java/org/olat/admin/notifications/NotificationsEmailAdminController.java +++ b/src/main/java/org/olat/admin/notifications/NotificationsEmailAdminController.java @@ -24,6 +24,8 @@ */ package org.olat.admin.notifications; +import java.util.List; + import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; @@ -33,10 +35,12 @@ import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; -import org.quartz.JobDetail; +import org.quartz.CronTrigger; +import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; -import org.springframework.scheduling.quartz.CronTriggerBean; +import org.quartz.Trigger; +import org.springframework.beans.factory.annotation.Autowired; /** @@ -49,20 +53,26 @@ import org.springframework.scheduling.quartz.CronTriggerBean; */ public class NotificationsEmailAdminController extends BasicController { private static final String TRIGGER_NOTIFY = "notification.start.button"; + + private final JobKey notificationsJobKey = new JobKey("org.olat.notifications.job.enabled", Scheduler.DEFAULT_GROUP); - private VelocityContainer content; private Link startNotifyButton; + + @Autowired + private Scheduler scheduler; public NotificationsEmailAdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); - content = createVelocityContainer("index"); + VelocityContainer content = createVelocityContainer("index"); boolean enabled; String cronExpression = ""; try { CoreSpringFactory.getBean("org.olat.notifications.job.enabled"); enabled = true; - CronTriggerBean bean = (CronTriggerBean)CoreSpringFactory.getBean("sendNotificationsEmailTrigger"); - cronExpression = bean.getCronExpression(); + List<? extends Trigger> triggers = scheduler.getTriggersOfJob(notificationsJobKey); + if(triggers.size() == 1 && triggers.get(0) instanceof CronTrigger) { + cronExpression = ((CronTrigger)triggers.get(0)).getCronExpression(); + } } catch (Exception e) { enabled = false; } @@ -71,31 +81,20 @@ public class NotificationsEmailAdminController extends BasicController { putInitialPanel(content); } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.components.Component, - * org.olat.core.gui.control.Event) - */ @Override public void event(UserRequest ureq, Component source, Event event) { if (source == startNotifyButton) { //trigger the cron job try { - Scheduler scheduler = CoreSpringFactory.getImpl(Scheduler.class); - JobDetail detail = scheduler.getJobDetail("org.olat.notifications.job.enabled", Scheduler.DEFAULT_GROUP); - scheduler.triggerJob(detail.getName(), detail.getGroup()); + CoreSpringFactory.getImpl(Scheduler.class).triggerJob(notificationsJobKey); } catch (SchedulerException e) { logError("", e); } } } - /** - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ @Override protected void doDispose() { //nothing to do } - -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java b/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java index 6a5b002b2f893de30b7778d51cd45490cd0546ab..382943cc484a646115eac4f068c0a73af79aa844 100644 --- a/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java +++ b/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java @@ -43,7 +43,6 @@ import org.olat.core.util.vfs.QuotaManager; * Description:<BR> * Generic editor controller for quotas. Can be constructed from a quota or a * folder path. When finished the controller fires the following events:<BR> - * Event.CANCELLED_EVENT * Event.CHANGED_EVENT * <p> * Check with QuotaManager.hasQuotaEditRights if you are allowed to use this @@ -57,11 +56,9 @@ public class GenericQuotaEditController extends BasicController { private VelocityContainer myContent; private QuotaForm quotaForm; - private boolean modalMode; private Quota currentQuota; private Link delQuotaButton; - private Link cancelButton; /** @@ -73,12 +70,9 @@ public class GenericQuotaEditController extends BasicController { * @param ureq * @param wControl * @param quotaPath The path for which the quota should be edited - * @param modalMode true: window will push to fullscreen and pop itself when finished. false: normal - * controller mode, get initial component using getInitialComponent() */ - GenericQuotaEditController(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode) { + GenericQuotaEditController(UserRequest ureq, WindowControl wControl, String relPath) { super(ureq, wControl); - this.modalMode = modalMode; // check if quota foqf.cannot.del.defaultr this path already exists QuotaManager qm = QuotaManager.getInstance(); @@ -103,7 +97,6 @@ public class GenericQuotaEditController extends BasicController { */ public GenericQuotaEditController(UserRequest ureq, WindowControl wControl, Quota quota) { super(ureq, wControl); - this.modalMode = false; initMyContent(ureq); @@ -119,6 +112,26 @@ public class GenericQuotaEditController extends BasicController { putInitialPanel(myContent); } + /** + * Constructor for the generic quota edit controller used when a new + * existing quota should be edited. + * + * @param ureq + * @param wControl + */ + public GenericQuotaEditController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + initMyContent(ureq); + + // start with new quota + currentQuota = QuotaManager.getInstance().createQuota(null, null, null); + myContent.contextPut("isEmptyQuota", true); + initQuotaForm(ureq, currentQuota); + + putInitialPanel(myContent); + } + private void initMyContent(UserRequest ureq) { QuotaManager qm = QuotaManager.getInstance(); if (!qm.hasQuotaEditRights(ureq.getIdentity())) { @@ -126,10 +139,8 @@ public class GenericQuotaEditController extends BasicController { } myContent = createVelocityContainer("edit"); - myContent.contextPut("modalMode", Boolean.valueOf(modalMode)); LinkFactory.createButtonSmall("qf.new", myContent, this); delQuotaButton = LinkFactory.createButtonSmall("qf.del", myContent, this); - cancelButton = LinkFactory.createButtonSmall("cancel", myContent, this); myContent.contextPut("users",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_USERS)); myContent.contextPut("powerusers",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_POWER)); @@ -151,9 +162,7 @@ public class GenericQuotaEditController extends BasicController { myContent.contextPut("editQuota", Boolean.TRUE); } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ + @Override public void event(UserRequest ureq, Component source, Event event) { initQuotaForm(ureq, currentQuota); if (source == delQuotaButton){ @@ -166,14 +175,10 @@ public class GenericQuotaEditController extends BasicController { } else { showError("qf.cannot.del.default"); } - } else if(source == cancelButton){ - fireEvent(ureq, Event.CANCELLED_EVENT); } } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) - */ + @Override public void event(UserRequest ureq, Controller source, Event event) { if (source == quotaForm) { if (event == Event.DONE_EVENT) { @@ -184,17 +189,13 @@ public class GenericQuotaEditController extends BasicController { } } } - /** - * @return Quota the edited quota - */ + public Quota getQuota() { if (currentQuota == null) throw new AssertException("getQuota called but currentQuota is null"); return currentQuota; } - /** - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ + @Override protected void doDispose() { // } diff --git a/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java b/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java index 22d7d4467ed7e45642f91f7c57f95df99a586230..a99dea8f06470ec88617dfdb56e1608da62691cd 100644 --- a/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java +++ b/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java @@ -44,7 +44,6 @@ public class GenericQuotaViewController extends BasicController { private VelocityContainer myContent; private QuotaForm quotaForm; - private boolean modalMode; private Quota currentQuota; @@ -57,12 +56,9 @@ public class GenericQuotaViewController extends BasicController { * @param ureq * @param wControl * @param quotaPath The path for which the quota should be edited - * @param modalMode true: window will push to fullscreen and pop itself when finished. false: normal - * controller mode, get initial component using getInitialComponent() */ - GenericQuotaViewController(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode) { + GenericQuotaViewController(UserRequest ureq, WindowControl wControl, String relPath) { super(ureq, wControl); - this.modalMode = modalMode; // check if quota foqf.cannot.del.defaultr this path already exists QuotaManager qm = QuotaManager.getInstance(); @@ -86,7 +82,6 @@ public class GenericQuotaViewController extends BasicController { QuotaManager qm = QuotaManager.getInstance(); myContent = createVelocityContainer("edit"); myContent.contextPut("notEnoughPrivilege", Boolean.FALSE); - myContent.contextPut("modalMode", Boolean.valueOf(modalMode)); myContent.contextPut("users",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_USERS)); myContent.contextPut("powerusers",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_POWER)); myContent.contextPut("groups",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_GROUPS)); diff --git a/src/main/java/org/olat/admin/quota/QuotaByteRenderer.java b/src/main/java/org/olat/admin/quota/QuotaByteRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..3c951c516c6e8e55088e21416fb06be7b9bc9028 --- /dev/null +++ b/src/main/java/org/olat/admin/quota/QuotaByteRenderer.java @@ -0,0 +1,50 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.admin.quota; + +import java.util.Locale; + +import org.olat.core.gui.components.table.CustomCellRenderer; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.util.Formatter; + +/** + * Render the bytes of the quota in a human readable format. + * + * Initial date: 12.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class QuotaByteRenderer implements CustomCellRenderer { + + @Override + public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) { + if (val instanceof Long) { + Long kBytes = (Long) val; + Long bytes = kBytes * 1000L; + sb.append(Formatter.formatBytes(bytes)) + .append(" (") + .append(kBytes) + .append(")"); + } + } + +} diff --git a/src/main/java/org/olat/admin/quota/QuotaController.java b/src/main/java/org/olat/admin/quota/QuotaController.java index 221eb33a6dd90e7409adc1f460e2cd3b6c36a792..8675d98b93a53d53151b2a56575953bacf5531cc 100644 --- a/src/main/java/org/olat/admin/quota/QuotaController.java +++ b/src/main/java/org/olat/admin/quota/QuotaController.java @@ -30,6 +30,8 @@ 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.panel.Panel; +import org.olat.core.gui.components.table.ColumnDescriptor; +import org.olat.core.gui.components.table.CustomRenderColumnDescriptor; import org.olat.core.gui.components.table.DefaultColumnDescriptor; import org.olat.core.gui.components.table.StaticColumnDescriptor; import org.olat.core.gui.components.table.Table; @@ -83,8 +85,10 @@ public class QuotaController extends BasicController { quotaTableModel = new QuotaTableModel(); tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.path", 0, null, getLocale())); - tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.quota", 1, null, getLocale())); - tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.limit", 2, null, getLocale())); + tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.quota", 1, null, getLocale(), + ColumnDescriptor.ALIGNMENT_LEFT, new QuotaByteRenderer())); + tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.limit", 2, null, getLocale(), + ColumnDescriptor.ALIGNMENT_LEFT, new QuotaByteRenderer())); tableCtr.addColumnDescriptor(new StaticColumnDescriptor("qf.edit", "table.action", translate("edit"))); tableCtr.addColumnDescriptor(new StaticColumnDescriptor("qf.del", "table.action", translate("delete"))); tableCtr.setTableDataModel(quotaTableModel); @@ -95,24 +99,20 @@ public class QuotaController extends BasicController { putInitialPanel(main); } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ + @Override public void event(UserRequest ureq, Component source, Event event) { if(source == addQuotaButton){ // clean up old controller first if (quotaEditCtr != null) removeAsListenerAndDispose(quotaEditCtr); // start edit workflow in dedicated quota edit controller removeAsListenerAndDispose(quotaEditCtr); - quotaEditCtr = new GenericQuotaEditController(ureq, getWindowControl(), null); + quotaEditCtr = new GenericQuotaEditController(ureq, getWindowControl()); listenTo(quotaEditCtr); main.setContent(quotaEditCtr.getInitialComponent()); } } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) - */ + @Override public void event(UserRequest ureq, Controller source, Event event) { if (source == quotaEditCtr) { if (event == Event.CHANGED_EVENT) { @@ -142,17 +142,14 @@ public class QuotaController extends BasicController { tableCtr.setTableDataModel(quotaTableModel); showInfo("qf.deleted", q.getPath()); } else { - // default quotas can not be qf.cannot.del.default")deleted + // default quotas can not be deleted showError("qf.cannot.del.default"); } } } } - /** - * - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ + @Override protected void doDispose() { // } diff --git a/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java b/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java index 2a66746c7d1f23807212a20f63ec4c627df73da1..0a376e6bfc2973a208516c906ff80f7e672b9aaf 100644 --- a/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java +++ b/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java @@ -86,6 +86,7 @@ public class QuotaManagerImpl extends QuotaManager { /** * @see org.olat.core.util.vfs.QuotaManager#createQuota(java.lang.String, java.lang.Long, java.lang.Long) */ + @Override public Quota createQuota(String path, Long quotaKB, Long ulLimitKB) { return new QuotaImpl(path, quotaKB, ulLimitKB); } @@ -94,6 +95,7 @@ public class QuotaManagerImpl extends QuotaManager { * [called by spring] * */ + @Override public void init() { quotaResource = resourceManager.findOrPersistResourceable(OresHelper.lookupType(Quota.class)); initDefaultQuotas(); // initialize default quotas @@ -155,6 +157,7 @@ public class QuotaManagerImpl extends QuotaManager { * @param identifyer * @return */ + @Override public Quota getDefaultQuota(String identifyer) { if (defaultQuotas == null) { throw new OLATRuntimeException(QuotaManagerImpl.class, "Quota manager has not been initialized properly! Must call init() first.", null); @@ -169,6 +172,7 @@ public class QuotaManagerImpl extends QuotaManager { * @param path * @return Quota object. */ + @Override public Quota getCustomQuota(String path) { if (defaultQuotas == null) { throw new OLATRuntimeException(QuotaManagerImpl.class, "Quota manager has not been initialized properly! Must call init() first.", null); @@ -200,6 +204,7 @@ public class QuotaManagerImpl extends QuotaManager { * * @param quota */ + @Override public void setCustomQuotaKB(Quota quota) { if (defaultQuotas == null) { throw new OLATRuntimeException(QuotaManagerImpl.class, "Quota manager has not been initialized properly! Must call init() first.", null); @@ -224,6 +229,7 @@ public class QuotaManagerImpl extends QuotaManager { * @return true if quota successfully deleted or no such quota, false if quota * not deleted because it was a default quota that can not be deleted */ + @Override public boolean deleteCustomQuota(Quota quota) { if (defaultQuotas == null) { throw new OLATRuntimeException(QuotaManagerImpl.class, "Quota manager has not been initialized properly! Must call init() first.", null); @@ -299,6 +305,7 @@ public class QuotaManagerImpl extends QuotaManager { * @param identity * @return */ + @Override public Quota getDefaultQuotaDependingOnRole(Identity identity) { if (BaseSecurityManager.getInstance().isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_AUTHOR)) { return getDefaultQuotaPowerUsers(); } if (BaseSecurityManager.getInstance().isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_ADMIN)) { return getDefaultQuotaPowerUsers(); } @@ -312,6 +319,7 @@ public class QuotaManagerImpl extends QuotaManager { * @param identity * @return custom quota or quota depending on role */ + @Override public Quota getCustomQuotaOrDefaultDependingOnRole(Identity identity, String relPath) { Quota quota = getCustomQuota(relPath); if (quota == null) { // no custom quota @@ -361,6 +369,7 @@ public class QuotaManagerImpl extends QuotaManager { * @param currentContainer2 Upload container (folder) * @return Upload limit on KB */ + @Override public int getUploadLimitKB(long quotaKB2, long uploadLimitKB2, VFSContainer currentContainer2) { if (quotaKB2 == Quota.UNLIMITED) { if (uploadLimitKB2 == Quota.UNLIMITED) { @@ -401,16 +410,13 @@ public class QuotaManagerImpl extends QuotaManager { return true; } - /** - * @see org.olat.core.util.vfs.QuotaManager#getQuotaEditorInstance(org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl, java.lang.String, boolean) - */ @Override - public Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode) { + public Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath) { try { - return new GenericQuotaEditController(ureq, wControl, relPath, modalMode); + return new GenericQuotaEditController(ureq, wControl, relPath); } catch (OLATSecurityException e) { log.warn("Try to access the quota editor without enough privilege", e); - GenericQuotaViewController viewCtrl = new GenericQuotaViewController(ureq, wControl, relPath, modalMode); + GenericQuotaViewController viewCtrl = new GenericQuotaViewController(ureq, wControl, relPath); viewCtrl.setNotEnoughPrivilegeMessage(); return viewCtrl; } @@ -418,8 +424,8 @@ public class QuotaManagerImpl extends QuotaManager { @Override - public Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode) { - return new GenericQuotaViewController(ureq, wControl, relPath, modalMode); + public Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath) { + return new GenericQuotaViewController(ureq, wControl, relPath); } @Override diff --git a/src/main/java/org/olat/admin/quota/_content/edit.html b/src/main/java/org/olat/admin/quota/_content/edit.html index 75138ad7b6bc5e2f0e332ee2f643d496dce9db9c..6a0d2a3638126836b2af68f2f7dd3e7154d2fcb4 100644 --- a/src/main/java/org/olat/admin/quota/_content/edit.html +++ b/src/main/java/org/olat/admin/quota/_content/edit.html @@ -19,10 +19,6 @@ <div class="o_button_group o_button_group_right">$r.render("qf.new")</div> #end <div class="o_info">$r.translate("qf.noquota")</div> - #if ($modalMode) - - $r.render("cancel") - #end </fieldset> #end <div class="panel panel-default"> @@ -32,13 +28,40 @@ <tr><th>$r.translate("qd.title")</th><th>$r.translate("qf.quota")</th><th>$r.translate("qf.limit")</th></tr> </thead> <tbody> - <tr><td>$r.translate("qd.users")</td><td>$users.getQuotaKB()</td><td>$users.getUlLimitKB()</td></tr> - <tr><td>$r.translate("qd.powerusers")</td><td>$powerusers.getQuotaKB()</td><td>$powerusers.getUlLimitKB()</td></tr> - <tr><td>$r.translate("qd.groups")</td><td>$groups.getQuotaKB()</td><td>$groups.getUlLimitKB()</td></tr> - <tr><td>$r.translate("qd.repository")</td><td>$repository.getQuotaKB()</td><td>$repository.getUlLimitKB()</td></tr> - <tr><td>$r.translate("qd.coursefolder")</td><td>$coursefolder.getQuotaKB()</td><td>$coursefolder.getUlLimitKB()</td></tr> - <tr><td>$r.translate("qd.nodefolder")</td><td>$nodefolder.getQuotaKB()</td><td>$nodefolder.getUlLimitKB()</td></tr> - <tr><td>$r.translate("qd.feeds")</td><td>$feeds.getQuotaKB()</td><td>$feeds.getUlLimitKB()</td></tr> + #set ($userQuotaBytes = $users.getQuotaKB() * 1000) + <tr><td>$r.translate("qd.users")</td><td>$r.formatBytes($userQuotaBytes) ($users.getQuotaKB())</td> + #set ($userUlLimitBytes = $users.getUlLimitKB() * 1000) + <td>$r.formatBytes($userUlLimitBytes) ($users.getUlLimitKB())</td></tr> + + #set ($poweruserQuotaBytes = $powerusers.getQuotaKB() * 1000) + <tr><td>$r.translate("qd.powerusers")</td><td>$r.formatBytes($poweruserQuotaBytes) ($powerusers.getQuotaKB())</td> + #set ($poweruserUlLimitBytes = $powerusers.getUlLimitKB() * 1000) + <td>$r.formatBytes($poweruserUlLimitBytes) ($powerusers.getUlLimitKB())</td></tr> + + #set ($groupsQuotaBytes = $groups.getQuotaKB() * 1000) + <tr><td>$r.translate("qd.groups")</td><td>$r.formatBytes($groupsQuotaBytes) ($groups.getQuotaKB())</td> + #set ($groupsUlLimitBytes = $groups.getUlLimitKB() * 1000) + <td>$r.formatBytes($groupsUlLimitBytes) ($groups.getUlLimitKB())</td></tr> + + #set ($repositoryQuotaBytes = $repository.getQuotaKB() * 1000) + <tr><td>$r.translate("qd.repository")</td><td>$r.formatBytes($repositoryQuotaBytes) ($repository.getQuotaKB())</td> + #set ($repositoryUlLimitBytes = $repository.getUlLimitKB() * 1000) + <td>$r.formatBytes($repositoryUlLimitBytes) ($repository.getUlLimitKB())</td></tr> + + #set ($coursefolderQuotaBytes = $coursefolder.getQuotaKB() * 1000) + <tr><td>$r.translate("qd.coursefolder")</td><td>$r.formatBytes($coursefolderQuotaBytes) ($coursefolder.getQuotaKB())</td> + #set ($coursefolderUlLimitBytes = $coursefolder.getUlLimitKB() * 1000) + <td>$r.formatBytes($coursefolderUlLimitBytes) ($coursefolder.getUlLimitKB())</td></tr> + + #set ($nodefolderQuotaBytes = $nodefolder.getQuotaKB() * 1000) + <tr><td>$r.translate("qd.nodefolder")</td><td>$r.formatBytes($nodefolderQuotaBytes) ($nodefolder.getQuotaKB())</td> + #set ($nodefolderUlLimitBytes = $nodefolder.getUlLimitKB() * 1000) + <td>$r.formatBytes($nodefolderUlLimitBytes) ($nodefolder.getUlLimitKB())</td></tr> + + #set ($feedsQuotaBytes = $feeds.getQuotaKB() * 1000) + <tr><td>$r.translate("qd.feeds")</td><td>$r.formatBytes($feedsQuotaBytes) ($feeds.getQuotaKB())</td> + #set ($feedsUlLimitBytes = $feeds.getUlLimitKB() * 1000) + <td>$r.formatBytes($feedsUlLimitBytes) ($feeds.getUlLimitKB())</td></tr> </tbody> </table> </div> \ No newline at end of file diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_cs.properties index 0e217a14c35b08f4a4e4f83f786c7579a5ec13a8..eeaa465e02a7d2bb3eef2ed96f0e7d247ffb7698 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_cs.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_cs.properties @@ -19,6 +19,6 @@ qf.noquota=Tento adres\u00E1\u0159 nem\u00E1 specifikovanou kv\u00F3tu. Jsou u\u qf.path=Cesta qf.quota=Kv\u00F3ta (KB) qf.title=Administrace kv\u00F3t -table.header.limit=Upload limit KB +table.header.limit=Upload limit (KB) table.header.path=Cesta -table.header.quota=Kv\u00F3ta KB +table.header.quota=Kv\u00F3ta (KB) diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_da.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_da.properties index bb5324611346d3a22f7015d357f2fd58f595dac6..17b5e0394b3e48a9b1d202ee8661c92bb475f6cd 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_da.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_da.properties @@ -19,6 +19,6 @@ qf.noquota=Denne mappe har ingen specifik kvota. Den f\u00F8lgende standardkvota qf.path=Stinavn qf.quota=Kvota (KB) qf.title=Kvota administration -table.header.limit=Upload begr\u00E6nsning i KB +table.header.limit=Upload begr\u00E6nsning (KB) table.header.path=Stinavn -table.header.quota=Kvota KB +table.header.quota=Kvota (KB) diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_de.properties index f369dc40ade35f80016837c75a2c07e2a8863382..5fc186b1efe47b5f9e8dfe6ae9c9f4988500fcd8 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_de.properties @@ -22,7 +22,7 @@ qf.noquota=Dieser Ordner hat keine spezifische Quota. Die untenstehenden Default qf.path=Pfad qf.quota=Quota (KB) qf.title=Quotaverwaltung -table.header.limit=Upload Limite KB +table.header.limit=Upload Limite (KB) table.header.path=Pfad -table.header.quota=Quota KB +table.header.quota=Quota (KB) warning.qd.not.enough.privilege=Sie haben nicht die Berechtigungen Quota zu editieren. diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_el.properties index a711a6828715314ad06201f94def18f2c7b04559..061097806219f44f1fce36755ba84cd9d05cfcb8 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_el.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_el.properties @@ -21,6 +21,6 @@ qf.noquota=\u039F \u03C6\u03AC\u03BA\u03B5\u03BB\u03BF\u03C2 \u03B4\u03B5\u03BD qf.path=\u0394\u03B9\u03B1\u03B4\u03C1\u03BF\u03BC\u03AE qf.quota=\u038C\u03C1\u03B9\u03B1 (KB) qf.title=\u0394\u03B9\u03B1\u03C7\u03B5\u03AF\u03C1\u03B9\u03C3\u03B7 \u039F\u03C1\u03AF\u03C9\u03BD -table.header.limit=\u038C\u03C1\u03B9\u03BF Upload [KB] +table.header.limit=\u038C\u03C1\u03B9\u03BF Upload (KB) table.header.path=\u0394\u03B9\u03B1\u03B4\u03C1\u03BF\u03BC\u03AE -table.header.quota=\u038C\u03C1\u03B9\u03BF [KB] +table.header.quota=\u038C\u03C1\u03B9\u03BF (KB) diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_en.properties index a701d4ec531257bd24d4e69e7e9b9a7a1466dde3..0d3e8d670725155f806b96bcf9804fe88f17266d 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_en.properties @@ -22,7 +22,7 @@ qf.noquota=This folder has no specific quota. The following default quotas will qf.path=Path qf.quota=Quota (KB) qf.title=Quota management -table.header.limit=Upload limit KB +table.header.limit=Upload limit (KB) table.header.path=Path -table.header.quota=Quota KB +table.header.quota=Quota (KB) warning.qd.not.enough.privilege=You don't have the privileges to edit quotas. diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_es.properties index 6c5ee528420d0f784c59e25202467dbdfa417d06..9bf50c317171040e5636a3e663388a7bacf41bd3 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_es.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_es.properties @@ -19,6 +19,6 @@ qf.noquota=Esta carpeta no tiene cuota espec\u00EDfica. Se est\u00E1n utilizando qf.path=Ruta qf.quota=Cuota (KB) qf.title=Gesti\u00F3n de cuota -table.header.limit=L\u00EDmite de subida en KB +table.header.limit=L\u00EDmite de subida en (KB) table.header.path=Ruta -table.header.quota=Cuota KB +table.header.quota=Cuota (KB) diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_fa.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_fa.properties index 38617c141c79a8b2a0045aa97d4e5e478f385215..eb6c3e0670b92321242791beb78fd01f2c46fbd4 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_fa.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_fa.properties @@ -19,6 +19,6 @@ qf.noquota=This folder has no specific quota. The following default quotas are u qf.path=Path qf.quota=Quota (KB) qf.title=Quota management -table.header.limit=Upload limit KB +table.header.limit=Upload limit (KB) table.header.path=Path -table.header.quota=Quota KB +table.header.quota=Quota (KB) diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_it.properties index 8208dde9ef9be88742a2f466cb7b87a2f12610b2..843c68f8d2bf82d62d5f28534fecf5e161059c53 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_it.properties @@ -22,7 +22,7 @@ qf.noquota=Questa cartella non ha una quota specifica. Vengono utilizzate le quo qf.path=Percorso qf.quota=Quota (KB) qf.title=Gestione delle quote -table.header.limit=Limite di caricamento KB +table.header.limit=Limite di caricamento (KB) table.header.path=Percorso -table.header.quota=Quota KB +table.header.quota=Quota (KB) warning.qd.not.enough.privilege=Privilegi insufficienti per modificare le quote. diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_jp.properties index da8b913d94ca067a0fb0b2e218b48484d9f07251..fe364a77fae82a6345f30287122dca1351fe190c 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_jp.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_jp.properties @@ -21,6 +21,6 @@ qf.noquota=\u3053\u306E\u30D5\u30A9\u30EB\u30C0\u306B\u306F\u3001\u30AF\u30AA\u3 qf.path=\u30D1\u30B9 qf.quota=\u30AF\u30AA\u30FC\u30BF (KB) qf.title=\u30AF\u30AA\u30FC\u30BF\u7BA1\u7406 -table.header.limit=\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u5236\u9650 KB +table.header.limit=\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u5236\u9650 (KB) table.header.path=\u30D1\u30B9 -table.header.quota=\u30AF\u30AA\u30FC\u30BF KB +table.header.quota=\u30AF\u30AA\u30FC\u30BF (KB) diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_lt.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_lt.properties index 83282cbcce855d7af7766ae87dc27eeb4df492fd..d2d73dffec482b22db97654a8fbfde299a9eb99b 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_lt.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_lt.properties @@ -19,6 +19,6 @@ qf.noquota=Aplankas neturi nustatytos kvotos. Bus naudojamos kvotos pagal nutyl\ qf.path=Kelias qf.quota=Kvota KB qf.title=Kvot\u0173 valdymas -table.header.limit=Nusiuntimo limitas KB +table.header.limit=Nusiuntimo limitas (KB) table.header.path=Kelias -table.header.quota=Kvota KB +table.header.quota=Kvota (KB) diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_nl_NL.properties index 5ce951a339600b6750cd80c40a3f27fca2d1d268..1c95b7445090a8fd8428b39a2c3cb14131575b75 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_nl_NL.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_nl_NL.properties @@ -21,6 +21,6 @@ qf.noquota=Deze map heeft geen specifieke quota. De volgende default quota's zul qf.path=Pad qf.quota=Quota (KB) qf.title=Quota beheer -table.header.limit=Upload limiet KB +table.header.limit=Upload limiet (KB) table.header.path=Pad -table.header.quota=Quota KB +table.header.quota=Quota (KB) diff --git a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_sq.properties index 235a3a1af0a844b8e40f6cf67a0f1c602fc78809..5491fd1283e3acb212e17905ec5d053dc794438f 100644 --- a/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_sq.properties +++ b/src/main/java/org/olat/admin/quota/_i18n/LocalStrings_sq.properties @@ -19,6 +19,6 @@ qf.noquota=Kjo dosje nuk ka ndonj\u00EB kuot\u00EB t\u00EB ve\u00E7ant\u00EB. N\ qf.path=Dosje qf.quota=Kuota (KB) qf.title=Menaxhimi i kuot\u00EBs -table.header.limit=Kufiri i ngarkimi n\u00EB KB +table.header.limit=Kufiri i ngarkimi n\u00EB (KB) table.header.path=Dosje -table.header.quota=Q\=Kuota KB +table.header.quota=Q\=Kuota (KB) diff --git a/src/main/java/org/olat/admin/registration/SystemRegistrationManager.java b/src/main/java/org/olat/admin/registration/SystemRegistrationManager.java index 6c9f9583256fa752b7a1dd65be5d267f27502ee7..93c9c4606e105a6934c0ccdf19607ad891d01649 100644 --- a/src/main/java/org/olat/admin/registration/SystemRegistrationManager.java +++ b/src/main/java/org/olat/admin/registration/SystemRegistrationManager.java @@ -24,7 +24,10 @@ */ package org.olat.admin.registration; -import java.text.ParseException; +import static org.quartz.CronScheduleBuilder.cronSchedule; +import static org.quartz.JobBuilder.newJob; +import static org.quartz.TriggerBuilder.newTrigger; + import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; @@ -63,10 +66,11 @@ import org.olat.group.model.SearchBusinessGroupParams; import org.olat.instantMessaging.InstantMessagingModule; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; -import org.quartz.CronTrigger; import org.quartz.JobDetail; +import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; +import org.quartz.Trigger; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -171,7 +175,7 @@ public class SystemRegistrationManager implements InitializingBean { public void send() { try { - scheduler.triggerJob(SCHEDULER_NAME, Scheduler.DEFAULT_GROUP); + scheduler.triggerJob(new JobKey(SCHEDULER_NAME, Scheduler.DEFAULT_GROUP)); } catch (SchedulerException e) { log.error("", e); } @@ -250,7 +254,7 @@ public class SystemRegistrationManager implements InitializingBean { // System config msgProperties.put("instantMessagingEnabled", String.valueOf(CoreSpringFactory.getImpl(InstantMessagingModule.class).isEnabled())); - msgProperties.put("enabledLanguages", I18nModule.getEnabledLanguageKeys().toString()); + msgProperties.put("enabledLanguages", CoreSpringFactory.getImpl(I18nModule.class).getEnabledLanguageKeys().toString()); msgProperties.put("clusterEnabled", clusterMode); msgProperties.put("debuggingEnabled", String.valueOf(Settings.isDebuging())); @@ -318,19 +322,16 @@ public class SystemRegistrationManager implements InitializingBean { String cronExpression = createCronTriggerExpression(); try { - // Create job with cron trigger configuration - JobDetail jobDetail = new JobDetail(SCHEDULER_NAME, Scheduler.DEFAULT_GROUP, SystemRegistrationJob.class); - CronTrigger trigger = new CronTrigger(); - trigger.setName(TRIGGER); - // Use this cron expression for debugging, tries to send data every minute - //trigger.setCronExpression("0 * * * * ?"); - trigger.setCronExpression(cronExpression); - // Schedule job now + JobDetail jobDetail = newJob(SystemRegistrationJob.class) + .withIdentity(SCHEDULER_NAME, Scheduler.DEFAULT_GROUP) + .build(); + Trigger trigger = newTrigger() + .withIdentity(TRIGGER) + .withSchedule(cronSchedule(cronExpression)) + .build(); scheduler.scheduleJob(jobDetail, trigger); - } catch (ParseException e) { + } catch (Exception e) { log.error("Illegal cron expression for system registration", e); - } catch (SchedulerException e) { - log.error("Can not start system registration scheduler", e); } log.info("Registration background job successfully started: "+cronExpression, null); } diff --git a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_de.properties index 03b1d089604aff8d5191a8ccf68e63d041326627..23db5bb427956a432722de3ba8d86239c352c836 100644 --- a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_de.properties @@ -29,7 +29,7 @@ managed.flags.course.chat=Einstellung f\u00fcr Chat managed.flags.course.layout=Einstellung f\u00fcr Layout managed.flags.course.lecture=Lektionen managed.flags.course.lecturemanagement=Lektionen verwalten -managed.flags.course.lectureconfig=Lektionen un Absenzen in Kurs konfigurieren +managed.flags.course.lectureconfig=Lektionen und Absenzen in Kurs konfigurieren managed.flags.course.resourcefolder=Einstellung f\u00fcr Ressourcenordner managed.flags.course.efficencystatement=Einstellung f\u00fcr Leistungsnachweis managed.flags.course.calendar=Einstellung f\u00fcr Kalender diff --git a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_fr.properties index c0943336772601ccf32ee95c27301f5205f1a5cb..daed7eea8d461ff24636c42b76424053e1fc8fd2 100644 --- a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Sun Nov 08 13:03:44 CET 2015 +#Sun Aug 27 16:10:13 CEST 2017 managed.cal=Calendriers g\u00E9r\u00E9s managed.flags.course.access=Configuration d'acc\u00E8s managed.flags.course.all=Compl\u00E8tement g\u00E9r\u00E9 de l'ext\u00E9rieur @@ -15,6 +15,9 @@ managed.flags.course.efficencystatement=Configuration des feuilles de notes managed.flags.course.glossary=Configuration du glossaire managed.flags.course.groups=Gestion des groupes managed.flags.course.layout=Configuration du layout +managed.flags.course.lecture=Cours blocs +managed.flags.course.lectureconfig=Configurer les cours blocs et les absences dans les cours +managed.flags.course.lecturemanagement=Administrer les cours blocs managed.flags.course.membersmanagement=Gestion des membres managed.flags.course.resourcefolder=Configuration du dossier de stockage managed.flags.course.settings=Configurations diff --git a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_pt_BR.properties index 5b35f6de1c5cd8751fbba671d259df7d021445e7..aec8baa51d3d3b736e7997690b20fd490d5c7a53 100644 --- a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Fri Apr 29 00:05:00 CEST 2016 +#Tue Sep 05 23:33:55 CEST 2017 managed.cal=Calend\u00E1rios administrados managed.flags.course.access=Acessar configura\u00E7\u00E3o managed.flags.course.all=Gerenciado externamente por completo @@ -15,6 +15,9 @@ managed.flags.course.efficencystatement=Configura\u00E7\u00F5es do comprovante d managed.flags.course.glossary=Configura\u00E7\u00F5es do gloss\u00E1rio managed.flags.course.groups=Gest\u00E3o de grupo managed.flags.course.layout=Configura\u00E7\u00E3o de layout +managed.flags.course.lecture=Aulas +managed.flags.course.lectureconfig=Configura\u00E7\u00E3o de aulas e aus\u00EAncias no curso +managed.flags.course.lecturemanagement=Gest\u00E3o de aulas managed.flags.course.membersmanagement=Gest\u00E3o de membros managed.flags.course.resourcefolder=Configura\u00E7\u00E3o de pasta de recursos managed.flags.course.settings=Configura\u00E7\u00F5es diff --git a/src/main/java/org/olat/admin/statistics/StatisticsAdminController.java b/src/main/java/org/olat/admin/statistics/StatisticsAdminController.java index f6635f31062bc4356c1837325d620001884b0ad8..6bdd1266246e5b13f20f9d882a8126eb27fec62b 100644 --- a/src/main/java/org/olat/admin/statistics/StatisticsAdminController.java +++ b/src/main/java/org/olat/admin/statistics/StatisticsAdminController.java @@ -41,11 +41,12 @@ import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.course.statistic.StatisticUpdateManager; -import org.quartz.JobDetail; +import org.quartz.CronTrigger; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; -import org.springframework.scheduling.quartz.CronTriggerBean; +import org.quartz.TriggerKey; +import org.springframework.beans.factory.annotation.Autowired; /** * Admin Controller for statistics - similar to the notifications controller. @@ -70,6 +71,9 @@ public class StatisticsAdminController extends BasicController { private DialogBoxController dialogCtr_; + @Autowired + private Scheduler scheduler; + public StatisticsAdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); content = createVelocityContainer("index"); @@ -82,38 +86,42 @@ public class StatisticsAdminController extends BasicController { } private void refreshUIState() { + + log_.info("refreshUIState: schedulerFactoryBean found"); + boolean enabled = false; String cronExpression = ""; - if (CoreSpringFactory.containsBean("schedulerFactoryBean")) { - log_.info("refreshUIState: schedulerFactoryBean found"); - Object schedulerFactoryBean = CoreSpringFactory.getBean("schedulerFactoryBean"); - if (schedulerFactoryBean!=null && schedulerFactoryBean instanceof Scheduler) { - Scheduler schedulerBean = (Scheduler) schedulerFactoryBean; - int triggerState; - try { - triggerState = schedulerBean.getTriggerState("updateStatisticsTrigger", null/*trigger group*/); - enabled = (triggerState!=Trigger.STATE_NONE) && (triggerState!=Trigger.STATE_ERROR); - log_.info("refreshUIState: updateStatisticsTrigger state was "+triggerState+", enabled now: "+enabled); - } catch (SchedulerException e) { - log_.warn("refreshUIState: Got a SchedulerException while asking for the updateStatisticsTrigger's state", e); - } - } - CronTriggerBean triggerBean = (CronTriggerBean) CoreSpringFactory.getBean("updateStatisticsTrigger"); - JobDetail jobDetail = triggerBean.getJobDetail(); - enabled &= jobDetail.getName().equals("org.olat.statistics.job.enabled"); - log_.info("refreshUIState: org.olat.statistics.job.enabled check, enabled now: "+enabled); - cronExpression = triggerBean.getCronExpression(); - StatisticUpdateManager statisticUpdateManager = getStatisticUpdateManager(); - if (statisticUpdateManager==null) { - log_.info("refreshUIState: statisticUpdateManager not configured"); - enabled = false; + Trigger.TriggerState triggerState; + try { + TriggerKey triggerKey = new TriggerKey("updateStatisticsTrigger", null/*trigger group*/); + triggerState = scheduler.getTriggerState(triggerKey); + enabled = triggerState != Trigger.TriggerState.NONE && triggerState!=Trigger.TriggerState.ERROR; + + Trigger trigger = scheduler.getTrigger(triggerKey); + if(trigger == null) { + enabled &= false; } else { - enabled &= statisticUpdateManager.isEnabled(); - log_.info("refreshUIState: statisticUpdateManager configured, enabled now: "+enabled); + enabled &= trigger.getJobKey().getName().equals("org.olat.statistics.job.enabled"); + if(trigger instanceof CronTrigger) { + log_.info("refreshUIState: org.olat.statistics.job.enabled check, enabled now: "+enabled); + cronExpression = ((CronTrigger)trigger).getCronExpression(); + } } + + log_.info("refreshUIState: updateStatisticsTrigger state was "+triggerState+", enabled now: "+enabled); + } catch (SchedulerException e) { + log_.warn("refreshUIState: Got a SchedulerException while asking for the updateStatisticsTrigger's state", e); + } + + StatisticUpdateManager statisticUpdateManager = getStatisticUpdateManager(); + if (statisticUpdateManager==null) { + log_.info("refreshUIState: statisticUpdateManager not configured"); + enabled = false; } else { - log_.info("refreshUIState: schedulerFactoryBean not found"); + enabled &= statisticUpdateManager.isEnabled(); + log_.info("refreshUIState: statisticUpdateManager configured, enabled now: "+enabled); } + if (enabled) { content.contextPut("status", getTranslator().translate("statistics.status.enabled", new String[]{ cronExpression })); } else { @@ -150,6 +158,7 @@ public class StatisticsAdminController extends BasicController { } } + @Override public void event(UserRequest ureq, Controller source, Event event) { if (source == dialogCtr_) { if (DialogBoxUIFactory.isYesEvent(event)) { @@ -165,12 +174,6 @@ public class StatisticsAdminController extends BasicController { } } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.components.Component, - * org.olat.core.gui.control.Event) - */ @Override public void event(UserRequest ureq, Component source, Event event) { if (STATISTICS_FULL_RECALCULATION_TRIGGER_BUTTON.equals(event.getCommand())) { diff --git a/src/main/java/org/olat/admin/sysinfo/_content/infomsgEdit.html b/src/main/java/org/olat/admin/sysinfo/_content/infomsgEdit.html index 3045d2f03a0f693467ae8fecf1a2db19e38797b9..8073a1fa63acd8f1b1e14feabab9b9fb2f99208d 100644 --- a/src/main/java/org/olat/admin/sysinfo/_content/infomsgEdit.html +++ b/src/main/java/org/olat/admin/sysinfo/_content/infomsgEdit.html @@ -16,6 +16,6 @@ #end <h4>$r.translate("staticFolder")</h4> -<div class="o_copy_code o_nowrap">$extlink</div> +<div class="o_copy_code o_nowrap"><input type="text" value="$extlink" onclick="this.select()"/></div> $r.render("staticFolder") </fieldset> \ No newline at end of file diff --git a/src/main/java/org/olat/admin/sysinfo/_content/sessionDetails.html b/src/main/java/org/olat/admin/sysinfo/_content/sessionDetails.html index df5315b9e42cba037d02ff642ebf44fe27590542..e0043ea0769c7890260cfa07756b0dfb3b46fdfa 100644 --- a/src/main/java/org/olat/admin/sysinfo/_content/sessionDetails.html +++ b/src/main/java/org/olat/admin/sysinfo/_content/sessionDetails.html @@ -44,7 +44,7 @@ <tr><td><i>$r.translate("sess.noattributes")</i></td></tr> #else #foreach($key in $env.getAttributes().keySet()) - <tr><td>$key:</td><td>$env.getAttributes().get($key)</td></tr> + <tr><td>$key:</td><td>$!env.getAttributes().get($key)</td></tr> #end #end </table> diff --git a/src/main/java/org/olat/admin/user/SendTokenToUserForm.java b/src/main/java/org/olat/admin/user/SendTokenToUserForm.java index 89081c6588ea3f4df5bac47f908dfd743f9607d5..3510ddf2708cbdcc854a66d02321033ddf857b8f 100644 --- a/src/main/java/org/olat/admin/user/SendTokenToUserForm.java +++ b/src/main/java/org/olat/admin/user/SendTokenToUserForm.java @@ -42,6 +42,7 @@ import org.olat.core.id.UserConstants; import org.olat.core.util.Encoder; import org.olat.core.util.Util; import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.i18n.I18nModule; import org.olat.core.util.mail.MailBundle; import org.olat.core.util.mail.MailManager; import org.olat.core.util.mail.MailerResult; @@ -64,6 +65,11 @@ public class SendTokenToUserForm extends FormBasicController { private TextElement mailText; private String dummyKey; + + @Autowired + private I18nModule i18nModule; + @Autowired + private I18nManager i18nManager; @Autowired private MailManager mailManager; @Autowired @@ -122,7 +128,7 @@ public class SendTokenToUserForm extends FormBasicController { Translator userTrans = Util.createPackageTranslator(RegistrationManager.class, locale) ; String body = userTrans.translate("pwchange.intro", new String[] { user.getName() }) + userTrans.translate("pwchange.body", new String[] { - serverpath, dummyKey, I18nManager.getInstance().getLocaleKey(locale) + serverpath, dummyKey, i18nModule.getLocaleKey(locale) }); return body; } @@ -147,7 +153,7 @@ public class SendTokenToUserForm extends FormBasicController { } Preferences prefs = user.getUser().getPreferences(); - Locale locale = I18nManager.getInstance().getLocaleOrDefault(prefs.getLanguage()); + Locale locale = i18nManager.getLocaleOrDefault(prefs.getLanguage()); String emailAdress = user.getUser().getProperty(UserConstants.EMAIL, locale); TemporaryKey tk = registrationManager.loadTemporaryKeyByEmail(emailAdress); diff --git a/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java b/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java index 1d8196fce68a9a5cea9693d83a8c9dc548334568..3a8bfd01eeb2725327e2280b9da3483e860b9cbf 100644 --- a/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java +++ b/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java @@ -27,7 +27,6 @@ package org.olat.admin.user; import org.olat.admin.user.bulkChange.UserBulkChangeManager; import org.olat.basesecurity.BaseSecurity; -import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.BaseSecurityModule; import org.olat.basesecurity.Constants; import org.olat.basesecurity.SecurityGroup; @@ -39,6 +38,8 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.id.Identity; +import org.olat.core.util.UserSession; +import org.springframework.beans.factory.annotation.Autowired; /** * Initial Date: Jan 27, 2006 @@ -64,6 +65,11 @@ public class SystemRolesAndRightsController extends BasicController { private SystemRolesAndRightsForm sysRightsForm; private Identity identity; + @Autowired + private BaseSecurity securityManager; + @Autowired + private UserBulkChangeManager userBulkChangeManager; + /** * Constructor for a controller that lets you edit the users system roles and rights. * @param wControl @@ -117,69 +123,70 @@ public class SystemRolesAndRightsController extends BasicController { * @param form */ private void saveFormData(UserRequest ureq, Identity myIdentity, SystemRolesAndRightsForm form) { - boolean iAmOlatAdmin = ureq.getUserSession().getRoles().isOLATAdmin(); - boolean iAmUserManager = ureq.getUserSession().getRoles().isUserManager(); - BaseSecurity secMgr = BaseSecurityManager.getInstance(); + UserSession usess = ureq.getUserSession(); + boolean iAmOlatAdmin = usess.getRoles().isOLATAdmin(); + boolean iAmUserManager = usess.getRoles().isUserManager(); + // 1) general user type - anonymous or user // anonymous users boolean isAnonymous = false; Boolean canGuestsByConfig = BaseSecurityModule.USERMANAGER_CAN_MANAGE_GUESTS; if (canGuestsByConfig.booleanValue() || iAmOlatAdmin) { - SecurityGroup anonymousGroup = secMgr.findSecurityGroupByName(Constants.GROUP_ANONYMOUS); - boolean hasBeenAnonymous = secMgr.isIdentityInSecurityGroup(myIdentity, anonymousGroup); + SecurityGroup anonymousGroup = securityManager.findSecurityGroupByName(Constants.GROUP_ANONYMOUS); + boolean hasBeenAnonymous = securityManager.isIdentityInSecurityGroup(myIdentity, anonymousGroup); isAnonymous = form.isAnonymous(); - updateSecurityGroup(myIdentity, secMgr, anonymousGroup, hasBeenAnonymous, isAnonymous, Constants.GROUP_ANONYMOUS); + updateSecurityGroup(myIdentity, securityManager, anonymousGroup, hasBeenAnonymous, isAnonymous, Constants.GROUP_ANONYMOUS); // system users - oposite of anonymous users - SecurityGroup usersGroup = secMgr.findSecurityGroupByName(Constants.GROUP_OLATUSERS); - boolean hasBeenUser = secMgr.isIdentityInSecurityGroup(myIdentity, usersGroup); + SecurityGroup usersGroup = securityManager.findSecurityGroupByName(Constants.GROUP_OLATUSERS); + boolean hasBeenUser = securityManager.isIdentityInSecurityGroup(myIdentity, usersGroup); boolean isUser = !form.isAnonymous(); - updateSecurityGroup(myIdentity, secMgr, usersGroup, hasBeenUser, isUser,Constants.GROUP_OLATUSERS); + updateSecurityGroup(myIdentity, securityManager, usersGroup, hasBeenUser, isUser,Constants.GROUP_OLATUSERS); } // 2) system roles // group manager Boolean canGroupmanagerByConfig =BaseSecurityModule.USERMANAGER_CAN_MANAGE_GROUPMANAGERS; if (canGroupmanagerByConfig.booleanValue() || iAmOlatAdmin) { - SecurityGroup groupManagerGroup = secMgr.findSecurityGroupByName(Constants.GROUP_GROUPMANAGERS); - boolean hasBeenGroupManager = secMgr.isIdentityInSecurityGroup(myIdentity, groupManagerGroup); + SecurityGroup groupManagerGroup = securityManager.findSecurityGroupByName(Constants.GROUP_GROUPMANAGERS); + boolean hasBeenGroupManager = securityManager.isIdentityInSecurityGroup(myIdentity, groupManagerGroup); boolean isGroupManager = form.isGroupmanager(); - updateSecurityGroup(myIdentity, secMgr, groupManagerGroup, hasBeenGroupManager, isGroupManager, Constants.GROUP_GROUPMANAGERS); + updateSecurityGroup(myIdentity, securityManager, groupManagerGroup, hasBeenGroupManager, isGroupManager, Constants.GROUP_GROUPMANAGERS); } // pool manager Boolean canPoolmanagerByConfig =BaseSecurityModule.USERMANAGER_CAN_MANAGE_POOLMANAGERS; if (canPoolmanagerByConfig.booleanValue() || iAmOlatAdmin) { - SecurityGroup poolManagerGroup = secMgr.findSecurityGroupByName(Constants.GROUP_POOL_MANAGER); - boolean hasBeenPoolManager = secMgr.isIdentityInSecurityGroup(myIdentity, poolManagerGroup); + SecurityGroup poolManagerGroup = securityManager.findSecurityGroupByName(Constants.GROUP_POOL_MANAGER); + boolean hasBeenPoolManager = securityManager.isIdentityInSecurityGroup(myIdentity, poolManagerGroup); boolean isPoolManager = form.isPoolmanager(); - updateSecurityGroup(myIdentity, secMgr, poolManagerGroup, hasBeenPoolManager, isPoolManager, Constants.GROUP_AUTHORS); + updateSecurityGroup(myIdentity, securityManager, poolManagerGroup, hasBeenPoolManager, isPoolManager, Constants.GROUP_AUTHORS); } // author Boolean canAuthorByConfig = BaseSecurityModule.USERMANAGER_CAN_MANAGE_AUTHORS; if (canAuthorByConfig.booleanValue() || iAmOlatAdmin) { - SecurityGroup authorGroup = secMgr.findSecurityGroupByName(Constants.GROUP_AUTHORS); - boolean hasBeenAuthor = secMgr.isIdentityInSecurityGroup(myIdentity, authorGroup); + SecurityGroup authorGroup = securityManager.findSecurityGroupByName(Constants.GROUP_AUTHORS); + boolean hasBeenAuthor = securityManager.isIdentityInSecurityGroup(myIdentity, authorGroup); boolean isAuthor = form.isAuthor() || form.isInstitutionalResourceManager(); - updateSecurityGroup(myIdentity, secMgr, authorGroup, hasBeenAuthor, isAuthor, Constants.GROUP_AUTHORS); + updateSecurityGroup(myIdentity, securityManager, authorGroup, hasBeenAuthor, isAuthor, Constants.GROUP_AUTHORS); } // user manager, only allowed by admin if (iAmOlatAdmin) { - SecurityGroup userManagerGroup = secMgr.findSecurityGroupByName(Constants.GROUP_USERMANAGERS); - boolean hasBeenUserManager = secMgr.isIdentityInSecurityGroup(myIdentity, userManagerGroup); + SecurityGroup userManagerGroup = securityManager.findSecurityGroupByName(Constants.GROUP_USERMANAGERS); + boolean hasBeenUserManager = securityManager.isIdentityInSecurityGroup(myIdentity, userManagerGroup); boolean isUserManager = form.isUsermanager(); - updateSecurityGroup(myIdentity, secMgr, userManagerGroup, hasBeenUserManager, isUserManager, Constants.GROUP_USERMANAGERS); + updateSecurityGroup(myIdentity, securityManager, userManagerGroup, hasBeenUserManager, isUserManager, Constants.GROUP_USERMANAGERS); } // institutional resource manager, only allowed by admin if (iAmUserManager || iAmOlatAdmin) { - SecurityGroup institutionalResourceManagerGroup = secMgr.findSecurityGroupByName(Constants.GROUP_INST_ORES_MANAGER); - boolean hasBeenInstitutionalResourceManager = secMgr.isIdentityInSecurityGroup(myIdentity, institutionalResourceManagerGroup); + SecurityGroup institutionalResourceManagerGroup = securityManager.findSecurityGroupByName(Constants.GROUP_INST_ORES_MANAGER); + boolean hasBeenInstitutionalResourceManager = securityManager.isIdentityInSecurityGroup(myIdentity, institutionalResourceManagerGroup); boolean isInstitutionalResourceManager = form.isInstitutionalResourceManager(); - updateSecurityGroup(myIdentity, secMgr, institutionalResourceManagerGroup, hasBeenInstitutionalResourceManager, isInstitutionalResourceManager, Constants.GROUP_INST_ORES_MANAGER); + updateSecurityGroup(myIdentity, securityManager, institutionalResourceManagerGroup, hasBeenInstitutionalResourceManager, isInstitutionalResourceManager, Constants.GROUP_INST_ORES_MANAGER); } // system administrator, only allowed by admin if (iAmOlatAdmin) { - SecurityGroup adminGroup = secMgr.findSecurityGroupByName(Constants.GROUP_ADMIN); - boolean hasBeenAdmin = secMgr.isIdentityInSecurityGroup(myIdentity, adminGroup); + SecurityGroup adminGroup = securityManager.findSecurityGroupByName(Constants.GROUP_ADMIN); + boolean hasBeenAdmin = securityManager.isIdentityInSecurityGroup(myIdentity, adminGroup); boolean isAdmin = form.isAdmin(); - updateSecurityGroup(myIdentity, secMgr, adminGroup, hasBeenAdmin, isAdmin, Constants.GROUP_ADMIN); + updateSecurityGroup(myIdentity, securityManager, adminGroup, hasBeenAdmin, isAdmin, Constants.GROUP_ADMIN); } Boolean canManageStatus =BaseSecurityModule.USERMANAGER_CAN_MANAGE_STATUS; if ((iAmOlatAdmin || canManageStatus.booleanValue()) && !myIdentity.getStatus().equals(form.getStatus()) ) { @@ -197,10 +204,10 @@ public class SystemRolesAndRightsController extends BasicController { : "unknown")))); if(oldStatus != newStatus && newStatus == Identity.STATUS_LOGIN_DENIED && form.getSendLoginDeniedEmail()) { - UserBulkChangeManager.getInstance().sendLoginDeniedEmail(myIdentity); + userBulkChangeManager.sendLoginDeniedEmail(myIdentity); } - identity = secMgr.saveIdentityStatus(myIdentity, newStatus); + identity = securityManager.saveIdentityStatus(myIdentity, newStatus); logAudit("User::" + getIdentity().getName() + " changed accout status for user::" + myIdentity.getName() + " from::" + oldStatusText + " to::" + newStatusText, null); } } @@ -228,6 +235,7 @@ public class SystemRolesAndRightsController extends BasicController { /** * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) */ + @Override protected void doDispose() { // nothing to do } diff --git a/src/main/java/org/olat/admin/user/UserAdminController.java b/src/main/java/org/olat/admin/user/UserAdminController.java index be4c41ca2e7a74775f97957945a716bc333a7c05..94fc6d70e2f9e953bcfb5092d5093e8ed247dc8e 100644 --- a/src/main/java/org/olat/admin/user/UserAdminController.java +++ b/src/main/java/org/olat/admin/user/UserAdminController.java @@ -64,6 +64,7 @@ import org.olat.ldap.LDAPLoginModule; import org.olat.modules.lecture.LectureModule; import org.olat.modules.lecture.ui.ParticipantLecturesOverviewController; import org.olat.properties.Property; +import org.olat.resource.accesscontrol.ui.UserOrderController; import org.olat.user.ChangePrefsController; import org.olat.user.DisplayPortraitController; import org.olat.user.ProfileAndHomePageEditController; @@ -76,11 +77,11 @@ import org.springframework.beans.factory.annotation.Autowired; * @author Sabina Jeger * <pre> * Complete rebuild on 17. jan 2006 by Florian Gnaegi - * - * Functionality to change or view all kind of things for this user - * based on the configuration for the user manager. + * + * Functionality to change or view all kind of things for this user + * based on the configuration for the user manager. * This controller should only be used by the UserAdminMainController. - * + * * </pre> */ public class UserAdminController extends BasicController implements Activateable2 { @@ -97,12 +98,13 @@ public class UserAdminController extends BasicController implements Activateable private static final String NLS_EDIT_UQUOTA = "edit.uquota"; private static final String NLS_VIEW_GROUPS = "view.groups"; private static final String NLS_VIEW_COURSES = "view.courses"; + private static final String NLS_VIEW_ACCESS = "view.access"; private static final String NLS_VIEW_EFF_STATEMENTS = "view.effStatements"; private static final String NLS_VIEW_SUBSCRIPTIONS = "view.subscriptions"; private static final String NLS_VIEW_LECTURES = "view.lectures"; - + private VelocityContainer myContent; - + private Identity myIdentity = null; // controllers used in tabbed pane @@ -118,7 +120,7 @@ public class UserAdminController extends BasicController implements Activateable private CertificateAndEfficiencyStatementListController efficicencyCtrl; private final boolean isOlatAdmin; - + @Autowired private BaseSecurity securityManager; @Autowired @@ -139,36 +141,36 @@ public class UserAdminController extends BasicController implements Activateable isOlatAdmin = ureq.getUserSession().getRoles().isOLATAdmin(); if (!securityManager.isIdentityPermittedOnResourceable( - ureq.getIdentity(), - Constants.PERMISSION_ACCESS, + ureq.getIdentity(), + Constants.PERMISSION_ACCESS, OresHelper.lookupType(this.getClass()))) { throw new OLATSecurityException("Insufficient permissions to access UserAdminController"); } - + myIdentity = identity; - - if (allowedToManageUser(ureq, myIdentity)) { + + if (allowedToManageUser(ureq, myIdentity)) { myContent = createVelocityContainer("udispatcher"); backLink = LinkFactory.createLinkBack(myContent, this); userShortDescrCtr = new UserShortDescription(ureq, wControl, identity); listenTo(userShortDescrCtr); myContent.put("userShortDescription", userShortDescrCtr.getInitialComponent()); - + setBackButtonEnabled(true); // default initTabbedPane(myIdentity, ureq); - exposeUserDataToVC(ureq, myIdentity); + exposeUserDataToVC(ureq, myIdentity); putInitialPanel(myContent); } else { - String supportAddr = WebappHelper.getMailConfig("mailSupport"); - showWarning(NLS_ERROR_NOACCESS_TO_USER, supportAddr); + String supportAddr = WebappHelper.getMailConfig("mailSupport"); + showWarning(NLS_ERROR_NOACCESS_TO_USER, supportAddr); putInitialPanel(new Panel("empty")); } } - + @Override public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { if(entries == null || entries.isEmpty()) return; - + String entryPoint = entries.get(0).getOLATResourceable().getResourceableTypeName(); if("tab".equals(entryPoint)) { userTabP.activate(ureq, entries, state); @@ -188,7 +190,7 @@ public class UserAdminController extends BasicController implements Activateable myContent.contextPut("showButton", Boolean.valueOf(backButtonEnabled)); } } - + /** * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) */ @@ -209,8 +211,8 @@ public class UserAdminController extends BasicController implements Activateable if (source == propertiesCtr) { if (event.getCommand().equals("PropFound")){ PropFoundEvent foundEvent = (PropFoundEvent) event; - Property myfoundProperty = foundEvent.getProperty(); - showInfo(NLS_FOUND_PROPERTY, myfoundProperty.getKey().toString()); + Property myfoundProperty = foundEvent.getProperty(); + showInfo(NLS_FOUND_PROPERTY, myfoundProperty.getKey().toString()); } } else if (source == pwdCtr) { if (event == Event.DONE_EVENT) { @@ -279,7 +281,7 @@ public class UserAdminController extends BasicController implements Activateable // passed all tests, current user is allowed to edit given identity return true; } - + /** * Initialize the tabbed pane according to the users rights and the system * configuration @@ -290,7 +292,7 @@ public class UserAdminController extends BasicController implements Activateable // first Initialize the user details tabbed pane userTabP = new TabbedPane("userTabP", ureq.getLocale()); userTabP.addListener(this); - + /** * Determine, whether the user admin is or is not able to edit all fields in user * profile form. The system admin is always able to do so. @@ -303,7 +305,7 @@ public class UserAdminController extends BasicController implements Activateable userProfileCtr = new ProfileAndHomePageEditController(ureq, getWindowControl(), identity, canEditAllFields.booleanValue()); listenTo(userProfileCtr); userTabP.addTab(translate(NLS_EDIT_UPROFILE), userProfileCtr.getInitialComponent()); - + userTabP.addTab(translate(NLS_EDIT_UPREFS), new TabCreator() { @Override public Component create(UserRequest uureq) { @@ -317,13 +319,13 @@ public class UserAdminController extends BasicController implements Activateable userTabP.addTab(translate(NLS_EDIT_UPWD), new TabCreator() { @Override public Component create(UserRequest uureq) { - pwdCtr = new UserChangePasswordController(uureq, getWindowControl(), identity); - listenTo(pwdCtr); + pwdCtr = new UserChangePasswordController(uureq, getWindowControl(), identity); + listenTo(pwdCtr); return pwdCtr.getInitialComponent(); } }); } - + Boolean canAuth = BaseSecurityModule.USERMANAGER_ACCESS_TO_AUTH; if (canAuth.booleanValue() || isOlatAdmin) { userTabP.addTab(translate(NLS_EDIT_UAUTH), new TabCreator() { @@ -335,19 +337,19 @@ public class UserAdminController extends BasicController implements Activateable } }); } - + Boolean canProp = BaseSecurityModule.USERMANAGER_ACCESS_TO_PROP; if (canProp.booleanValue() || isOlatAdmin) { userTabP.addTab(translate(NLS_EDIT_UPROP), new TabCreator() { @Override public Component create(UserRequest uureq) { - propertiesCtr = new UserPropertiesController(uureq, getWindowControl(), identity); + propertiesCtr = new UserPropertiesController(uureq, getWindowControl(), identity); listenTo(propertiesCtr); return propertiesCtr.getInitialComponent(); } }); } - + Boolean canStartGroups = BaseSecurityModule.USERMANAGER_CAN_START_GROUPS; userTabP.addTab(translate(NLS_VIEW_GROUPS), new TabCreator() { @Override @@ -366,8 +368,19 @@ public class UserAdminController extends BasicController implements Activateable return courseCtr.getInitialComponent(); } }); - - if (isOlatAdmin) { + + if (isOlatAdmin) { + userTabP.addTab(translate(NLS_VIEW_ACCESS), new TabCreator() { + @Override + public Component create(UserRequest uureq) { + Controller accessCtr = new UserOrderController(ureq, getWindowControl(), identity); + listenTo(accessCtr); + return accessCtr.getInitialComponent(); + } + }); + } + + if (isOlatAdmin) { userTabP.addTab(translate(NLS_VIEW_EFF_STATEMENTS), new TabCreator() { @Override public Component create(UserRequest uureq) { @@ -391,10 +404,10 @@ public class UserAdminController extends BasicController implements Activateable listenTo(subscriptionsCtr); return subscriptionsCtr.getInitialComponent(); } - - }); + + }); } - + userTabP.addTab(translate(NLS_EDIT_UROLES), new TabCreator() { @Override public Component create(UserRequest uureq) { @@ -403,24 +416,24 @@ public class UserAdminController extends BasicController implements Activateable return rolesCtr.getInitialComponent(); } }); - + Boolean canQuota = BaseSecurityModule.USERMANAGER_ACCESS_TO_QUOTA; if (canQuota.booleanValue() || isOlatAdmin) { userTabP.addTab(translate(NLS_EDIT_UQUOTA), new TabCreator() { @Override public Component create(UserRequest uureq) { String relPath = FolderConfig.getUserHomes() + "/" + identity.getName(); - quotaCtr = QuotaManager.getInstance().getQuotaEditorInstance(uureq, getWindowControl(), relPath, false); + quotaCtr = QuotaManager.getInstance().getQuotaEditorInstance(uureq, getWindowControl(), relPath); return quotaCtr.getInitialComponent(); } }); } - + if(lectureModule.isEnabled()) { userTabP.addTab(translate(NLS_VIEW_LECTURES), new TabCreator() { @Override public Component create(UserRequest uureq) { - lecturesCtrl = new ParticipantLecturesOverviewController(uureq, getWindowControl(), identity, true, true, true); + lecturesCtrl = new ParticipantLecturesOverviewController(uureq, getWindowControl(), identity, true, true, true, true); listenTo(lecturesCtrl); BreadcrumbedStackedPanel stackPanel = new BreadcrumbedStackedPanel("lectures", getTranslator(), lecturesCtrl); stackPanel.pushController(translate(NLS_VIEW_LECTURES), lecturesCtrl); @@ -430,11 +443,11 @@ public class UserAdminController extends BasicController implements Activateable } }); } - + // now push to velocity myContent.put("userTabP", userTabP); } - + private boolean isPasswordChangesAllowed(Identity identity) { Boolean canChangePwd = BaseSecurityModule.USERMANAGER_CAN_MODIFY_PWD; if (canChangePwd.booleanValue() || isOlatAdmin) { @@ -444,14 +457,14 @@ public class UserAdminController extends BasicController implements Activateable // it's an ldap-user return ldapLoginModule.isPropagatePasswordChangedOnLdapServer(); } - + Boolean canCreatePwd = BaseSecurityModule.USERMANAGER_CAN_CREATE_PWD; Authentication olatAuth = securityManager.findAuthentication(identity, BaseSecurityModule.getDefaultAuthProviderIdentifier()); if (olatAuth != null || canCreatePwd.booleanValue() || isOlatAdmin) { return true; } } - + return false; } @@ -460,7 +473,7 @@ public class UserAdminController extends BasicController implements Activateable * @param ureq * @param identity */ - private void exposeUserDataToVC(UserRequest ureq, Identity identity) { + private void exposeUserDataToVC(UserRequest ureq, Identity identity) { removeAsListenerAndDispose(portraitCtr); portraitCtr = new DisplayPortraitController(ureq, getWindowControl(), identity, true, true); myContent.put("portrait", portraitCtr.getInitialComponent()); @@ -468,9 +481,9 @@ public class UserAdminController extends BasicController implements Activateable userShortDescrCtr = new UserShortDescription(ureq, getWindowControl(), identity); myContent.put("userShortDescription", userShortDescrCtr.getInitialComponent()); } - + /** - * + * * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) */ @Override diff --git a/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java b/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java index 03f368effbc95ea05574c5e9057185325e5b0eb5..c83957ea1b2acb8a99b7a537027dacc5725dae9f 100644 --- a/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java +++ b/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java @@ -145,6 +145,8 @@ public class UsermanagerUserSearchController extends BasicController implements private BaseSecurityModule securityModule; @Autowired private BaseSecurity securityManager; + @Autowired + private UserBulkChangeManager ubcMan; /** * Constructor to trigger the user search workflow using a generic search form @@ -571,7 +573,6 @@ public class UsermanagerUserSearchController extends BasicController implements return; } selectedIdentities = tdm.getIdentities(tmse.getSelection()); - final UserBulkChangeManager ubcMan = UserBulkChangeManager.getInstance(); // valid selection: load in wizard Step start = new UserBulkChangeStep00(ureq, selectedIdentities); diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties index 86047f2db7364e468abac4a500a79785787a1f7f..e28d44592504a680a0ae52561fe5a087547eb38a 100644 --- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties @@ -56,13 +56,13 @@ msg.selectionempty=Bitte min. einen User ausw\u00E4hlen. new.error.email.choosen=Diese E-Mail-Adresse ist bereits vorhanden, Sie k\u00F6nnen f\u00FCr diese Person kein neues Benutzerkonto erstellen. Es wurden keine Daten gespeichert. new.error.loginname.choosen=Dieser Benutzername ist bereits vergeben. Versuchen Sie es mit einem anderen Benutzernamen. new.error.loginname.empty=$org.olat.user\:form.checkUsername -new.error.password.nomatch=Die beiden Passw\u00F6rter stimmen nicht \u00FCberein. +new.error.password.nomatch=Die beiden Passw\u00F6rter stimmen nicht \u00FCberein. new.error.property.invalid=Invalid input\! new.form.auth=OLAT-Passwort new.form.auth.false=nicht jetzt anlegen new.form.auth.true=anlegen new.form.language=Sprache -new.form.mandatory=Dieses Feld muss aufgef\u00FCllt werden. +new.form.mandatory=Dieses Feld muss aufgef\u00FCllt werden. new.form.password.new1=Passwort new.form.password.new2=Passwort verifizieren new.form.please.enter=Angaben zur Person des neuen Benutzerkontos @@ -119,7 +119,7 @@ search.form.title.user=Einschr\u00E4nkung auf Benutzer search.form.userLoginAfterDate=Nutzer hat sich zuletzt angemeldet nach search.form.userLoginBeforeDate=Nutzer hat sich zuletzt angemeldet vor selectall=$org.olat.core.gui.components.table\:checkall -sendtoken.wrong.auth=Dieser Benutzer verf\u00FCgt \u00FCber Authentifizierungsmethoden, welche nicht \u00FCber diesen Passwortlink ge\u00E4ndert werden k\u00F6nnen. Bitte pr\u00FCfen und l\u00F6schen Sie diese Authentifizierungsmethoden zuerst. +sendtoken.wrong.auth=Dieser Benutzer verf\u00FCgt \u00FCber Authentifizierungsmethoden, welche nicht \u00FCber diesen Passwortlink ge\u00E4ndert werden k\u00F6nnen. Bitte pr\u00FCfen und l\u00F6schen Sie diese Authentifizierungsmethoden zuerst. submit.cancel=Abbrechen submit.save=Speichern submit.search=Suchen @@ -131,7 +131,7 @@ table.header.vcard=Visitenkarte table.identity.action=Aktion table.identity.vcard=<i class\='o_icon o_icon-lg o_icon_home'> </i> table.identity.creationdate=Erstellt -table.identity.lastlogin=letzter Login +table.identity.lastlogin=letzter Login table.identity.name=Benutzername table.name.firstName=Vorname table.name.lastName=Nachname @@ -151,6 +151,7 @@ title.userlist=Liste der Benutzer title.usersearch=Benutzersuche user.found=Benutzer wurde gefunden view.courses=Lernressourcen +view.access=Buchungen view.effStatements=Statements view.groups=Gruppen view.lectures=Lektionen diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties index 2b9c5c6e304fda57346138db5368ef74eeae1698..d27e6e965a04ee63daf5d67e51d11d1d605037e5 100644 --- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties @@ -65,7 +65,7 @@ new.form.language=Language new.form.mandatory=This field is mandatory. new.form.password.new1=Password new.form.password.new2=Verify password -new.form.please.enter=Please enter information on new user +new.form.please.enter=Please enter information on new user new.form.please.enter.pwd=Choose a password for new user new.form.username=User name new.user.cancel=Action cancelled. No new user account created. @@ -98,9 +98,9 @@ search.form.afterDate=User created after search.form.beforeDate=User created before search.form.constraint.admin=Administrator search.form.constraint.auth.LDAP=LDAP password -search.form.constraint.auth.OLAT=OLAT/WebDAV password +search.form.constraint.auth.OLAT=OLAT/WebDAV password search.form.constraint.auth.OAuth=Social network authentication / Single-Sign-On (OAuth) -search.form.constraint.auth.Shib=Shibboleth password +search.form.constraint.auth.Shib=Shibboleth password search.form.constraint.auth.ShibGeneric=$\:search.form.constraint.auth.Shib search.form.constraint.auth.WEBDAV=WebDAV password search.form.constraint.auth.none=No authentication @@ -119,7 +119,7 @@ search.form.title.user=User restrictions search.form.userLoginAfterDate=Last user login after search.form.userLoginBeforeDate=Last user login before selectall=$org.olat.core.gui.components.table\:checkall -sendtoken.wrong.auth=This user has authentication tokens which can not be changed using this password link. Please review and delete this additional authentication tokens first. +sendtoken.wrong.auth=This user has authentication tokens which can not be changed using this password link. Please review and delete this additional authentication tokens first. submit.cancel=Cancel submit.save=Save submit.search=Search @@ -151,6 +151,7 @@ title.userlist=User list title.usersearch=User search user.found=User was found view.courses=Learning resources +view.access=Bookings view.effStatements=Statements view.groups=Groups view.lectures=Lectures diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fr.properties index c28d89636405bf65ece22f51e0d4643e0c73e72c..86e01f1594ba4459d2485f814cb79195130bd8ab 100644 --- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Sat Aug 27 17:52:54 CEST 2016 +#Sun Aug 27 16:10:20 CEST 2017 action.bulkedit=Changer les attributs de cet utilisateur action.choose=S\u00E9lectionner action.choose.finish=S\u00E9lectionner et terminer @@ -118,7 +118,7 @@ search.form.title.user=Limitation par utilisateurs search.form.userLoginAfterDate=Dernier login de l'utilisateur apr\u00E8s search.form.userLoginBeforeDate=Dernier login de l'utilisateur avant selectall=$org.olat.core.gui.components.table\:checkall -sendtoken.wrong.auth=L'utilisateur utilise une m\u00E9thode d'authentification qui ne peut pas \u00EAtre modifi\u00E9e avec le lien de changement de mot de passe. V\u00E9rifiez s'il-vous-pla\u00EEt d'abord la liste des m\u00E9thodes d'authentifications et \u00E9ventuellement effacez-les. +sendtoken.wrong.auth=L'utilisateur utilise une m\u00E9thode d'authentification qui ne peut pas \u00EAtre modifi\u00E9e avec le lien de changement de mot de passe. V\u00E9rifiez s'il vous pla\u00EEt d'abord la liste des m\u00E9thodes d'authentifications et \u00E9ventuellement effacez-les. submit.cancel=Annuler submit.save=Enregistrer submit.search=Chercher @@ -152,4 +152,5 @@ user.found=L'utilisateur a \u00E9t\u00E9 trouv\u00E9 view.courses=Objects didactiques view.effStatements=Attestations view.groups=Groupes +view.lectures=Cours blocs view.subscriptions=Abonnements diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_BR.properties index e6ec2e50cf449730a9e29a0b070d16f22dd48a7c..466c9145dfe2053a1a5ebea1d98b56cb8d6801ee 100644 --- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue Nov 22 16:11:19 CET 2016 +#Tue Sep 05 23:34:05 CEST 2017 action.bulkedit=Editar os atributos desses usu\u00E1rios action.choose=Choose action.choose.finish=Fechar e terminar @@ -153,4 +153,5 @@ user.found=User was found view.courses=Cursos view.effStatements=Comprovantes view.groups=Grupos +view.lectures=Aulas view.subscriptions=Assinaturas diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java index 1997655f7f7e46e78620829501f0894923d56f15..11e019e86262d93bca58c7a2247712e1342f3ab0 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java +++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java @@ -35,12 +35,9 @@ import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.runtime.RuntimeConstants; import org.olat.admin.user.SystemRolesAndRightsController; import org.olat.basesecurity.BaseSecurity; -import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.Constants; import org.olat.basesecurity.SecurityGroup; -import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DB; -import org.olat.core.commons.persistence.DBFactory; import org.olat.core.gui.components.form.ValidationError; import org.olat.core.gui.translator.Translator; import org.olat.core.helpers.Settings; @@ -50,7 +47,6 @@ import org.olat.core.id.User; import org.olat.core.id.UserConstants; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; -import org.olat.core.manager.BasicManager; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.WebappHelper; @@ -64,6 +60,9 @@ import org.olat.login.auth.OLATAuthManager; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.GenderPropertyHandler; import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * Description:<br> @@ -74,15 +73,30 @@ import org.olat.user.propertyhandlers.UserPropertyHandler; * * @author rhaag */ -public class UserBulkChangeManager extends BasicManager { +@Service +public class UserBulkChangeManager implements InitializingBean { + private static VelocityEngine velocityEngine; - private static OLog log = Tracing.createLoggerFor(UserBulkChangeManager.class); - private static UserBulkChangeManager INSTANCE = new UserBulkChangeManager(); + private static final OLog log = Tracing.createLoggerFor(UserBulkChangeManager.class); static final String PWD_IDENTIFYER = "password"; static final String LANG_IDENTIFYER = "language"; + + @Autowired + private DB dbInstance; + @Autowired + private MailManager mailManager; + @Autowired + private UserManager userManager; + @Autowired + private OLATAuthManager olatAuthManager; + @Autowired + private BaseSecurity securityManager; + @Autowired + private BusinessGroupService businessGroupService; - public UserBulkChangeManager() { + @Override + public void afterPropertiesSet() throws Exception { // init velocity engine Properties p = null; try { @@ -95,32 +109,29 @@ public class UserBulkChangeManager extends BasicManager { throw new RuntimeException("config error " + p.toString()); } } - - public static UserBulkChangeManager getInstance() { - return INSTANCE; - } public void changeSelectedIdentities(List<Identity> selIdentities, Map<String, String> attributeChangeMap, Map<String, String> roleChangeMap, List<String> notUpdatedIdentities, boolean isAdministrativeUser, List<Long> ownGroups, List<Long> partGroups, Translator trans, Identity addingIdentity) { - Translator transWithFallback = UserManager.getInstance().getPropertyHandlerTranslator(trans); + Translator transWithFallback = userManager.getPropertyHandlerTranslator(trans); String usageIdentifyer = UserBulkChangeStep00.class.getCanonicalName(); notUpdatedIdentities.clear(); - List<Identity> changedIdentities = new ArrayList<Identity>(); - List<UserPropertyHandler> userPropertyHandlers = UserManager.getInstance().getUserPropertyHandlersFor(usageIdentifyer, + List<Identity> changedIdentities = new ArrayList<>(); + List<UserPropertyHandler> userPropertyHandlers = userManager.getUserPropertyHandlersFor(usageIdentifyer, isAdministrativeUser); - String[] securityGroups = { Constants.GROUP_USERMANAGERS, Constants.GROUP_GROUPMANAGERS, Constants.GROUP_AUTHORS, Constants.GROUP_ADMIN }; - UserManager um = UserManager.getInstance(); - BaseSecurity secMgr = BaseSecurityManager.getInstance(); + String[] securityGroups = { + Constants.GROUP_USERMANAGERS, Constants.GROUP_GROUPMANAGERS, + Constants.GROUP_AUTHORS, Constants.GROUP_ADMIN, + Constants.GROUP_POOL_MANAGER, Constants.GROUP_INST_ORES_MANAGER + }; // loop over users to be edited: for (Identity identity : selIdentities) { - DB db = DBFactory.getInstance(); //reload identity from cache, to prevent stale object - identity = (Identity) db.loadObject(identity); + identity = securityManager.loadIdentityByKey(identity.getKey()); User user = identity.getUser(); String errorDesc = ""; boolean updateError = false; @@ -128,15 +139,14 @@ public class UserBulkChangeManager extends BasicManager { if (attributeChangeMap.containsKey(PWD_IDENTIFYER)) { String newPwd = attributeChangeMap.get(PWD_IDENTIFYER); if (StringHelper.containsNonWhitespace(newPwd)) { - if (!UserManager.getInstance().syntaxCheckOlatPassword(newPwd)) { + if (!userManager.syntaxCheckOlatPassword(newPwd)) { errorDesc = transWithFallback.translate("error.password"); updateError = true; } } else { newPwd = null; } - OLATAuthManager olatAuthenticationSpi = CoreSpringFactory.getImpl(OLATAuthManager.class); - olatAuthenticationSpi.changePasswordAsAdmin(identity, newPwd); + olatAuthManager.changePasswordAsAdmin(identity, newPwd); } // set language @@ -187,20 +197,20 @@ public class UserBulkChangeManager extends BasicManager { // set roles for identity // loop over securityGroups defined above for (String securityGroup : securityGroups) { - SecurityGroup secGroup = secMgr.findSecurityGroupByName(securityGroup); - Boolean isInGroup = secMgr.isIdentityInSecurityGroup(identity, secGroup); + SecurityGroup secGroup = securityManager.findSecurityGroupByName(securityGroup); + Boolean isInGroup = securityManager.isIdentityInSecurityGroup(identity, secGroup); String thisRoleAction = ""; if (roleChangeMap.containsKey(securityGroup)) { thisRoleAction = roleChangeMap.get(securityGroup); // user not anymore in security group, remove him if (isInGroup && thisRoleAction.equals("remove")) { - secMgr.removeIdentityFromSecurityGroup(identity, secGroup); - logAudit("User::" + addingIdentity.getName() + " removed system role::" + securityGroup + " from user::" + identity.getName(), null); + securityManager.removeIdentityFromSecurityGroup(identity, secGroup); + log.audit("User::" + addingIdentity.getName() + " removed system role::" + securityGroup + " from user::" + identity.getName(), null); } // user not yet in security group, add him if (!isInGroup && thisRoleAction.equals("add")) { - secMgr.addIdentityToSecurityGroup(identity, secGroup); - logAudit("User::" + addingIdentity.getName() + " added system role::" + securityGroup + " to user::" + identity.getName(), null); + securityManager.addIdentityToSecurityGroup(identity, secGroup); + log.audit("User::" + addingIdentity.getName() + " added system role::" + securityGroup + " to user::" + identity.getName(), null); } } } @@ -224,8 +234,8 @@ public class UserBulkChangeManager extends BasicManager { if(oldStatus != status && status == Identity.STATUS_LOGIN_DENIED && Boolean.parseBoolean(roleChangeMap.get("sendLoginDeniedEmail"))) { sendLoginDeniedEmail(identity); } - identity = secMgr.saveIdentityStatus(identity, status); - logAudit("User::" + addingIdentity.getName() + " changed accout status for user::" + identity.getName() + " from::" + oldStatusText + " to::" + newStatusText, null); + identity = securityManager.saveIdentityStatus(identity, status); + log.audit("User::" + addingIdentity.getName() + " changed accout status for user::" + identity.getName() + " from::" + oldStatusText + " to::" + newStatusText, null); } // persist changes: @@ -234,13 +244,13 @@ public class UserBulkChangeManager extends BasicManager { log.debug("error during bulkChange of users, following user could not be updated: " + errorOutput); notUpdatedIdentities.add(errorOutput); } else { - um.updateUserFromIdentity(identity); + userManager.updateUserFromIdentity(identity); changedIdentities.add(identity); - logAudit("User::" + addingIdentity.getName() + " successfully changed account data for user::" + identity.getName() + " in bulk change", null); + log.audit("User::" + addingIdentity.getName() + " successfully changed account data for user::" + identity.getName() + " in bulk change", null); } // commit changes for this user - db.intermediateCommit(); + dbInstance.commit(); } // for identities // FXOLAT-101: add identity to new groups: @@ -263,10 +273,9 @@ public class UserBulkChangeManager extends BasicManager { } } - BusinessGroupService bgs = CoreSpringFactory.getImpl(BusinessGroupService.class); MailPackage mailing = new MailPackage(); - bgs.updateMemberships(addingIdentity, changes, mailing); - DBFactory.getInstance().commit(); + businessGroupService.updateMemberships(addingIdentity, changes, mailing); + dbInstance.commit(); } } @@ -276,11 +285,11 @@ public class UserBulkChangeManager extends BasicManager { Translator translator = Util.createPackageTranslator(SystemRolesAndRightsController.class, locale); String gender = ""; - UserPropertyHandler handler = UserManager.getInstance().getUserPropertiesConfig().getPropertyHandler(UserConstants.GENDER); + UserPropertyHandler handler = userManager.getUserPropertiesConfig().getPropertyHandler(UserConstants.GENDER); if(handler instanceof GenderPropertyHandler) { String internalGender = ((GenderPropertyHandler)handler).getInternalValue(identity.getUser()); if(StringHelper.containsNonWhitespace(internalGender)) { - Translator userPropTrans = UserManager.getInstance().getUserPropertiesConfig().getTranslator(translator); + Translator userPropTrans = userManager.getUserPropertiesConfig().getTranslator(translator); gender = userPropTrans.translate("form.name.gender.salutation." + internalGender); } } @@ -288,7 +297,7 @@ public class UserBulkChangeManager extends BasicManager { String[] args = new String[] { identity.getName(),//0: changed users username identity.getUser().getProperty(UserConstants.EMAIL, null),// 1: changed users email address - UserManager.getInstance().getUserDisplayName(identity.getUser()),// 2: Name (first and last name) of user who changed the password + userManager.getUserDisplayName(identity.getUser()),// 2: Name (first and last name) of user who changed the password WebappHelper.getMailConfig("mailSupport"), //3: configured support email address identity.getUser().getProperty(UserConstants.LASTNAME, null), //4 last name getServerURI(), //5 url system @@ -299,7 +308,7 @@ public class UserBulkChangeManager extends BasicManager { bundle.setToId(identity); bundle.setContent(translator.translate("mailtemplate.login.denied.subject", args), translator.translate("mailtemplate.login.denied.body", args)); - CoreSpringFactory.getImpl(MailManager.class).sendExternMessage(bundle, null, false); + mailManager.sendExternMessage(bundle, null, false); } private String getServerURI() { @@ -317,19 +326,15 @@ public class UserBulkChangeManager extends BasicManager { velocityEngine.evaluate(vcContext, evaluatedUserValue, "vcUservalue", valToEval); } catch (ParseErrorException e) { log.error("parsing of values in BulkChange Field not possible!"); - e.printStackTrace(); return "ERROR"; } catch (MethodInvocationException e) { log.error("evaluating of values in BulkChange Field not possible!"); - e.printStackTrace(); return "ERROR"; } catch (ResourceNotFoundException e) { log.error("evaluating of values in BulkChange Field not possible!"); - e.printStackTrace(); return "ERROR"; } catch (Exception e) { log.error("evaluating of values in BulkChange Field not possible!"); - e.printStackTrace(); return "ERROR"; } return evaluatedUserValue.toString(); @@ -342,8 +347,7 @@ public class UserBulkChangeManager extends BasicManager { * @param isAdministrativeUser */ public void setUserContext(Identity identity, Context vcContext) { - List<UserPropertyHandler> userPropertyHandlers2; - userPropertyHandlers2 = UserManager.getInstance().getAllUserPropertyHandlers(); + List<UserPropertyHandler> userPropertyHandlers2 = userManager.getAllUserPropertyHandlers(); for (UserPropertyHandler userPropertyHandler : userPropertyHandlers2) { String propertyName = userPropertyHandler.getName(); String userValue = identity.getUser().getProperty(propertyName, null); @@ -358,8 +362,7 @@ public class UserBulkChangeManager extends BasicManager { public Context getDemoContext(Translator propertyTrans) { Context vcContext = new VelocityContext(); - List<UserPropertyHandler> userPropertyHandlers2; - userPropertyHandlers2 = UserManager.getInstance().getAllUserPropertyHandlers(); + List<UserPropertyHandler> userPropertyHandlers2 = userManager.getAllUserPropertyHandlers(); for (UserPropertyHandler userPropertyHandler : userPropertyHandlers2) { String propertyName = userPropertyHandler.getName(); String userValue = propertyTrans.translate("import.example." + userPropertyHandler.getName()); diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep00.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep00.java index cd83c298e0bf1a385ad3f4f2770f22a2e6d1444c..7f3d9a394ea998578cd7440207e07361899c3e16 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep00.java +++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep00.java @@ -60,6 +60,7 @@ import org.olat.user.ProfileFormController; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.GenericUnique127CharTextPropertyHandler; import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.springframework.beans.factory.annotation.Autowired; public /** * Description:<br> @@ -74,12 +75,10 @@ class UserBulkChangeStep00 extends BasicStep { static final String usageIdentifyer = UserBulkChangeStep00.class.getCanonicalName(); static final String usageIdentifyerForAllProperties = ProfileFormController.class.getCanonicalName(); - TextElement textAreaElement; - List<Identity> identitiesToEdit; + private List<Identity> identitiesToEdit; private static VelocityEngine velocityEngine; - boolean isAdministrativeUser; - boolean isOLATAdmin; - static UserBulkChangeManager ubcMan; + private boolean isAdministrativeUser; + private boolean isOLATAdmin; static { // init velocity engine @@ -100,7 +99,6 @@ class UserBulkChangeStep00 extends BasicStep { this.identitiesToEdit = toEdit; setI18nTitleAndDescr("step0.description", null); setNextStep(new UserBulkChangeStep01(ureq)); - ubcMan = UserBulkChangeManager.getInstance(); Roles roles = ureq.getUserSession().getRoles(); isOLATAdmin = roles.isOLATAdmin(); isAdministrativeUser = (roles.isAuthor() || roles.isGroupManager() || roles.isUserManager() || roles.isOLATAdmin()); @@ -129,9 +127,12 @@ class UserBulkChangeStep00 extends BasicStep { private final class UserBulkChangeStepForm00 extends StepFormBasicController { private FormLayoutContainer textContainer; private List<UserPropertyHandler> userPropertyHandlers; - FormItem formitem; - List<MultipleSelectionElement> checkBoxes; - List<FormItem> formItems; + private FormItem formitem; + private List<MultipleSelectionElement> checkBoxes; + private List<FormItem> formItems; + + @Autowired + private UserBulkChangeManager ubcMan; public UserBulkChangeStepForm00(UserRequest ureq, WindowControl control, Form rootForm, StepsRunContext runContext) { super(ureq, control, rootForm, runContext, LAYOUT_VERTICAL, null); diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep01.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep01.java index 6460b32e27ecaae8ce29a9fb9ee524b28fbcfaf6..582d45f4618400ae8690bd61f1950e64a380116f 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep01.java +++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep01.java @@ -20,11 +20,10 @@ package org.olat.admin.user.bulkChange; import java.util.HashMap; -import java.util.HashSet; +import java.util.Map; import org.olat.admin.user.SystemRolesAndRightsController; import org.olat.basesecurity.BaseSecurity; -import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.Constants; import org.olat.basesecurity.SecurityGroup; import org.olat.core.gui.UserRequest; @@ -36,7 +35,6 @@ import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; -import org.olat.core.gui.components.form.flexible.impl.rules.RulesFactory; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.wizard.BasicStep; @@ -48,6 +46,7 @@ import org.olat.core.gui.control.generic.wizard.StepsRunContext; import org.olat.core.id.Identity; import org.olat.core.util.Util; import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -91,25 +90,34 @@ class UserBulkChangeStep01 extends BasicStep { private final class UserBulkChangeStepForm01 extends StepFormBasicController { private FormLayoutContainer textContainer; - private HashSet<FormItem> targets; + private MultipleSelectionElement chkAuthor; private SingleSelection setAuthor; private MultipleSelectionElement chkUserManager; private SingleSelection setUserManager; private MultipleSelectionElement chkGroupManager; private SingleSelection setGroupManager; - private Identity identity; + private MultipleSelectionElement chkPoolManager; + private SingleSelection setPoolManager; + private MultipleSelectionElement chkInstitutionManager; + private SingleSelection setInstitutionManager; private MultipleSelectionElement chkAdmin; private SingleSelection setAdmin; private MultipleSelectionElement chkStatus; private SingleSelection setStatus; private MultipleSelectionElement sendLoginDeniedEmail; + + private Identity identity; + + @Autowired + private UserManager userManager; + @Autowired + private BaseSecurity securityManager; public UserBulkChangeStepForm01(UserRequest ureq, WindowControl control, Form rootForm, StepsRunContext runContext) { super(ureq, control, rootForm, runContext, LAYOUT_VERTICAL, null); // use custom translator with fallback to user properties translator - UserManager um = UserManager.getInstance(); - setTranslator(um.getPropertyHandlerTranslator(getTranslator())); + setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); flc.setTranslator(getTranslator()); initForm(ureq); } @@ -121,9 +129,8 @@ class UserBulkChangeStep01 extends BasicStep { @Override protected void formOK(UserRequest ureq) { - Boolean validChange = (Boolean) getFromRunContext("validChange"); - HashMap<String, String> roleChangeMap = new HashMap<String, String>(); + Map<String, String> roleChangeMap = new HashMap<>(); if (chkUserManager!=null && chkUserManager.getSelectedKeys().contains("Usermanager")) { roleChangeMap.put(Constants.GROUP_USERMANAGERS, setUserManager.getSelectedKey()); @@ -139,6 +146,16 @@ class UserBulkChangeStep01 extends BasicStep { roleChangeMap.put(Constants.GROUP_AUTHORS, setAuthor.getSelectedKey()); validChange = true; } + + if (chkPoolManager!=null && chkPoolManager.getSelectedKeys().contains("PoolManager")) { + roleChangeMap.put(Constants.GROUP_POOL_MANAGER, setPoolManager.getSelectedKey()); + validChange = true; + } + + if (chkInstitutionManager!=null && chkInstitutionManager.getSelectedKeys().contains("InstitutionManager")) { + roleChangeMap.put(Constants.GROUP_INST_ORES_MANAGER, setInstitutionManager.getSelectedKey()); + validChange = true; + } if (chkAdmin!=null && chkAdmin.getSelectedKeys().contains("Admin")) { roleChangeMap.put(Constants.GROUP_ADMIN, setAdmin.getSelectedKey()); @@ -160,6 +177,29 @@ class UserBulkChangeStep01 extends BasicStep { fireEvent(ureq, StepsEvent.ACTIVATE_NEXT); } + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(chkUserManager == source) { + setUserManager.setVisible(chkUserManager.isAtLeastSelected(1)); + } else if(chkGroupManager == source) { + setGroupManager.setVisible(chkGroupManager.isAtLeastSelected(1)); + } else if(chkAuthor == source) { + setAuthor.setVisible(chkAuthor.isAtLeastSelected(1)); + } else if(chkPoolManager == source) { + setPoolManager.setVisible(chkPoolManager.isAtLeastSelected(1)); + } else if(chkInstitutionManager == source) { + setInstitutionManager.setVisible(chkInstitutionManager.isAtLeastSelected(1)); + } else if(chkAdmin == source) { + setAdmin.setVisible(chkAdmin.isAtLeastSelected(1)); + } else if(chkStatus == source || setStatus == source) { + setStatus.setVisible(chkStatus.isAtLeastSelected(1)); + boolean loginDenied = chkStatus.isAtLeastSelected(1) && setStatus.isOneSelected() + && Integer.toString(Identity.STATUS_LOGIN_DENIED).equals(setStatus.getSelectedKey()); + sendLoginDeniedEmail.setVisible(loginDenied); + } + super.formInnerEvent(ureq, source, event); + } + @Override protected boolean validateFormLogic(UserRequest ureq) { // always true, because no changes are required @@ -184,16 +224,20 @@ class UserBulkChangeStep01 extends BasicStep { // check user rights: boolean iAmOlatAdmin = ureq.getUserSession().getRoles().isOLATAdmin(); identity = ureq.getIdentity(); - BaseSecurity secMgr = BaseSecurityManager.getInstance(); + // get user system roles groups from security manager - SecurityGroup adminGroup = secMgr.findSecurityGroupByName(Constants.GROUP_ADMIN); - boolean isAdmin = secMgr.isIdentityInSecurityGroup(identity, adminGroup); - SecurityGroup userManagerGroup = secMgr.findSecurityGroupByName(Constants.GROUP_USERMANAGERS); - boolean isUserManager = secMgr.isIdentityInSecurityGroup(identity, userManagerGroup); - SecurityGroup authorGroup = secMgr.findSecurityGroupByName(Constants.GROUP_AUTHORS); - boolean isAuthor = secMgr.isIdentityInSecurityGroup(identity, authorGroup); - SecurityGroup groupmanagerGroup = secMgr.findSecurityGroupByName(Constants.GROUP_GROUPMANAGERS); - boolean isGroupManager = secMgr.isIdentityInSecurityGroup(identity, groupmanagerGroup); + SecurityGroup adminGroup = securityManager.findSecurityGroupByName(Constants.GROUP_ADMIN); + boolean isAdmin = securityManager.isIdentityInSecurityGroup(identity, adminGroup); + SecurityGroup userManagerGroup = securityManager.findSecurityGroupByName(Constants.GROUP_USERMANAGERS); + boolean isUserManager = securityManager.isIdentityInSecurityGroup(identity, userManagerGroup); + SecurityGroup authorGroup = securityManager.findSecurityGroupByName(Constants.GROUP_AUTHORS); + boolean isAuthor = securityManager.isIdentityInSecurityGroup(identity, authorGroup); + SecurityGroup groupmanagerGroup = securityManager.findSecurityGroupByName(Constants.GROUP_GROUPMANAGERS); + boolean isGroupManager = securityManager.isIdentityInSecurityGroup(identity, groupmanagerGroup); + SecurityGroup poolManagerGroup = securityManager.findSecurityGroupByName(Constants.GROUP_POOL_MANAGER); + boolean isPoolManager = securityManager.isIdentityInSecurityGroup(identity, poolManagerGroup); + SecurityGroup insitutionManagerGroup = securityManager.findSecurityGroupByName(Constants.GROUP_INST_ORES_MANAGER); + boolean isInstitutionManager = securityManager.isIdentityInSecurityGroup(identity, insitutionManagerGroup); // usermanager: if (isAdmin || isUserManager || iAmOlatAdmin) { @@ -203,10 +247,6 @@ class UserBulkChangeStep01 extends BasicStep { setUserManager = uifactory.addDropdownSingleselect("setUserManager", null, innerFormLayout, addremove, addremoveTranslated, null); setUserManager.setVisible(false); - targets = new HashSet<FormItem>(); - targets.add(setUserManager); - RulesFactory.createHideRule(chkUserManager, null, targets, innerFormLayout); - RulesFactory.createShowRule(chkUserManager, "Usermanager", targets, innerFormLayout); } // groupmanager @@ -217,10 +257,6 @@ class UserBulkChangeStep01 extends BasicStep { setGroupManager = uifactory.addDropdownSingleselect("setGroupManager", null, innerFormLayout, addremove, addremoveTranslated, null); setGroupManager.setVisible(false); - targets = new HashSet<FormItem>(); - targets.add(setGroupManager); - RulesFactory.createHideRule(chkGroupManager, null, targets, innerFormLayout); - RulesFactory.createShowRule(chkGroupManager, "Groupmanager", targets, innerFormLayout); } // author @@ -231,14 +267,27 @@ class UserBulkChangeStep01 extends BasicStep { setAuthor = uifactory.addDropdownSingleselect("setAuthor", null, innerFormLayout, addremove, addremoveTranslated, null); setAuthor.setVisible(false); - targets = new HashSet<FormItem>(); - targets.add(setAuthor); - RulesFactory.createHideRule(chkAuthor, null, targets, innerFormLayout); - RulesFactory.createShowRule(chkAuthor, "Author", targets, innerFormLayout); } - //TODO unique user property (doesn't bulk change unique property) - + //pool manager + if (isAdmin || isPoolManager || iAmOlatAdmin) { + chkPoolManager = uifactory.addCheckboxesHorizontal("PoolManager", "table.role.poolManager", innerFormLayout, new String[] { "PoolManager" }, new String[] { "" }); + chkPoolManager.select("Author", false); + chkPoolManager.addActionListener(FormEvent.ONCLICK); + + setPoolManager = uifactory.addDropdownSingleselect("setPoolManager", null, innerFormLayout, addremove, addremoveTranslated, null); + setPoolManager.setVisible(false); + } + + // + if (isAdmin || isInstitutionManager || iAmOlatAdmin) { + chkInstitutionManager = uifactory.addCheckboxesHorizontal("InsitutionManager", "table.role.institutionManager", innerFormLayout, new String[] { "InstitutionManager" }, new String[] { "" }); + chkInstitutionManager.select("Author", false); + chkInstitutionManager.addActionListener(FormEvent.ONCLICK); + + setInstitutionManager = uifactory.addDropdownSingleselect("setInstitutionManager", null, innerFormLayout, addremove, addremoveTranslated, null); + setInstitutionManager.setVisible(false); + } // sysadmin if (isAdmin || iAmOlatAdmin) { @@ -248,10 +297,6 @@ class UserBulkChangeStep01 extends BasicStep { setAdmin = uifactory.addDropdownSingleselect("setAdmin",null, innerFormLayout, addremove, addremoveTranslated, null); setAdmin.setVisible(false); - targets = new HashSet<FormItem>(); - targets.add(setAdmin); - RulesFactory.createHideRule(chkAdmin, null, targets, innerFormLayout); - RulesFactory.createShowRule(chkAdmin, "Admin", targets, innerFormLayout); } // status @@ -260,7 +305,6 @@ class UserBulkChangeStep01 extends BasicStep { chkStatus.select("Status", false); chkStatus.addActionListener(FormEvent.ONCLICK); - // TODO: RH: pay attention: if status changes in Identity-statics this // may lead to missing status // implement methods in SystemRolesAndRightsController.java @@ -273,23 +317,11 @@ class UserBulkChangeStep01 extends BasicStep { setStatus = uifactory.addDropdownSingleselect("setStatus",null, innerFormLayout, statusKeys, statusValues, null); setStatus.setVisible(false); setStatus.addActionListener(FormEvent.ONCHANGE); - targets = new HashSet<FormItem>(); - targets.add(setStatus); - RulesFactory.createHideRule(chkStatus, null, targets, innerFormLayout); - RulesFactory.createShowRule(chkStatus, "Status", targets, innerFormLayout); - + sendLoginDeniedEmail = uifactory.addCheckboxesHorizontal("rightsForm.sendLoginDeniedEmail", innerFormLayout, new String[]{"y"}, new String[]{translate("rightsForm.sendLoginDeniedEmail")}); sendLoginDeniedEmail.setLabel(null, null); sendLoginDeniedEmail.setVisible(false); - RulesFactory.createHideRule(chkStatus, null, sendLoginDeniedEmail, innerFormLayout); - RulesFactory.createHideRule(setStatus, Integer.toString(Identity.STATUS_ACTIV), sendLoginDeniedEmail, innerFormLayout); - RulesFactory.createHideRule(setStatus, Integer.toString(Identity.STATUS_PERMANENT), sendLoginDeniedEmail, innerFormLayout); - RulesFactory.createShowRule(setStatus, Integer.toString(Identity.STATUS_LOGIN_DENIED), sendLoginDeniedEmail, innerFormLayout); - } - } - } - } diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep02.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep02.java index 0a334e52cf281d6ef227e68e647cab877907eed0..3d301cf72e65c3d75ce9851ce83bbaff032ce4d8 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep02.java +++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep02.java @@ -32,7 +32,6 @@ import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.Constants; import org.olat.basesecurity.SecurityGroup; -import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.EscapeMode; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -64,6 +63,7 @@ import org.olat.group.BusinessGroupService; import org.olat.group.ui.BusinessGroupFormController; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -80,20 +80,16 @@ class UserBulkChangeStep02 extends BasicStep { static final String usageIdentifyer = UserBulkChangeStep00.class.getCanonicalName(); public List<UserPropertyHandler> userPropertyHandlers; - private final UserBulkChangeManager ubcMan; - private final BusinessGroupService businessGroupService; - public UserBulkChangeStep02(UserRequest ureq) { super(ureq); setI18nTitleAndDescr("step2.description", null); setNextStep(Step.NOSTEP); - businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class); - ubcMan = UserBulkChangeManager.getInstance(); } /** * @see org.olat.core.gui.control.generic.wizard.Step#getInitialPrevNextFinishConfig() */ + @Override public PrevNextFinishConfig getInitialPrevNextFinishConfig() { return new PrevNextFinishConfig(true, false, true); } @@ -104,6 +100,7 @@ class UserBulkChangeStep02 extends BasicStep { * org.olat.core.gui.control.generic.wizard.StepsRunContext, * org.olat.core.gui.components.form.flexible.impl.Form) */ + @Override public StepFormController getStepController(UserRequest ureq, WindowControl windowControl, StepsRunContext stepsRunContext, Form form) { StepFormController stepI = new UserBulkChangeStepForm02(ureq, windowControl, form, stepsRunContext); return stepI; @@ -112,6 +109,11 @@ class UserBulkChangeStep02 extends BasicStep { private final class UserBulkChangeStepForm02 extends StepFormBasicController { private FormLayoutContainer textContainer; + + @Autowired + private UserBulkChangeManager ubcMan; + @Autowired + private BusinessGroupService businessGroupService; public UserBulkChangeStepForm02(UserRequest ureq, WindowControl control, Form rootForm, StepsRunContext runContext) { super(ureq, control, rootForm, runContext, LAYOUT_VERTICAL, null); @@ -165,8 +167,11 @@ class UserBulkChangeStep02 extends BasicStep { boolean isAdministrativeUser = (roles.isAuthor() || roles.isGroupManager() || roles.isUserManager() || roles.isOLATAdmin()); userPropertyHandlers = UserManager.getInstance().getUserPropertyHandlersFor(usageIdentifyer, isAdministrativeUser); - String[] securityGroups = { Constants.GROUP_USERMANAGERS, Constants.GROUP_GROUPMANAGERS, Constants.GROUP_AUTHORS, - Constants.GROUP_ADMIN }; + String[] securityGroups = { + Constants.GROUP_USERMANAGERS, Constants.GROUP_GROUPMANAGERS, + Constants.GROUP_POOL_MANAGER, Constants.GROUP_INST_ORES_MANAGER, + Constants.GROUP_AUTHORS, Constants.GROUP_ADMIN + }; // loop over users to be edited: for (Identity identity : selectedIdentities) { @@ -247,6 +252,8 @@ class UserBulkChangeStep02 extends BasicStep { } tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, "table.role.useradmin", colPos++, false, null, FlexiColumnModel.ALIGNMENT_LEFT, textRenderer)); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, "table.role.groupadmin", colPos++, false, null, FlexiColumnModel.ALIGNMENT_LEFT, textRenderer)); + tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, "table.role.poolManager", colPos++, false, null, FlexiColumnModel.ALIGNMENT_LEFT, textRenderer)); + tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, "table.role.institutionManager", colPos++, false, null, FlexiColumnModel.ALIGNMENT_LEFT, textRenderer)); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, "table.role.author", colPos++, false, null, FlexiColumnModel.ALIGNMENT_LEFT, textRenderer)); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, "table.role.admin", colPos++, false, null, FlexiColumnModel.ALIGNMENT_LEFT, textRenderer)); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, "table.role.status", colPos++, false, null, FlexiColumnModel.ALIGNMENT_LEFT, textRenderer)); diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties index f37c38da20a05dfd9191749301972dcbe00a00f2..d19e4c27a8cff8bb2638f5fe2465f27359e4ac99 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties @@ -21,6 +21,8 @@ table.role.author=Autor table.role.groupadmin=Gruppenverwalter table.role.status=Status table.role.useradmin=Benutzerverwalter +table.role.poolManager=Poolverwalter +table.role.institutionManager=Lernressourcenverwalter table.user.login=Benutzername title=\u00C4nderung von Benutzer-Attributen main.menu.title=OLAT Passwort diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties index f033cd7d2775be5c3a123acbd2be5ec785076c5b..da2a9fceb3eedb1ee4e015d047dae3bc751bed02 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties @@ -29,6 +29,8 @@ table.role.author=Author table.role.groupadmin=Group administrator table.role.status=Status table.role.useradmin=User administrator +table.role.poolManager=Question bank manager +table.role.institutionManager=Learning resource manager table.user.login=User name title=Modification of user attributes step1a.description=Choose group(s) diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_fr.properties index a1e212e8f657489c415645fb451d001eb43410d3..7ab76e8662e5bb0f8094dc2aff0032a59de0010c 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_fr.properties @@ -31,5 +31,7 @@ table.role.author=Auteur table.role.groupadmin=Administrateur des groupes table.role.status=Statut table.role.useradmin=Administrateur des utilisateurs +table.role.poolManager=Gestion banque de questions +table.role.institutionManager=Administrateur des ressources didactiques table.user.login=Nom d'utilisateur title=Modifications des attributs d'utilisateurs diff --git a/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java b/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java index 9cba30628dc6aa937f15a8e043706a0c122281bd..4dd3fc9ee0eb89271c09e2be17efe58d431d7d6a 100644 --- a/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java +++ b/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java @@ -67,6 +67,7 @@ import org.olat.properties.PropertyManager; import org.olat.registration.RegistrationManager; import org.olat.registration.TemporaryKey; import org.olat.repository.RepositoryDeletionModule; +import org.olat.resource.accesscontrol.provider.auto.AutoAccessManager; import org.olat.user.UserDataDeletable; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -76,12 +77,12 @@ import org.springframework.stereotype.Service; /** * Manager for user-deletion. - * - * @author Christian Guretzki + * + * @author Christian Guretzki */ @Service("userDeletionManager") public class UserDeletionManager extends BasicManager { - + public static final String DELETED_USER_DELIMITER = "_bkp_"; /** Default value for last-login duration in month. */ private static final int DEFAULT_LAST_LOGIN_DURATION = 24; @@ -90,14 +91,14 @@ public class UserDeletionManager extends BasicManager { private static final String LAST_LOGIN_DURATION_PROPERTY_NAME = "LastLoginDuration"; private static final String DELETE_EMAIL_DURATION_PROPERTY_NAME = "DeleteEmailDuration"; private static final String PROPERTY_CATEGORY = "UserDeletion"; - + private static UserDeletionManager INSTANCE; public static final String SEND_DELETE_EMAIL_ACTION = "sendDeleteEmail"; private static final String USER_ARCHIVE_DIR = "archive_deleted_users"; private static final String USER_DELETED_ACTION = "userdeleted"; private static boolean keepUserLoginAfterDeletion; private static boolean keepUserEmailAfterDeletion; - + // Flag used in user-delete to indicate that all deletable managers are initialized @Autowired @@ -109,6 +110,8 @@ public class UserDeletionManager extends BasicManager { @Autowired private MailManager mailManager; @Autowired + private AutoAccessManager autoAccessManager; + @Autowired private GroupDAO groupDao; @Autowired private DB dbInstance; @@ -127,12 +130,12 @@ public class UserDeletionManager extends BasicManager { /** * Send 'delete'- emails to a list of identities. The delete email is an announcement for the user-deletion. - * + * * @param selectedIdentities - * @return String with warning message (e.g. email-address not valid, could not send email). - * If there is no warning, the return String is empty (""). + * @return String with warning message (e.g. email-address not valid, could not send email). + * If there is no warning, the return String is empty (""). */ - public String sendUserDeleteEmailTo(List<Identity> selectedIdentities, MailTemplate template, + public String sendUserDeleteEmailTo(List<Identity> selectedIdentities, MailTemplate template, boolean isTemplateChanged, String keyEmailSubject, String keyEmailBody, Identity sender, Translator pT ) { StringBuilder buf = new StringBuilder(); if (template != null) { @@ -144,10 +147,10 @@ public class UserDeletionManager extends BasicManager { Translator identityTranslator = Util.createPackageTranslator(SelectionController.class, I18nManager.getInstance().getLocaleOrDefault(identity.getUser().getPreferences().getLanguage())); template.setSubjectTemplate(identityTranslator.translate(keyEmailSubject)); template.setBodyTemplate(identityTranslator.translate(keyEmailBody)); - } + } template.putVariablesInMailContext(template.getContext(), identity); logDebug(" Try to send Delete-email to identity=" + identity.getName() + " with email=" + identity.getUser().getProperty(UserConstants.EMAIL, null)); - + MailerResult result = new MailerResult(); MailBundle bundle = mailManager.makeMailBundle(null, identity, template, null, null, result); if(bundle != null) { @@ -159,7 +162,7 @@ public class UserDeletionManager extends BasicManager { mailManager.sendMessage(ccBundle); } } - + if (result.getReturnCode() != MailerResult.OK) { buf.append(pT.translate("email.error.send.failed", new String[] {identity.getUser().getProperty(UserConstants.EMAIL, null), identity.getName()} )).append("\n"); } @@ -176,11 +179,11 @@ public class UserDeletionManager extends BasicManager { } return buf.toString(); } - + private void markSendEmailEvent(Identity identity) { LifeCycleManager.createInstanceFor(identity).markTimestampFor(SEND_DELETE_EMAIL_ACTION); } - + /** * Return list of identities which have last-login older than 'lastLoginDuration' parameter. * This user are ready to start with user-deletion process. @@ -195,28 +198,28 @@ public class UserDeletionManager extends BasicManager { StringBuilder sb = new StringBuilder(); sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident") .append(" inner join fetch ident.user as user") - .append(" where ident.status=").append(Identity.STATUS_ACTIV).append(" and (ident.lastLogin = null or ident.lastLogin < :lastLogin)"); + .append(" where ident.status=").append(Identity.STATUS_ACTIV).append(" and (ident.lastLogin = null or ident.lastLogin < :lastLogin)"); List<Identity> identities = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Identity.class) .setParameter("lastLogin", lastLoginLimit.getTime(), TemporalType.TIMESTAMP) .getResultList(); - + // 2. get all 'active' identities in deletion process String queryStr = "select ident from org.olat.core.id.Identity as ident" + " , org.olat.commons.lifecycle.LifeCycleEntry as le" + " where ident.key = le.persistentRef " - + " and le.persistentTypeName ='" + IdentityImpl.class.getName() + "'" + + " and le.persistentTypeName ='" + IdentityImpl.class.getName() + "'" + " and le.action ='" + SEND_DELETE_EMAIL_ACTION + "' "; DBQuery dbq = DBFactory.getInstance().createQuery(queryStr); List<Identity> identitiesInProcess = dbq.list(); // 3. Remove all identities in deletion-process from all inactive-identities identities.removeAll(identitiesInProcess); - return identities; + return identities; } /** - * Return list of identities which are in user-deletion-process. - * user-deletion-process means delete-announcement.email send, duration of waiting for response is not expired. + * Return list of identities which are in user-deletion-process. + * user-deletion-process means delete-announcement.email send, duration of waiting for response is not expired. * @param deleteEmailDuration Duration of user-deletion-process in days * @return List of Identity objects */ @@ -228,7 +231,7 @@ public class UserDeletionManager extends BasicManager { + " , org.olat.commons.lifecycle.LifeCycleEntry as le" + " where ident.key = le.persistentRef " + " and ident.status = " + Identity.STATUS_ACTIV - + " and le.persistentTypeName ='" + IdentityImpl.class.getName() + "'" + + " and le.persistentTypeName ='" + IdentityImpl.class.getName() + "'" + " and le.action ='" + SEND_DELETE_EMAIL_ACTION + "' and le.lcTimestamp >= :deleteEmailDate "; DBQuery dbq = DBFactory.getInstance().createQuery(queryStr); dbq.setDate("deleteEmailDate", deleteEmailLimit.getTime()); @@ -236,8 +239,8 @@ public class UserDeletionManager extends BasicManager { } /** - * Return list of identities which are ready-to-delete in user-deletion-process. - * (delete-announcement.email send, duration of waiting for response is expired). + * Return list of identities which are ready-to-delete in user-deletion-process. + * (delete-announcement.email send, duration of waiting for response is expired). * @param deleteEmailDuration Duration of user-deletion-process in days * @return List of Identity objects */ @@ -249,17 +252,17 @@ public class UserDeletionManager extends BasicManager { + " , org.olat.commons.lifecycle.LifeCycleEntry as le" + " where ident.key = le.persistentRef " + " and ident.status = " + Identity.STATUS_ACTIV - + " and le.persistentTypeName ='" + IdentityImpl.class.getName() + "'" + + " and le.persistentTypeName ='" + IdentityImpl.class.getName() + "'" + " and le.action ='" + SEND_DELETE_EMAIL_ACTION + "' and le.lcTimestamp < :deleteEmailDate "; DBQuery dbq = DBFactory.getInstance().createQuery(queryStr); dbq.setDate("deleteEmailDate", deleteEmailLimit.getTime()); return dbq.list(); } - + /** * Delete all user-data in registered deleteable resources. * @param identity - * @return true + * @return true */ public void deleteIdentity(Identity identity) { logInfo("Start deleteIdentity for identity=" + identity); @@ -275,7 +278,7 @@ public class UserDeletionManager extends BasicManager { logInfo("UserDataDeletable-Loop element=" + element); element.deleteUserData(identity, newName, archiveFilePath); } - + // Delete all authentications for certain identity List<Authentication> authentications = securityManager.getAuthentications(identity); for (Authentication auth:authentications) { @@ -283,7 +286,7 @@ public class UserDeletionManager extends BasicManager { securityManager.deleteAuthentication(auth); logDebug("Delete auth=" + auth + " of identity=" + identity); } - + //remove identity from its security groups List<SecurityGroup> securityGroups = securityManager.getSecurityGroupsForIdentity(identity); for (SecurityGroup secGroup : securityGroups) { @@ -293,12 +296,15 @@ public class UserDeletionManager extends BasicManager { //remove identity from groups groupDao.removeMemberships(identity); + //remove all advance orders in auto-booking access manager + autoAccessManager.deleteAdvanceOrders(identity); + String key = identity.getUser().getProperty("emchangeKey", null); TemporaryKey tempKey = registrationManager.loadTemporaryKeyByRegistrationKey(key); if (tempKey != null) { registrationManager.deleteTemporaryKey(tempKey); - } - + } + identity = securityManager.loadIdentityByKey(identity.getKey()); //keep login-name only -> change email @@ -311,11 +317,11 @@ public class UserDeletionManager extends BasicManager { && !(keepUserEmailAfterDeletion && UserConstants.EMAIL.equals(actualProperty))) { persistedUser.setProperty(actualProperty, null); } - + if((!keepUserEmailAfterDeletion && UserConstants.EMAIL.equals(actualProperty))) { String oldEmail = userPropertyHandler.getUserProperty(persistedUser, null); String newEmail = ""; - if (StringHelper.containsNonWhitespace(oldEmail)){ + if (StringHelper.containsNonWhitespace(oldEmail)){ newEmail = getBackupStringWithDate(oldEmail); } logInfo("Update user-property user=" + persistedUser); @@ -323,7 +329,7 @@ public class UserDeletionManager extends BasicManager { } } UserManager.getInstance().updateUserFromIdentity(identity); - + logInfo("deleteUserProperties user=" + persistedUser); dbInstance.commit(); identity = securityManager.loadIdentityByKey(identity.getKey()); @@ -331,23 +337,23 @@ public class UserDeletionManager extends BasicManager { if (!keepUserEmailAfterDeletion) { identity = securityManager.saveIdentityName(identity, newName, null); } - + //keep everything, change identity.status to deleted logInfo("Change stater identity=" + identity); identity = securityManager.saveIdentityStatus(identity, Identity.STATUS_DELETED); - + LifeCycleManager.createInstanceFor(identity).deleteTimestampFor(SEND_DELETE_EMAIL_ACTION); LifeCycleManager.createInstanceFor(identity).markTimestampFor(USER_DELETED_ACTION, createLifeCycleLogDataFor(identity)); logAudit("User-Deletion: Delete all userdata for identity=" + identity); } - + public String getBackupStringWithDate(String original){ DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmm"); String dateStamp = dateFormat.format(new Date()); return dateStamp + DELETED_USER_DELIMITER + original; } - + private String createLifeCycleLogDataFor(Identity identity) { StringBuilder buf = new StringBuilder(); buf.append("<identity>"); @@ -417,7 +423,7 @@ public class UserDeletionManager extends BasicManager { } private File getArchivFilePath(Identity identity) { - String archiveFilePath = deletionModule.getArchiveRootPath() + File.separator + USER_ARCHIVE_DIR + File.separator + RepositoryDeletionModule.getArchiveDatePath() + String archiveFilePath = deletionModule.getArchiveRootPath() + File.separator + USER_ARCHIVE_DIR + File.separator + RepositoryDeletionModule.getArchiveDatePath() + File.separator + "del_identity_" + identity.getName(); File archiveIdentityRootDir = new File(archiveFilePath); if (!archiveIdentityRootDir.exists()) { @@ -445,7 +451,7 @@ public class UserDeletionManager extends BasicManager { public static boolean isKeepUserLoginAfterDeletion() { return keepUserLoginAfterDeletion; } - + public static class UserDataDeletableComparator implements Comparator<UserDataDeletable> { @Override public int compare(UserDataDeletable o1, UserDataDeletable o2) { diff --git a/src/main/java/org/olat/admin/user/imp/ImportStep00.java b/src/main/java/org/olat/admin/user/imp/ImportStep00.java index 0005b9bf3ffc512f50be2c7a4f5a166b2483aff2..2a46213ab295b9df6bb5687b53ec6b9eb0c18357 100644 --- a/src/main/java/org/olat/admin/user/imp/ImportStep00.java +++ b/src/main/java/org/olat/admin/user/imp/ImportStep00.java @@ -60,7 +60,6 @@ import org.olat.core.gui.media.MediaResource; import org.olat.core.id.Identity; import org.olat.core.id.UserConstants; import org.olat.core.util.StringHelper; -import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; import org.olat.registration.RegistrationManager; import org.olat.registration.TemporaryKey; @@ -124,6 +123,8 @@ class ImportStep00 extends BasicStep { @Autowired private UserManager um; @Autowired + private I18nModule i18nModule; + @Autowired private BaseSecurity securityManager; @Autowired private ShibbolethModule shibbolethModule; @@ -165,7 +166,7 @@ class ImportStep00 extends BasicStep { return true; } - String defaultlang = I18nModule.getDefaultLocale().toString(); + String defaultlang = i18nModule.getDefaultLocale().toString(); List<String> importedEmails = new ArrayList<String>(); boolean importDataError = false; @@ -184,7 +185,7 @@ class ImportStep00 extends BasicStep { // org.olat.admin.user.imp.UserImportController // are required and have to be submitted in the right order // - pwd can be enabled / disabled by configuration - Collection<String> languages = I18nModule.getEnabledLanguageKeys(); + Collection<String> languages = i18nModule.getEnabledLanguageKeys(); String[] lines = inp.split("\r?\n"); for (int i = 0; i < lines.length; i++) { if(i % 25 == 0) { @@ -449,7 +450,7 @@ class ImportStep00 extends BasicStep { private Mapper createMapper(UserRequest ureq) { final String charset = UserManager.getInstance().getUserCharset(ureq.getIdentity()); Mapper m = new Mapper() { - @SuppressWarnings({"synthetic-access" }) + @Override public MediaResource handle(String relPath, HttpServletRequest request) { setTranslator(UserManager.getInstance().getPropertyHandlerTranslator(getTranslator())); String headerLine = translate("table.user.login") + " *"; @@ -459,7 +460,7 @@ class ImportStep00 extends BasicStep { dataLine += "\t" + "olat4you"; } headerLine += "\t" + translate("table.user.lang"); - dataLine += "\t" + I18nManager.getInstance().getLocaleKey(getLocale()); + dataLine += "\t" + i18nModule.getLocaleKey(getLocale()); UserPropertyHandler userPropertyHandler; for (int i = 0; i < userPropertyHandlers.size(); i++) { userPropertyHandler = userPropertyHandlers.get(i); diff --git a/src/main/java/org/olat/admin/user/imp/TransientIdentity.java b/src/main/java/org/olat/admin/user/imp/TransientIdentity.java index fad7b2470525fe1cc3786c40da5bc1d8c659cd7d..c10747776e9ea3cf573d8808dba757750d398db0 100644 --- a/src/main/java/org/olat/admin/user/imp/TransientIdentity.java +++ b/src/main/java/org/olat/admin/user/imp/TransientIdentity.java @@ -85,6 +85,11 @@ public class TransientIdentity implements Identity, User { return properties.get(UserConstants.EMAIL); } + @Override + public String getInstitutionalEmail() { + return properties.get(UserConstants.INSTITUTIONALEMAIL); + } + public String getPassword() { return password; } diff --git a/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java b/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java index 60b9c43c0fc31eca06bfa9dd5295f90a2d019e17..bcfaf150e09372c21b38e5beafd478ff9e380710 100644 --- a/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java +++ b/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java @@ -168,6 +168,11 @@ public class UpdateIdentity implements Identity { return updatedProperties.get(UserConstants.EMAIL); } + @Override + public String getInstitutionalEmail() { + return updatedProperties.get(UserConstants.INSTITUTIONALEMAIL); + } + @Override public Date getCreationDate() { return user.getCreationDate(); diff --git a/src/main/java/org/olat/basesecurity/AuthHelper.java b/src/main/java/org/olat/basesecurity/AuthHelper.java index 007d56f6dab92b858ee281a4af1a80b94baa3aef..23627735571badd48b6f1404f53ab67a5841dfcb 100644 --- a/src/main/java/org/olat/basesecurity/AuthHelper.java +++ b/src/main/java/org/olat/basesecurity/AuthHelper.java @@ -224,7 +224,7 @@ public class AuthHelper { * @return true if login was successful, false otherwise */ public static int doAnonymousLogin(UserRequest ureq, Locale locale) { - Collection<String> supportedLanguages = I18nModule.getEnabledLanguageKeys(); + Collection<String> supportedLanguages = CoreSpringFactory.getImpl(I18nModule.class).getEnabledLanguageKeys(); if ( locale == null || ! supportedLanguages.contains(locale.toString()) ) { locale = I18nModule.getDefaultLocale(); } @@ -363,7 +363,7 @@ public class AuthHelper { boolean wasGuest = false; UserSession usess = ureq.getUserSession(); if(usess != null && usess.getRoles() != null) { - wasGuest = ureq.getUserSession().getRoles().isGuestOnly(); + wasGuest = usess.getRoles().isGuestOnly(); } String lang = I18nManager.getInstance().getLocaleKey(ureq.getLocale()); diff --git a/src/main/java/org/olat/basesecurity/BaseSecurity.java b/src/main/java/org/olat/basesecurity/BaseSecurity.java index c2445becd78ba24a3d1fc8aa92b68b84719cd7ac..6445099485a48b6e3b79ebbe526ac0cae81f08c6 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurity.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurity.java @@ -60,7 +60,7 @@ public interface BaseSecurity { * @param olatResourceable * @return true if permitted */ - public boolean isIdentityPermittedOnResourceable(Identity identity, String permission, OLATResourceable olatResourceable); + public boolean isIdentityPermittedOnResourceable(IdentityRef identity, String permission, OLATResourceable olatResourceable); @@ -70,7 +70,7 @@ public interface BaseSecurity { * @param identity * @return The roles of the identity */ - public Roles getRoles(Identity identity); + public Roles getRoles(IdentityRef identity); /** * Get the list of roles as string without inheritence (an admin @@ -78,7 +78,7 @@ public interface BaseSecurity { * @param identity * @return */ - public List<String> getRolesAsString(Identity identity); + public List<String> getRolesAsString(IdentityRef identity); /** * Update the roles @@ -95,7 +95,7 @@ public interface BaseSecurity { * @param checkTypeRight * @return true if permitted */ - public boolean isIdentityPermittedOnResourceable(Identity identity, String permission, OLATResourceable olatResourceable, + public boolean isIdentityPermittedOnResourceable(IdentityRef identity, String permission, OLATResourceable olatResourceable, boolean checkTypeRight); /** @@ -367,6 +367,8 @@ public interface BaseSecurity { */ public Authentication findAuthentication(IdentityRef identity, String provider); + public List<Authentication> findAuthentications(IdentityRef identity, List<String> providers); + public String findAuthenticationName(IdentityRef identity, String provider); @@ -526,6 +528,9 @@ public interface BaseSecurity { * found */ public Authentication findAuthenticationByAuthusername(String authusername, String provider); + + + public List<Authentication> findAuthenticationByAuthusername(String authusername, List<String> providers); /** diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java index d71ffa545081bac5350051de15ee371f098bb8b6..20ce0a75a79a428ae3d8a529c70ce219ef390bee 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java @@ -1,4 +1,5 @@ /** + * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> @@ -328,7 +329,7 @@ public class BaseSecurityManager implements BaseSecurity { } @Override - public boolean isIdentityPermittedOnResourceable(Identity identity, String permission, OLATResourceable olatResourceable) { + public boolean isIdentityPermittedOnResourceable(IdentityRef identity, String permission, OLATResourceable olatResourceable) { return isIdentityPermittedOnResourceable(identity, permission, olatResourceable, true); } @@ -336,7 +337,7 @@ public class BaseSecurityManager implements BaseSecurity { * @see org.olat.basesecurity.Manager#isIdentityPermittedOnResourceable(org.olat.core.id.Identity, java.lang.String, org.olat.core.id.OLATResourceable boolean) */ @Override - public boolean isIdentityPermittedOnResourceable(Identity identity, String permission, OLATResourceable olatResourceable, boolean checkTypeRight) { + public boolean isIdentityPermittedOnResourceable(IdentityRef identity, String permission, OLATResourceable olatResourceable, boolean checkTypeRight) { if(identity == null || identity.getKey() == null) return false;//no identity, no permission Long oresid = olatResourceable.getResourceableId(); @@ -368,7 +369,7 @@ public class BaseSecurityManager implements BaseSecurity { * @see org.olat.basesecurity.Manager#getRoles(org.olat.core.id.Identity) */ @Override - public Roles getRoles(Identity identity) { + public Roles getRoles(IdentityRef identity) { boolean isGuestOnly = false; boolean isInvitee = false; @@ -389,7 +390,7 @@ public class BaseSecurityManager implements BaseSecurity { } @Override - public List<String> getRolesAsString(Identity identity) { + public List<String> getRolesAsString(IdentityRef identity) { StringBuilder sb = new StringBuilder(); sb.append("select ngroup.groupName from ").append(NamedGroupImpl.class.getName()).append(" as ngroup ") .append(" where exists (") @@ -488,17 +489,20 @@ public class BaseSecurityManager implements BaseSecurity { /** * @see org.olat.basesecurity.Manager#isIdentityInSecurityGroup(org.olat.core.id.Identity, org.olat.basesecurity.SecurityGroup) */ + @Override public boolean isIdentityInSecurityGroup(Identity identity, SecurityGroup secGroup) { if (secGroup == null || identity == null) return false; - String queryString = "select count(sgmsi) from org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi where sgmsi.identity = :identitykey and sgmsi.securityGroup = :securityGroup"; - DBQuery query = DBFactory.getInstance().createQuery(queryString); - query.setLong("identitykey", identity.getKey()); - query.setLong("securityGroup", secGroup.getKey()); - query.setCacheable(true); - List res = query.list(); - Long cntL = (Long) res.get(0); - if (cntL.longValue() != 0 && cntL.longValue() != 1) throw new AssertException("unique n-to-n must always yield 0 or 1"); - return (cntL.longValue() == 1); + String queryString = "select sgmsi.key from org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi where sgmsi.identity.key=:identitykey and sgmsi.securityGroup.key=:securityGroupKey"; + + List<Long> membership = dbInstance.getCurrentEntityManager() + .createQuery(queryString, Long.class) + .setParameter("identitykey", identity.getKey()) + .setParameter("securityGroupKey", secGroup.getKey()) + .setHint("org.hibernate.cacheable", Boolean.TRUE) + .setFirstResult(0) + .setMaxResults(1) + .getResultList(); + return membership != null && membership.size() > 0 && membership.get(0) != null; } @Override @@ -1384,6 +1388,18 @@ public class BaseSecurityManager implements BaseSecurity { return results.get(0); } + @Override + public List<Authentication> findAuthentications(IdentityRef identity, List<String> providers) { + StringBuilder sb = new StringBuilder(); + sb.append("select auth from ").append(AuthenticationImpl.class.getName()) + .append(" as auth where auth.identity.key=:identityKey and auth.provider in (:providers)"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Authentication.class) + .setParameter("identityKey", identity.getKey()) + .setParameter("providers", providers) + .getResultList(); + } + @Override public String findAuthenticationName(IdentityRef identity, String provider) { if (identity==null) { @@ -1518,6 +1534,19 @@ public class BaseSecurityManager implements BaseSecurity { } return results.get(0); } + + @Override + public List<Authentication> findAuthenticationByAuthusername(String authusername, List<String> providers) { + StringBuilder sb = new StringBuilder(); + sb.append("select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth") + .append(" inner join fetch auth.identity ident") + .append(" where auth.provider in (:providers) and auth.authusername=:authusername"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Authentication.class) + .setParameter("providers", providers) + .setParameter("authusername", authusername) + .getResultList(); + } /** * @see org.olat.basesecurity.Manager#getVisibleIdentitiesByPowerSearch(java.lang.String, java.util.Map, boolean, org.olat.basesecurity.SecurityGroup[], org.olat.basesecurity.PermissionOnResourceable[], java.lang.String[], java.util.Date, java.util.Date) diff --git a/src/main/java/org/olat/basesecurity/_spring/baseSecurityContext.xml b/src/main/java/org/olat/basesecurity/_spring/baseSecurityContext.xml index f2a10a370bb7b09b4c8dd555929af490154a8fbc..88ed650d5ba0197e85acb7c130a3dc409dce66e4 100644 --- a/src/main/java/org/olat/basesecurity/_spring/baseSecurityContext.xml +++ b/src/main/java/org/olat/basesecurity/_spring/baseSecurityContext.xml @@ -10,14 +10,11 @@ <context:component-scan base-package="org.olat.basesecurity" /> - <!-- manager --> - <bean id="baseSecurityManager" class="org.olat.basesecurity.BaseSecurityManager" init-method="init" - depends-on="database, i18nModule, triggerI18nModuleInit"> + <bean id="baseSecurityManager" class="org.olat.basesecurity.BaseSecurityManager" init-method="init" depends-on="database"> <property name="resourceManager" ref="resourceManager"/> <property name="loginModule" ref="loginModule"/> <property name="dbInstance" ref="database"/> <property name="invitationDao" ref="invitationDao" /> <property name="dbVendor" value="${db.vendor}" /> </bean> - </beans> \ No newline at end of file diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java index 6e1da8f06550055b1c2096d49f5f60fbc2b3788d..2dff99d23e78423b70da0e15c811477b842fe65f 100644 --- a/src/main/java/org/olat/collaboration/CollaborationTools.java +++ b/src/main/java/org/olat/collaboration/CollaborationTools.java @@ -39,6 +39,7 @@ import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.Constants; import org.olat.basesecurity.GroupRoles; import org.olat.commons.calendar.CalendarManager; +import org.olat.commons.calendar.manager.ImportToCalendarManager; import org.olat.commons.calendar.ui.CalendarController; import org.olat.commons.calendar.ui.WeeklyCalendarController; import org.olat.commons.calendar.ui.components.KalendarRenderWrapper; @@ -671,8 +672,8 @@ public class CollaborationTools implements Serializable { * Delete calendar if exists */ if (businessGroupTodelete != null) { - CalendarManager calManager = CoreSpringFactory.getImpl(CalendarManager.class); - calManager.deleteGroupCalendar(businessGroupTodelete); + CoreSpringFactory.getImpl(ImportToCalendarManager.class).deleteGroupImportedCalendars(businessGroupTodelete); + CoreSpringFactory.getImpl(CalendarManager.class).deleteGroupCalendar(businessGroupTodelete); } /* diff --git a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java index 16785b2389a63f20361a4f1cf17833c0063bfdce..0c4e1c6a9fd8ecf11ea68a5cee4d64fa11f3a0b5 100644 --- a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java +++ b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java @@ -104,9 +104,9 @@ public class CollaborationToolsSettingsController extends BasicController { if (ureq.getUserSession().getRoles().isOLATAdmin()) { vc_collabtools.contextPut("isOlatAdmin", Boolean.TRUE); if(managed) { - quotaCtr = QuotaManager.getInstance().getQuotaViewInstance(ureq, getWindowControl(), collabTools.getFolderRelPath(), false); + quotaCtr = QuotaManager.getInstance().getQuotaViewInstance(ureq, getWindowControl(), collabTools.getFolderRelPath()); } else { - quotaCtr = QuotaManager.getInstance().getQuotaEditorInstance(ureq, getWindowControl(), collabTools.getFolderRelPath(), false); + quotaCtr = QuotaManager.getInstance().getQuotaEditorInstance(ureq, getWindowControl(), collabTools.getFolderRelPath()); } listenTo(quotaCtr); } else { diff --git a/src/main/java/org/olat/commons/calendar/CalendarUtils.java b/src/main/java/org/olat/commons/calendar/CalendarUtils.java index bee66d68fb7f9f43a834994a805aa22ae2eb1cfe..d5da7238248006c6b21b2a6f9d2cf555fa68d7fc 100644 --- a/src/main/java/org/olat/commons/calendar/CalendarUtils.java +++ b/src/main/java/org/olat/commons/calendar/CalendarUtils.java @@ -82,6 +82,15 @@ public class CalendarUtils { return cal; } + + + public static Date endOfDay(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal = getEndOfDay(cal); + return cal.getTime(); + } + public static Calendar getEndOfDay(Calendar cal) { cal.set(Calendar.HOUR_OF_DAY, 23); cal.set(Calendar.MINUTE, 59); diff --git a/src/main/java/org/olat/commons/calendar/ICalServlet.java b/src/main/java/org/olat/commons/calendar/ICalServlet.java index 545c4f991b30dfcf40a6136992ec0457eb44ae4e..beeed74b2a10369731ca15cbdc0b4281a36223ab 100644 --- a/src/main/java/org/olat/commons/calendar/ICalServlet.java +++ b/src/main/java/org/olat/commons/calendar/ICalServlet.java @@ -127,6 +127,8 @@ public class ICalServlet extends HttpServlet { throws IOException { String requestUrl = request.getPathInfo(); try { + //log need a session before the response is committed + request.getSession(); if (log.isDebug()) { log.debug("doGet pathInfo=" + requestUrl); } @@ -274,7 +276,7 @@ public class ICalServlet extends HttpServlet { out.write(CalScale.GREGORIAN.toString()); } - outputTTL(out); + outputTTL(agent, out); Set<String> timezoneIds = new HashSet<>(); outputCalendarComponents(calendar, out, agent, timezoneIds); @@ -312,7 +314,7 @@ public class ICalServlet extends HttpServlet { out.write(Version.VERSION_2_0.toString()); out.write(CalScale.GREGORIAN.toString()); - outputTTL(out); + outputTTL(agent, out); Set<String> timezoneIds = new HashSet<>(); int numOfFiles = iCalFiles.size(); @@ -337,6 +339,8 @@ public class ICalServlet extends HttpServlet { return Agent.outlook; } else if(userAgent != null && userAgent.indexOf("Google") >= 0 && userAgent.indexOf("Calendar") >= 0) { return Agent.googleCalendar; + } else if(userAgent != null && userAgent.startsWith("Java/1.")) { + return Agent.java; } return Agent.unkown; } @@ -349,12 +353,14 @@ public class ICalServlet extends HttpServlet { * @param out * @throws IOException */ - private void outputTTL(Writer out) + private void outputTTL(Agent agent, Writer out) throws IOException { out.write("X-PUBLISHED-TTL:PT" + TTL_HOURS + "H"); out.write(Strings.LINE_SEPARATOR); - out.write("REFRESH-INTERVAL;VALUE=DURATION:PT" + TTL_HOURS + "H"); - out.write(Strings.LINE_SEPARATOR); + if(agent == null || agent != Agent.java) { + out.write("REFRESH-INTERVAL;VALUE=DURATION:PT" + TTL_HOURS + "H"); + out.write(Strings.LINE_SEPARATOR); + } } private void outputTimeZoneForOutlook(Set<String> timezoneIds, Writer out) { @@ -499,8 +505,9 @@ public class ICalServlet extends HttpServlet { } private enum Agent { - unkown, - outlook, - googleCalendar + unkown, + outlook, + googleCalendar, + java } } \ No newline at end of file diff --git a/src/main/java/org/olat/commons/calendar/ImportCalendarJob.java b/src/main/java/org/olat/commons/calendar/ImportCalendarJob.java index 72beccee3076b35cd6b9879f4deaadfddb3c0672..8e6f2527213a9ebd73eac7ccd3f2bebd7e07270e 100644 --- a/src/main/java/org/olat/commons/calendar/ImportCalendarJob.java +++ b/src/main/java/org/olat/commons/calendar/ImportCalendarJob.java @@ -25,6 +25,8 @@ */ package org.olat.commons.calendar; +import java.util.Random; + import org.olat.commons.calendar.manager.ImportToCalendarManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.services.scheduler.JobWithDB; @@ -40,12 +42,25 @@ import org.quartz.JobExecutionContext; */ public class ImportCalendarJob extends JobWithDB { + private static final Random random = new Random(); + @Override public void executeWithDB(JobExecutionContext context) { try { + jitter(); CoreSpringFactory.getImpl(ImportToCalendarManager.class).updateCalendarIn(); } catch (Exception e) { log.error("", e); } } + + private void jitter() { + try { + double millis = random.nextDouble() * 180000.0d; + long wait = Math.round(millis); + Thread.sleep(wait); + } catch (InterruptedException e) { + log.error("", e); + } + } } diff --git a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_pt_BR.properties index 581a7b4235e41ac973f5b8f40b09e126f2744899..1bb2921e8c423c43f13f5e023cdd7758d20ff322 100644 --- a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Tue May 02 23:52:18 CEST 2017 +#Tue Sep 05 23:34:06 CEST 2017 cal.add.event=Adicionar evento cal.add.readonly=(somente leitura) cal.color.choose=Escolher cor diff --git a/src/main/java/org/olat/commons/calendar/_spring/calendarContext.xml b/src/main/java/org/olat/commons/calendar/_spring/calendarContext.xml index 5a5369adfe5e479364720c7d6f109f0f261445e0..f97c44e8e3819a685149c44b007de3d79f0d2188 100644 --- a/src/main/java/org/olat/commons/calendar/_spring/calendarContext.xml +++ b/src/main/java/org/olat/commons/calendar/_spring/calendarContext.xml @@ -10,7 +10,7 @@ <context:component-scan base-package="org.olat.commons.calendar" /> - <bean id="calendarImportTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="calendarImportTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="calendarImportJob" /> <!-- adjust cron style syntax for your needs A "Cron-Expression" is a string comprised of 6 or 7 fields separated by white space. The 6 mandatory and 1 optional fields are as follows: @@ -30,8 +30,9 @@ <property name="startDelay" value="40000" /> </bean> - <bean id="calendarImportJob" class="org.springframework.scheduling.quartz.JobDetailBean"> + <bean id="calendarImportJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="org.olat.commons.calendar.ImportCalendarJob" /> + <property name="durability" value="true" /> </bean> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> diff --git a/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java b/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java index a7c058380fe267e3f55b902aa4c4a305f62a5ee0..6b434b8585e07a01cf491f4d7c59d3584ef5e58d 100644 --- a/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java +++ b/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java @@ -700,18 +700,27 @@ public class ICalFileCalendarManager implements CalendarManager, InitializingBea // check all day event first boolean isAllDay = false; - Parameter dateParameter = event.getProperties().getProperty(Property.DTSTART).getParameters().getParameter(Value.DATE.getName()); - if (dateParameter != null) isAllDay = true; - - if (isAllDay) { + Parameter dateParameter = event.getProperties().getProperty(Property.DTSTART) + .getParameters().getParameter(Value.DATE.getName()); + if (dateParameter != null) { + isAllDay = true; + //Make sure the time of the dates are 00:00 localtime because DATE fields in iCal are GMT 00:00 //Note that start date and end date can have different offset because of daylight saving switch java.util.TimeZone timezone = java.util.GregorianCalendar.getInstance().getTimeZone(); start = new Date(start.getTime() - timezone.getOffset(start.getTime())); - end = new Date(end.getTime() - timezone.getOffset(end.getTime())); + end = new Date(end.getTime() - timezone.getOffset(end.getTime())); // adjust end date: ICal sets end dates to the next day end = new Date(end.getTime() - (1000 * 60 * 60 * 24)); + } else if(start != null && end != null && (end.getTime() - start.getTime()) == (24 * 60 * 60 * 1000)) { + //check that start has no hour, no minute and no second + java.util.Calendar cal = java.util.Calendar.getInstance(); + cal.setTime(start); + isAllDay = cal.get(java.util.Calendar.HOUR_OF_DAY) == 0 && cal.get(java.util.Calendar.MINUTE) == 0 + && cal.get(java.util.Calendar.SECOND) == 0 && cal.get(java.util.Calendar.MILLISECOND) == 0; + // adjust end date: ICal sets end dates to the next day + end = new Date(end.getTime() - (1000 * 60 * 60 * 24)); } Uid eventuid = event.getUid(); diff --git a/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarUserDeleteManager.java b/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarUserDeleteManager.java index eaf82a91bb71b806807ec083070d2e93035541ef..a003a306b92447879947fc992669149e511fc5fb 100644 --- a/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarUserDeleteManager.java +++ b/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarUserDeleteManager.java @@ -42,9 +42,13 @@ public class ICalFileCalendarUserDeleteManager implements UserDataDeletable { @Autowired private CalendarManager calendarManager; + @Autowired + private ImportToCalendarManager importToCalendarManager; @Override public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) { + importToCalendarManager.deletePersonalImportedCalendars(identity); + log.debug("Personal imported calendars deleted for identity=" + identity); calendarManager.deletePersonalCalendar(identity); log.debug("Personal calendar deleted for identity=" + identity); } diff --git a/src/main/java/org/olat/commons/calendar/manager/ImportCalendarManager.java b/src/main/java/org/olat/commons/calendar/manager/ImportCalendarManager.java index 85e7edadf4443772f07093a10c56b593a74ed8c9..f9af5d0d0cc03bfa982afe282a02442dc90b2fef 100644 --- a/src/main/java/org/olat/commons/calendar/manager/ImportCalendarManager.java +++ b/src/main/java/org/olat/commons/calendar/manager/ImportCalendarManager.java @@ -152,20 +152,24 @@ public class ImportCalendarManager { List<ImportedCalendar> importedCalendars = importedCalendarDao.getImportedCalendars(identity); for (ImportedCalendar importedCalendar: importedCalendars) { - if(reload) { - reloadImportCalendar(importedCalendar, timestamp); - } + try { + if(reload) { + reloadImportCalendar(importedCalendar, timestamp); + } - String calendarId = importedCalendar.getCalendarId(); - KalendarRenderWrapper calendarWrapper = calendarManager.getImportedCalendar(identity, calendarId); - calendarWrapper.setDisplayName(importedCalendar.getDisplayName()); - calendarWrapper.setAccess(KalendarRenderWrapper.ACCESS_READ_ONLY); - calendarWrapper.setImported(true); - CalendarUserConfiguration config = calendarManager.findCalendarConfigForIdentity(calendarWrapper.getKalendar(), identity); - if (config != null) { - calendarWrapper.setConfiguration(config); + String calendarId = importedCalendar.getCalendarId(); + KalendarRenderWrapper calendarWrapper = calendarManager.getImportedCalendar(identity, calendarId); + calendarWrapper.setDisplayName(importedCalendar.getDisplayName()); + calendarWrapper.setAccess(KalendarRenderWrapper.ACCESS_READ_ONLY); + calendarWrapper.setImported(true); + CalendarUserConfiguration config = calendarManager.findCalendarConfigForIdentity(calendarWrapper.getKalendar(), identity); + if (config != null) { + calendarWrapper.setConfiguration(config); + } + calendars.add(calendarWrapper); + } catch (Exception e) { + log.error("Cannot read an imported file", e); } - calendars.add(calendarWrapper); } Collections.sort(calendars, KalendarComparator.getInstance()); } diff --git a/src/main/java/org/olat/commons/calendar/manager/ImportToCalendarManager.java b/src/main/java/org/olat/commons/calendar/manager/ImportToCalendarManager.java index 1720bd39bb29e900f4a1bf5c6bb5b24bfbefaf4e..174defb0fefa1d0b7f352d6022bcfb9cf86fda17 100644 --- a/src/main/java/org/olat/commons/calendar/manager/ImportToCalendarManager.java +++ b/src/main/java/org/olat/commons/calendar/manager/ImportToCalendarManager.java @@ -30,14 +30,22 @@ import java.io.InputStream; import java.net.URL; import java.util.Date; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.olat.basesecurity.BaseSecurity; import org.olat.commons.calendar.CalendarManager; import org.olat.commons.calendar.model.ImportedToCalendar; import org.olat.commons.calendar.model.Kalendar; import org.olat.commons.calendar.ui.components.KalendarRenderWrapper; import org.olat.core.commons.persistence.DBFactory; +import org.olat.core.id.Identity; +import org.olat.core.id.OLATResourceable; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; +import org.olat.group.BusinessGroup; +import org.olat.group.manager.BusinessGroupDAO; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.manager.RepositoryEntryDAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -54,12 +62,19 @@ import org.springframework.stereotype.Service; */ @Service public class ImportToCalendarManager { - + + private AtomicInteger counter = new AtomicInteger(0); private static final OLog log = Tracing.createLoggerFor(ImportToCalendarManager.class); + @Autowired + private BaseSecurity securityManager; @Autowired private CalendarManager calendarManager; @Autowired + private BusinessGroupDAO businessGroupDao; + @Autowired + private RepositoryEntryDAO repositoryEntryDao; + @Autowired private ImportedToCalendarDAO importedToCalendarDao; /** @@ -70,30 +85,64 @@ public class ImportToCalendarManager { List<ImportedToCalendar> importedToCalendars = importedToCalendarDao.getImportedToCalendars(); log.audit("Begin to update " + importedToCalendars.size() + " calendars."); + //make a full check only every 10 runs + boolean check = counter.incrementAndGet() % 10 == 0; + int count = 0; for(ImportedToCalendar importedToCalendar:importedToCalendars) { String type = importedToCalendar.getToType(); String id = importedToCalendar.getToCalendarId(); String importUrl = importedToCalendar.getUrl(); - - Kalendar cal = calendarManager.getCalendar(type, id); - try(InputStream in = new URL(importUrl).openStream()) { - if(calendarManager.synchronizeCalendarFrom(in, importUrl, cal)) { - log.audit("Updated successfully calendar: " + type + " / " + id); - } else { - log.audit("Failed to update calendar: " + type + " / " + id); + if(check || check(importedToCalendar)) { + try(InputStream in = new URL(importUrl).openStream()) { + Kalendar cal = calendarManager.getCalendar(type, id); + if(calendarManager.synchronizeCalendarFrom(in, importUrl, cal)) { + log.audit("Updated successfully calendar: " + type + " / " + id); + } else { + log.audit("Failed to update calendar: " + type + " / " + id); + } + } catch(Exception ex) { + log.error("Cannot synchronize calendar (" + importedToCalendar.getKey() + ") from url: " + importUrl, ex); } - } catch(Exception ex) { - log.error("Cannot synchronize calendar from url: " + importUrl, ex); + } else { + log.audit("Delete imported calendar because of missing resource: " + type + " " + id + " with URL: " + importUrl); + deleteImportedCalendars(type, id); } if(count++ % 20 == 0) { DBFactory.getInstance().commit(); + + try { + Thread.sleep(1000);// sleep to don't overload the system + } catch (InterruptedException e) { + log.error("", e); + } } } return false; } + + private boolean check(ImportedToCalendar importedToCalendar) { + String id = importedToCalendar.getToCalendarId(); + String type = importedToCalendar.getToType(); + if(CalendarManager.TYPE_USER.equals(type)) { + Identity identity = securityManager.findIdentityByNameCaseInsensitive(id); + return identity != null && identity.getStatus() != null && identity.getStatus().intValue() < Identity.STATUS_DELETED; + } + if(CalendarManager.TYPE_COURSE.equals(type)) { + Long resourceId = new Long(id); + RepositoryEntry entry = repositoryEntryDao.loadByResourceId("CourseModule", resourceId); + return entry != null; + } + if(CalendarManager.TYPE_GROUP.equals(type)) { + Long resourceId = new Long(id); + BusinessGroup group = businessGroupDao.loadByResourceId(resourceId); + return group != null; + } + return true; + } + /** * Append the stream of events to the specified calendar. * @@ -139,4 +188,23 @@ public class ImportToCalendarManager { return false; } } + + public void deletePersonalImportedCalendars(Identity identity) { + deleteImportedCalendars(CalendarManager.TYPE_USER, identity.getName()); + } + + public void deleteGroupImportedCalendars(BusinessGroup businessGroup) { + deleteImportedCalendars(CalendarManager.TYPE_GROUP, businessGroup.getResourceableId().toString()); + } + + public void deleteCourseImportedCalendars(OLATResourceable course) { + deleteImportedCalendars(CalendarManager.TYPE_COURSE, course.getResourceableId().toString()); + } + + private void deleteImportedCalendars(String type, String id) { + List<ImportedToCalendar> importedToCalendars = importedToCalendarDao.getImportedToCalendars(id, type); + for(ImportedToCalendar importedToCalendar:importedToCalendars) { + importedToCalendarDao.delete(importedToCalendar); + } + } } diff --git a/src/main/java/org/olat/commons/calendar/manager/ImportedToCalendarDAO.java b/src/main/java/org/olat/commons/calendar/manager/ImportedToCalendarDAO.java index 21893f946b9c0049906339adf7a86ab0a3ac7b27..c77279d712aa8c3f72c4e4a118fae88dd9a3f5c1 100644 --- a/src/main/java/org/olat/commons/calendar/manager/ImportedToCalendarDAO.java +++ b/src/main/java/org/olat/commons/calendar/manager/ImportedToCalendarDAO.java @@ -65,9 +65,24 @@ public class ImportedToCalendarDAO { .getResultList(); } + public List<ImportedToCalendar> getImportedToCalendars(String toCalendarId, String toType) { + return dbInstance.getCurrentEntityManager() + .createNamedQuery("importedToCalendarByIdAndType", ImportedToCalendar.class) + .setParameter("toCalendarId", toCalendarId) + .setParameter("toType", toType) + .getResultList(); + } + public List<ImportedToCalendar> getImportedToCalendars() { return dbInstance.getCurrentEntityManager() .createNamedQuery("importedToCalendars", ImportedToCalendar.class) .getResultList(); } + + public void delete(ImportedToCalendar importedToCalendar) { + ImportedToCalendar reloadedImportedToCalendar = dbInstance.getCurrentEntityManager() + .getReference(ImportedToCalendar.class, importedToCalendar.getKey()); + dbInstance.getCurrentEntityManager() + .remove(reloadedImportedToCalendar); + } } diff --git a/src/main/java/org/olat/commons/calendar/model/ImportedToCalendar.java b/src/main/java/org/olat/commons/calendar/model/ImportedToCalendar.java index e9f0889d19f32f75c3df13c42d037e241c11eb9c..67e3f55addf02ee0e8023da122f73c3dcd88626c 100644 --- a/src/main/java/org/olat/commons/calendar/model/ImportedToCalendar.java +++ b/src/main/java/org/olat/commons/calendar/model/ImportedToCalendar.java @@ -46,6 +46,7 @@ import org.olat.core.id.Persistable; @Table(name="o_cal_import_to") @NamedQueries({ @NamedQuery(name="importedToCalendarByIdTypeAndUrl", query="select cal from importedtocal cal where cal.toCalendarId=:toCalendarId and cal.toType=:toType and cal.url=:url"), + @NamedQuery(name="importedToCalendarByIdAndType", query="select cal from importedtocal cal where cal.toCalendarId=:toCalendarId and cal.toType=:toType"), @NamedQuery(name="importedToCalendars", query="select cal from importedtocal cal") }) public class ImportedToCalendar implements ModifiedInfo, Persistable { diff --git a/src/main/java/org/olat/commons/calendar/ui/CalendarDetailsController.java b/src/main/java/org/olat/commons/calendar/ui/CalendarDetailsController.java index abc0b6516956dbde283dda9cdc2327197b922c14..7739cdcd98a66d521192649555a7f1aea0efb4eb 100644 --- a/src/main/java/org/olat/commons/calendar/ui/CalendarDetailsController.java +++ b/src/main/java/org/olat/commons/calendar/ui/CalendarDetailsController.java @@ -47,6 +47,7 @@ import org.olat.core.gui.media.RedirectMediaResource; import org.olat.core.gui.util.CSSHelper; import org.olat.core.helpers.Settings; import org.olat.core.util.CodeHelper; +import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.springframework.beans.factory.annotation.Autowired; @@ -81,10 +82,10 @@ public class CalendarDetailsController extends BasicController { if(!isGuestOnly && !(calendarModule.isManagedCalendars() && CalendarManagedFlag.isManaged(event, CalendarManagedFlag.all)) && calendar.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) { - editButton = LinkFactory.createButton("edit", mainVC, this); + editButton = LinkFactory.createButtonSmall("edit", mainVC, this); mainVC.put("edit", editButton); } - mainVC.contextPut("date", formatDate()); + addDateToMainVC(); if(!calendar.isPrivateEventsVisible() && event.getClassification() == KalendarEvent.CLASS_X_FREEBUSY) { mainVC.contextPut("subject", ""); @@ -92,7 +93,9 @@ public class CalendarDetailsController extends BasicController { mainVC.contextPut("links", new ArrayList<LinkWrapper>(1)); } else { mainVC.contextPut("subject", event.getSubject()); - mainVC.contextPut("description", event.getDescription()); + // format line breaks and render links as clickable links + StringBuilder description = Formatter.stripTabsAndReturns(Formatter.formatURLsAsLinks(event.getDescription())); + mainVC.contextPut("description", description.toString()); if(StringHelper.containsNonWhitespace(event.getLocation())) { mainVC.contextPut("location", event.getLocation()); } @@ -101,7 +104,7 @@ public class CalendarDetailsController extends BasicController { putInitialPanel(mainVC); } - private String formatDate() { + private String addDateToMainVC() { Locale locale = getLocale(); Calendar cal = CalendarUtils.createCalendarInstance(locale); Date begin = calEvent.getBegin(); @@ -110,13 +113,17 @@ public class CalendarDetailsController extends BasicController { StringBuilder sb = new StringBuilder(); sb.append(StringHelper.formatLocaleDateFull(begin.getTime(), locale)); + mainVC.contextPut("date", sb.toString()); + if (!calEvent.isAllDayEvent()) { - sb.append("<br />").append(StringHelper.formatLocaleTime(begin.getTime(), locale)); + sb = new StringBuilder(); + sb.append(StringHelper.formatLocaleTime(begin.getTime(), locale)); sb.append(" - "); if (!DateUtils.isSameDay(begin, end)) { sb.append(StringHelper.formatLocaleDateFull(end.getTime(), locale)).append(", "); } sb.append(StringHelper.formatLocaleTime(end.getTime(), locale)); + mainVC.contextPut("time", sb.toString()); } return sb.toString(); } diff --git a/src/main/java/org/olat/commons/calendar/ui/ConfirmUpdateController.java b/src/main/java/org/olat/commons/calendar/ui/ConfirmUpdateController.java index b403fdb1c3435c224cc0dca59b0c86c5ff0c9dbc..cbbf0a54b982a5dbc0e1e40a53904682d45f96e8 100644 --- a/src/main/java/org/olat/commons/calendar/ui/ConfirmUpdateController.java +++ b/src/main/java/org/olat/commons/calendar/ui/ConfirmUpdateController.java @@ -46,18 +46,20 @@ public class ConfirmUpdateController extends BasicController { private final Boolean allDay; private final Long dayDelta, minuteDelta; private final KalendarRecurEvent kalendarEvent; + private final boolean changeBegin; public ConfirmUpdateController(UserRequest ureq, WindowControl wControl, KalendarRecurEvent kalendarEvent) { - this(ureq, wControl, kalendarEvent, null, null, null); + this(ureq, wControl, kalendarEvent, null, null, null, true); } public ConfirmUpdateController(UserRequest ureq, WindowControl wControl, KalendarRecurEvent kalendarEvent, - Long dayDelta, Long minuteDelta, Boolean allDay) { + Long dayDelta, Long minuteDelta, Boolean allDay, boolean changeBegin) { super(ureq, wControl, Util.createPackageTranslator(CalendarModule.class, ureq.getLocale())); this.allDay = allDay; this.dayDelta = dayDelta; this.minuteDelta = minuteDelta; this.kalendarEvent = kalendarEvent; + this.changeBegin = changeBegin; VelocityContainer mainVC = createVelocityContainer("confirm_update"); cancelButton = LinkFactory.createButton("cancel", mainVC, this); @@ -80,6 +82,10 @@ public class ConfirmUpdateController extends BasicController { return minuteDelta; } + public boolean getChangeBegin() { + return changeBegin; + } + public KalendarRecurEvent getKalendarEvent() { return kalendarEvent; } diff --git a/src/main/java/org/olat/commons/calendar/ui/ImportCalendarByUrlController.java b/src/main/java/org/olat/commons/calendar/ui/ImportCalendarByUrlController.java index 4341f1896d39db6f8c5571a41c57f01eb2779f01..84bae23935dface3b32dd4a6a5cd259f7a707cfe 100644 --- a/src/main/java/org/olat/commons/calendar/ui/ImportCalendarByUrlController.java +++ b/src/main/java/org/olat/commons/calendar/ui/ImportCalendarByUrlController.java @@ -122,6 +122,7 @@ public class ImportCalendarByUrlController extends FormBasicController { logError("", e); } catch (OLATRuntimeException e) { showError("cal.import.url.content.invalid"); + logError("Invalid calendar: " + url, e); } } diff --git a/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java b/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java index df0c2b00d3afdfba43f9b179521dbff8527cee0f..5e35d520648e6a24233e2bfa1a7f853e4a18c39c 100644 --- a/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java +++ b/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java @@ -51,6 +51,7 @@ import org.olat.commons.calendar.ui.events.CalendarGUIModifiedEvent; import org.olat.commons.calendar.ui.events.CalendarGUIMoveEvent; import org.olat.commons.calendar.ui.events.CalendarGUIPrintEvent; import org.olat.commons.calendar.ui.events.CalendarGUIRemoveEvent; +import org.olat.commons.calendar.ui.events.CalendarGUIResizeEvent; import org.olat.commons.calendar.ui.events.CalendarGUISelectEvent; import org.olat.commons.calendar.ui.events.CalendarGUISettingEvent; import org.olat.commons.calendar.ui.events.CalendarGUIUpdateEvent; @@ -305,6 +306,10 @@ public class WeeklyCalendarController extends FormBasicController implements Act CalendarGUIMoveEvent moveEvent = (CalendarGUIMoveEvent)event; doMove(ureq, moveEvent.getKalendarEvent(), moveEvent.getDayDelta(), moveEvent.getMinuteDelta(), moveEvent.getAllDay()); + } else if (event instanceof CalendarGUIResizeEvent) { + CalendarGUIResizeEvent resizeEvent = (CalendarGUIResizeEvent)event; + doResize(ureq, resizeEvent.getKalendarEvent(), + resizeEvent.getMinuteDelta(), resizeEvent.getAllDay()); } else if (event instanceof CalendarGUIFormEvent) { String cmd = event.getCommand(); if(CalendarGUIFormEvent.CONFIGURE.equals(cmd)) { @@ -367,7 +372,7 @@ public class WeeklyCalendarController extends FormBasicController implements Act } else if(source == updateCtr) { if(event instanceof CalendarGUIUpdateEvent) { doUpdate((CalendarGUIUpdateEvent)event, updateCtr.getKalendarEvent(), - updateCtr.getDayDelta(), updateCtr.getMinuteDelta(), updateCtr.getAllDay()); + updateCtr.getDayDelta(), updateCtr.getMinuteDelta(), updateCtr.getAllDay(), updateCtr.getChangeBegin()); } cmc.deactivate(); cleanUp(); @@ -567,7 +572,7 @@ public class WeeklyCalendarController extends FormBasicController implements Act private void doMove(UserRequest ureq, KalendarEvent calEvent, Long dayDelta, Long minuteDelta, Boolean allDay) { if(calEvent instanceof KalendarRecurEvent && !StringHelper.containsNonWhitespace(calEvent.getRecurrenceID())) { - updateCtr = new ConfirmUpdateController(ureq, getWindowControl(), (KalendarRecurEvent)calEvent, dayDelta, minuteDelta, allDay); + updateCtr = new ConfirmUpdateController(ureq, getWindowControl(), (KalendarRecurEvent)calEvent, dayDelta, minuteDelta, allDay, true); listenTo(updateCtr); String title = translate("cal.edit.update"); @@ -586,10 +591,32 @@ public class WeeklyCalendarController extends FormBasicController implements Act } } - private void doUpdate(CalendarGUIUpdateEvent event, KalendarEvent kalendarEvent, Long dayDelta, Long minuteDelta, Boolean allDay) { + private void doResize(UserRequest ureq, KalendarEvent calEvent, Long minuteDelta, Boolean allDay) { + if(calEvent instanceof KalendarRecurEvent && !StringHelper.containsNonWhitespace(calEvent.getRecurrenceID())) { + updateCtr = new ConfirmUpdateController(ureq, getWindowControl(), (KalendarRecurEvent)calEvent, 0L, minuteDelta, allDay, false); + listenTo(updateCtr); + + String title = translate("cal.edit.update"); + cmc = new CloseableModalController(getWindowControl(), translate("close"), updateCtr.getInitialComponent(), true, title); + listenTo(cmc); + cmc.activate(); + } else { + Kalendar cal = calEvent.getCalendar(); + calEvent.setEnd(doMove(calEvent.getEnd(), 0L, minuteDelta)); + if(allDay != null && calEvent.isAllDayEvent() != allDay.booleanValue()) { + calEvent.setAllDayEvent(allDay.booleanValue()); + } + calendarManager.updateEventFrom(cal, calEvent); + calendarEl.getComponent().setDirty(true); + } + } + + private void doUpdate(CalendarGUIUpdateEvent event, KalendarEvent kalendarEvent, Long dayDelta, Long minuteDelta, Boolean allDay, boolean changeBegin) { switch(event.getCascade()) { case all: { - kalendarEvent.setBegin(doMove(kalendarEvent.getBegin(), dayDelta, minuteDelta)); + if (changeBegin) { + kalendarEvent.setBegin(doMove(kalendarEvent.getBegin(), dayDelta, minuteDelta)); + } kalendarEvent.setEnd(doMove(kalendarEvent.getEnd(), dayDelta, minuteDelta)); if(allDay != null && kalendarEvent.isAllDayEvent() != allDay.booleanValue()) { kalendarEvent.setAllDayEvent(allDay.booleanValue()); @@ -601,7 +628,9 @@ public class WeeklyCalendarController extends FormBasicController implements Act if(kalendarEvent instanceof KalendarRecurEvent) { KalendarRecurEvent refEvent = (KalendarRecurEvent)kalendarEvent; kalendarEvent = calendarManager.createKalendarEventRecurringOccurence(refEvent); - kalendarEvent.setBegin(doMove(kalendarEvent.getBegin(), dayDelta, minuteDelta)); + if (changeBegin) { + kalendarEvent.setBegin(doMove(kalendarEvent.getBegin(), dayDelta, minuteDelta)); + } kalendarEvent.setEnd(doMove(kalendarEvent.getEnd(), dayDelta, minuteDelta)); if(allDay != null && kalendarEvent.isAllDayEvent() != allDay.booleanValue()) { kalendarEvent.setAllDayEvent(allDay.booleanValue()); diff --git a/src/main/java/org/olat/commons/calendar/ui/_content/event_details.html b/src/main/java/org/olat/commons/calendar/ui/_content/event_details.html index 1cdcd575473a16eb274dc8b3b524d73ae2cad62c..1240684f85018817c1427706bd7bb6ad81850c60 100644 --- a/src/main/java/org/olat/commons/calendar/ui/_content/event_details.html +++ b/src/main/java/org/olat/commons/calendar/ui/_content/event_details.html @@ -1,14 +1,25 @@ -<div class="o_cal_time">$date</div> <div class="o_cal_wv_event_tooltip_content"> - $r.escapeHtml($subject) + <h5>$r.escapeHtml($subject)</h5> + + <div class="o_cal_date text-muted"> + <i class="o_icon o_icon-fw o_icon_calendar"> </i> + $date + </div> + #if($time && $time != "") + <div class="o_cal_time text-muted"> + <i class="o_icon o_icon-fw o_icon_time"> </i> + $time + </div> + #end #if($location && !${location.isEmpty()}) - <div class="o_cal_location"> - <b>$r.translate("cal.form.location"):</b> $r.escapeHtml($location) + <div class="o_cal_location text-muted"> + <i class="o_icon o_icon-fw o_icon_home" title="$r.translateInAttribute("cal.form.location")"> </i> + $r.escapeHtml($location) </div> #end #if($description && !${description.isEmpty()}) <div class="o_cal_description"> - <b>$r.translate("cal.form.description"):</b> $r.xssScan($description) + $r.xssScan($description) </div> #end <div class="o_cal_links"> diff --git a/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponent.java b/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponent.java index 0fa053c74c1f1b31213aaa9f4a688f6f8ac991fc..acaa327568faef50a4fe9b59eab523eac75c8707 100644 --- a/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponent.java +++ b/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponent.java @@ -147,6 +147,7 @@ public class FullCalendarComponent extends AbstractComponent { super.validate(ureq, vr); vr.getJsAndCSSAdder().addRequiredStaticJsFile("js/jquery/fullcalendar/fullcalendar.min.js"); vr.getJsAndCSSAdder().addRequiredStaticJsFile("js/jquery/ui/jquery-ui-1.11.4.custom.dnd.min.js"); + vr.getJsAndCSSAdder().addRequiredStaticJsFile("js/jquery/ui/jquery-ui-1.11.4.custom.resize.min.js"); } public boolean isOccurenceOfCalendarEvent(String eventId) { diff --git a/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponentRenderer.java b/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponentRenderer.java index 4149a42b09bcc18a545b01fbf854de12d6a0024e..044b13ff6b3344ab7d83fcdc3dfad311296aed59 100644 --- a/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponentRenderer.java +++ b/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponentRenderer.java @@ -144,6 +144,10 @@ public class FullCalendarComponentRenderer extends DefaultComponentRenderer { .append(FormJSHelper.generateXHRFnCallVariables(rootForm, formId, 1)) .append(" o_ffXHREvent(formNam, dispIdField, dispId, eventIdField, eventInt, true, false, false, 'evMove',calEvent.id,'dayDelta',dayDelta,'minuteDelta',minuteDelta,'allDay',allDay);\n") .append(" },\n") + .append(" eventResize: function(calEvent, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view) {\n") + .append(FormJSHelper.generateXHRFnCallVariables(rootForm, formId, 1)) + .append(" o_ffXHREvent(formNam, dispIdField, dispId, eventIdField, eventInt, true, false, false, 'evResize',calEvent.id,'dayDelta',dayDelta,'minuteDelta',minuteDelta,'allDay',allDay);\n") + .append(" },\n") .append(" select: function(startDate, endDate, allDay, jsEvent, view) {\n") .append(FormJSHelper.generateXHRFnCallVariables(rootForm, formId, 1)) .append(" o_ffXHREvent(formNam, dispIdField, dispId, eventIdField, eventInt, true, false, false, 'evAdd','new','start',startDate.getTime(),'end',endDate.getTime(),'allDay',allDay);\n") diff --git a/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarElement.java b/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarElement.java index 9a358019a7334bd5e1782e34ba7b5eea6a847e0c..3511dcc1c2d5005c2beb3a5b90179941e51f0058 100644 --- a/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarElement.java +++ b/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarElement.java @@ -30,6 +30,7 @@ import org.olat.commons.calendar.ui.events.CalendarGUIAddEvent; import org.olat.commons.calendar.ui.events.CalendarGUIFormEvent; import org.olat.commons.calendar.ui.events.CalendarGUIMoveEvent; import org.olat.commons.calendar.ui.events.CalendarGUIPrintEvent; +import org.olat.commons.calendar.ui.events.CalendarGUIResizeEvent; import org.olat.commons.calendar.ui.events.CalendarGUISelectEvent; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; @@ -104,6 +105,7 @@ public class FullCalendarElement extends FormItemImpl { String selectedEventId = getRootForm().getRequestParameter("evSelect"); String addEventMarker = getRootForm().getRequestParameter("evAdd"); String movedEventId = getRootForm().getRequestParameter("evMove"); + String resizedEventId = getRootForm().getRequestParameter("evResize"); String changeViewName = getRootForm().getRequestParameter("evChangeView"); String print = getRootForm().getRequestParameter("print"); String config = getRootForm().getRequestParameter("config"); @@ -134,6 +136,10 @@ public class FullCalendarElement extends FormItemImpl { String minuteDelta = getRootForm().getRequestParameter("minuteDelta"); String allDay = getRootForm().getRequestParameter("allDay"); doMove(ureq, movedEventId, dayDelta, minuteDelta, allDay); + } else if(StringHelper.containsNonWhitespace(resizedEventId)) { + String minuteDelta = getRootForm().getRequestParameter("minuteDelta"); + String allDay = getRootForm().getRequestParameter("allDay"); + doResize(ureq, resizedEventId, minuteDelta, allDay); } else if(StringHelper.containsNonWhitespace(changeViewName)) { String start = getRootForm().getRequestParameter("start"); doChangeView(changeViewName, start); @@ -189,6 +195,36 @@ public class FullCalendarElement extends FormItemImpl { } } + protected void doResize(UserRequest ureq, String eventId, String minuteDelta, String allDayStr) { + Long minute = null; + if(StringHelper.isLong(minuteDelta)) { + minute = Long.parseLong(minuteDelta); + } + + Boolean allDay = null; + if("true".equals(allDayStr)) { + allDay = Boolean.TRUE; + } else if("false".equals(allDayStr)) { + allDay = Boolean.FALSE; + } + + if(component.isOccurenceOfCalendarEvent(eventId)) { + String uid = component.getCalendarEventUid(eventId); + KalendarRenderWrapper cal = component.getCalendarById(uid); + KalendarRecurEvent rEvent = getCurrenceKalendarEvent(cal, eventId); + getRootForm().fireFormEvent(ureq, new CalendarGUIResizeEvent(this, rEvent, cal, minute, allDay)); + } else if(component.isReccurenceOfCalendarEvent(eventId)) { + String uid = component.getCalendarEventUid(eventId); + KalendarRenderWrapper cal = component.getCalendarById(uid); + KalendarRecurEvent rEvent = getCurrenceKalendarEvent(cal, eventId); + getRootForm().fireFormEvent(ureq, new CalendarGUIResizeEvent(this, rEvent, cal, minute, allDay)); + } else { + KalendarEvent event = component.getCalendarEvent(eventId); + KalendarRenderWrapper calWrapper = component.getCalendarByNormalizedId(eventId); + getRootForm().fireFormEvent(ureq, new CalendarGUIResizeEvent(this, event, calWrapper, minute, allDay)); + } + } + private void doAdd(UserRequest ureq, String start, String end, String allDay) { long startTime = -1; if(StringHelper.isLong(start)) { diff --git a/src/main/java/org/olat/commons/calendar/ui/events/CalendarGUIResizeEvent.java b/src/main/java/org/olat/commons/calendar/ui/events/CalendarGUIResizeEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..16edff1fbb9e36fa93e7539cb8318f41d5b65e98 --- /dev/null +++ b/src/main/java/org/olat/commons/calendar/ui/events/CalendarGUIResizeEvent.java @@ -0,0 +1,67 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.commons.calendar.ui.events; + +import org.olat.commons.calendar.model.KalendarEvent; +import org.olat.commons.calendar.ui.components.KalendarRenderWrapper; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; + +/** + * + * Initial date: 09.04.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CalendarGUIResizeEvent extends FormEvent { + + private static final long serialVersionUID = -5910033103406371704L; + public static final String CMD_RESIZE = "resizecalevent"; + + private Boolean allDay; + private Long minuteDelta; + private KalendarEvent event; + private KalendarRenderWrapper calendarWrapper; + + public CalendarGUIResizeEvent(FormItem item, KalendarEvent event, KalendarRenderWrapper calendarWrapper, + Long minuteDelta, Boolean allDay) { + super(CMD_RESIZE, item); + this.allDay = allDay; + this.minuteDelta = minuteDelta; + this.event = event; + this.calendarWrapper = calendarWrapper; + } + + public Boolean getAllDay() { + return allDay; + } + + public Long getMinuteDelta() { + return minuteDelta; + } + + public KalendarEvent getKalendarEvent() { + return event; + } + + public KalendarRenderWrapper getKalendarRenderWrapper() { + return calendarWrapper; + } +} diff --git a/src/main/java/org/olat/commons/info/model/InfoMessage.java b/src/main/java/org/olat/commons/info/InfoMessage.java similarity index 93% rename from src/main/java/org/olat/commons/info/model/InfoMessage.java rename to src/main/java/org/olat/commons/info/InfoMessage.java index b8de6b7f12a8b229cb5de796b541f7585599b6e0..d975bb12da44897ee4e1ade8a467505d7dd893ce 100644 --- a/src/main/java/org/olat/commons/info/model/InfoMessage.java +++ b/src/main/java/org/olat/commons/info/InfoMessage.java @@ -18,7 +18,7 @@ * <p> */ -package org.olat.commons.info.model; +package org.olat.commons.info; import java.util.Date; @@ -26,9 +26,6 @@ import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; /** - * - * Description:<br> - * TODO: srosse Class Description for InfoMessage * * <P> * Initial Date: 27 jul. 2010 <br> @@ -51,6 +48,10 @@ public interface InfoMessage { public String getMessage(); public void setMessage(String message); + + public String getAttachmentPath(); + + public void setAttachmentPath(String path); public Long getResId(); diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManager.java b/src/main/java/org/olat/commons/info/InfoMessageFrontendManager.java similarity index 87% rename from src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManager.java rename to src/main/java/org/olat/commons/info/InfoMessageFrontendManager.java index a43fc80e807e7d5979cc444da3e4b8b73f366eff..f1b3131881c78621728b6d5a2654e13d13429fad 100644 --- a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManager.java +++ b/src/main/java/org/olat/commons/info/InfoMessageFrontendManager.java @@ -18,17 +18,20 @@ * <p> */ -package org.olat.commons.info.manager; +package org.olat.commons.info; +import java.io.File; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; import org.olat.basesecurity.IdentityRef; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.manager.MailFormatter; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.util.resource.OresHelper; +import org.olat.core.util.vfs.VFSLeaf; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupRef; @@ -62,6 +65,12 @@ public interface InfoMessageFrontendManager { public void saveInfoMessage(InfoMessage msg); + public VFSLeaf getAttachment(InfoMessage msg); + + public String storeAttachment(File file, String filename, OLATResourceable ores, String subPath); + + public void deleteAttachments(Collection<String> paths); + public void deleteInfoMessage(InfoMessage infoMessage); public void updateInfoMessagesOfIdentity(BusinessGroupRef businessGroup, IdentityRef identity); diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageManager.java b/src/main/java/org/olat/commons/info/InfoMessageManager.java similarity index 55% rename from src/main/java/org/olat/commons/info/manager/InfoMessageManager.java rename to src/main/java/org/olat/commons/info/InfoMessageManager.java index 24f4b65916e8a4fc406661a8847153195d47bd66..82b4604057036684629761d2d018a9923980c19d 100644 --- a/src/main/java/org/olat/commons/info/manager/InfoMessageManager.java +++ b/src/main/java/org/olat/commons/info/InfoMessageManager.java @@ -18,40 +18,31 @@ * <p> */ -package org.olat.commons.info.manager; +package org.olat.commons.info; import java.util.Date; import java.util.List; import org.olat.basesecurity.IdentityRef; -import org.olat.commons.info.model.InfoMessage; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.group.BusinessGroupRef; -public abstract class InfoMessageManager { - - protected static InfoMessageManager INSTANCE; - - - public static InfoMessageManager getInstance() { - return INSTANCE; - } - +public interface InfoMessageManager { - public abstract InfoMessage createInfoMessage(OLATResourceable ores, String subPath, String businessPath, Identity author); + public InfoMessage createInfoMessage(OLATResourceable ores, String subPath, String businessPath, Identity author); - public abstract void saveInfoMessage(InfoMessage infoMessage); + public void saveInfoMessage(InfoMessage infoMessage); - public abstract void deleteInfoMessage(InfoMessage infoMessage); + public void deleteInfoMessage(InfoMessage infoMessage); - public abstract List<InfoMessage> loadInfoMessagesOfIdentity(BusinessGroupRef businessGroup, IdentityRef identity); + public List<InfoMessage> loadInfoMessagesOfIdentity(BusinessGroupRef businessGroup, IdentityRef identity); - public abstract InfoMessage loadInfoMessageByKey(Long key); + public InfoMessage loadInfoMessageByKey(Long key); - public abstract List<InfoMessage> loadInfoMessageByResource(OLATResourceable ores, String subPath, String businessPath, + public List<InfoMessage> loadInfoMessageByResource(OLATResourceable ores, String subPath, String businessPath, Date after, Date before, int firstResult, int maxReturn); - public abstract int countInfoMessageByResource(OLATResourceable ores, String subPath, String businessPath, + public int countInfoMessageByResource(OLATResourceable ores, String subPath, String businessPath, Date after, Date before); } diff --git a/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManager.java b/src/main/java/org/olat/commons/info/InfoSubscriptionManager.java similarity index 56% rename from src/main/java/org/olat/commons/info/notification/InfoSubscriptionManager.java rename to src/main/java/org/olat/commons/info/InfoSubscriptionManager.java index 210b10e83629630160edc9cb036cfaa257220d6a..0b010e065f8db2414844be0bdcb9742e87e9a80f 100644 --- a/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManager.java +++ b/src/main/java/org/olat/commons/info/InfoSubscriptionManager.java @@ -18,10 +18,11 @@ * <p> */ -package org.olat.commons.info.notification; +package org.olat.commons.info; import java.util.List; +import org.olat.commons.info.notification.InfoSubscription; import org.olat.core.commons.services.notifications.PublisherData; import org.olat.core.commons.services.notifications.Subscriber; import org.olat.core.commons.services.notifications.SubscriptionContext; @@ -38,30 +39,24 @@ import org.olat.core.util.prefs.Preferences; * Initial Date: 27 jul. 2010 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public abstract class InfoSubscriptionManager { - - protected static InfoSubscriptionManager INSTANCE; - - public static InfoSubscriptionManager getInstance() { - return INSTANCE; - } +public interface InfoSubscriptionManager { - public abstract SubscriptionContext getInfoSubscriptionContext(OLATResourceable resource, String subPath); + public SubscriptionContext getInfoSubscriptionContext(OLATResourceable resource, String subPath); - public abstract PublisherData getInfoPublisherData(OLATResourceable resource, String businessPath); + public PublisherData getInfoPublisherData(OLATResourceable resource, String businessPath); - public abstract InfoSubscription getInfoSubscription(Preferences prefs); + public InfoSubscription getInfoSubscription(Preferences prefs); - public abstract Subscriber getInfoSubscriber(Identity identity, OLATResourceable resource, String subPath); + public Subscriber getInfoSubscriber(Identity identity, OLATResourceable resource, String subPath); - public abstract List<Identity> getInfoSubscribers(OLATResourceable resource, String subPath); + public List<Identity> getInfoSubscribers(OLATResourceable resource, String subPath); - public abstract void subscribe(OLATResourceable resource, String resSubPath, String businessPath, Identity identity); + public void subscribe(OLATResourceable resource, String resSubPath, String businessPath, Identity identity); - public abstract void unsubscribe(OLATResourceable resource, String subPath, Identity identity); + public void unsubscribe(OLATResourceable resource, String subPath, Identity identity); - public abstract void markPublisherNews(OLATResourceable resource, String subPath); + public void markPublisherNews(OLATResourceable resource, String subPath); - public abstract void deleteSubscriptionContext(SubscriptionContext context); + public void deleteSubscriptionContext(SubscriptionContext context); } diff --git a/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml b/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml deleted file mode 100644 index 202632f67995d66b0a0d61be6f35fc8a00cb0871..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation="http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans.xsd"> - - <bean id="infoMessageFrontendManager" class="org.olat.commons.info.manager.InfoMessageFrontendManagerImpl"> - <property name="coordinatorManager" ref="coordinatorManager"/> - <property name="infoMessageManager" ref="infoMessageManager"/> - <property name="infoSubscriptionManager" ref="infoSubscriptionManager"/> - <property name="mailManager" ref="mailManager"/> - </bean> - - <bean id="infoMessageManager" class="org.olat.commons.info.manager.InfoMessageManagerImpl"> - <property name="dbInstance" ref="database"/> - </bean> - - <bean id="infoSubscriptionManager" class="org.olat.commons.info.notification.InfoSubscriptionManagerImpl"> - <property name="notificationsManager" ref="notificationsManager"/> - </bean> - -</beans> diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java index 518e29124305dd3ff660df85219baa2da5cca634..4a49b5e002a3955c8dd34cefa92831fb1caccb07 100644 --- a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java +++ b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java @@ -20,6 +20,16 @@ package org.olat.commons.info.manager; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; @@ -27,9 +37,12 @@ import java.util.Locale; import java.util.Set; import org.olat.basesecurity.IdentityRef; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; +import org.olat.commons.info.InfoMessageManager; +import org.olat.commons.info.InfoSubscriptionManager; import org.olat.commons.info.model.InfoMessageImpl; -import org.olat.commons.info.notification.InfoSubscriptionManager; +import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl; import org.olat.core.commons.services.notifications.SubscriptionContext; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; @@ -44,8 +57,14 @@ 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.MailerResult; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.VFSLeaf; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupRef; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + /** * @@ -55,47 +74,21 @@ import org.olat.group.BusinessGroupRef; * Initial Date: 28 juil. 2010 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ +@Service public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManager { + + private final DateFormat formater = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); + private static final OLog log = Tracing.createLoggerFor(InfoMessageFrontendManagerImpl.class); - private static final OLog log = Tracing.createLoggerFor(InfoMessageFrontendManagerImpl.class); - + @Autowired private MailManager mailManager; + @Autowired private CoordinatorManager coordinatorManager; + @Autowired private InfoMessageManager infoMessageManager; + @Autowired private InfoSubscriptionManager infoSubscriptionManager; - /** - * [used by Spring] - * @param mailManager - */ - public void setMailManager(MailManager mailManager) { - this.mailManager = mailManager; - } - - /** - * [used by Spring] - * @param coordinatorManager - */ - public void setCoordinatorManager(CoordinatorManager coordinatorManager) { - this.coordinatorManager = coordinatorManager; - } - - /** - * [used by Spring] - * @param infoMessageManager - */ - public void setInfoMessageManager(InfoMessageManager infoMessageManager) { - this.infoMessageManager = infoMessageManager; - } - - /** - * [used by Spring] - * @param infoSubscriptionManager - */ - public void setInfoSubscriptionManager(InfoSubscriptionManager infoSubscriptionManager) { - this.infoSubscriptionManager = infoSubscriptionManager; - } - @Override public InfoMessage loadInfoMessage(Long key) { return infoMessageManager.loadInfoMessageByKey(key); @@ -110,6 +103,72 @@ public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManage public void saveInfoMessage(InfoMessage infoMessage) { infoMessageManager.saveInfoMessage(infoMessage); } + + @Override + public VFSLeaf getAttachment(InfoMessage msg) { + VFSLeaf attachment = null; + if(StringHelper.containsNonWhitespace(msg.getAttachmentPath())) { + VFSItem item = getStoragePath().resolve(msg.getAttachmentPath()); + if(item instanceof VFSLeaf) { + attachment = (VFSLeaf)item; + } + } + return attachment; + } + + @Override + public void deleteAttachments(Collection<String> paths) { + if(paths == null || paths.isEmpty()) return; + + VFSContainer ressourceContainer = getStoragePath(); + for(String path:paths) { + VFSItem item = ressourceContainer.resolve(path); + if(item instanceof VFSLeaf) { + ((VFSLeaf)item).delete(); + } + } + } + + @Override + public String storeAttachment(File file, String filename, OLATResourceable ores, String subPath) { + try { + File ressourceDir = getResourceDir(ores); + + String datePart; + synchronized(formater) { + datePart = formater.format(new Date()); + } + if(filename == null) { + filename = file.getName(); + } + filename = datePart + "_" + filename; + File attachment = new File(ressourceDir, filename); + Files.copy(file.toPath(), attachment.toPath(), StandardCopyOption.REPLACE_EXISTING); + + File root = getStoragePath().getBasefile(); + Path relativePath = root.toPath().relativize(attachment.toPath()); + return relativePath.toString(); + } catch (IOException e) { + log.error("", e); + return null; + } + } + + private File getResourceDir(OLATResourceable ores) { + File root = getStoragePath().getBasefile(); + String type = ores.getResourceableTypeName().toLowerCase(); + File typePath = new File(root, type); + String id = ores.getResourceableId().toString(); + File resourceFile = new File(typePath, id); + if(!resourceFile.exists()) { + resourceFile.mkdirs(); + } + return resourceFile; + } + + private OlatRootFolderImpl getStoragePath() { + return new OlatRootFolderImpl("/infomessages/", null); + } @Override public boolean sendInfoMessage(InfoMessage infoMessage, MailFormatter mailFormatter, Locale locale, Identity from, List<Identity> tos) { @@ -138,13 +197,22 @@ public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManage if(!StringHelper.containsNonWhitespace(body)) { body = infoMessage.getMessage(); } - //fxdiff VCRP-16: intern mail system + File attachment = null; + if(StringHelper.containsNonWhitespace(infoMessage.getAttachmentPath())) { + File root = getStoragePath().getBasefile(); + attachment = new File(root, infoMessage.getAttachmentPath()); + } + MailContext context = new MailContextImpl(mailFormatter.getBusinessPath()); MailBundle bundle = new MailBundle(); bundle.setContext(context); bundle.setFromId(from); bundle.setContactList(contactList); - bundle.setContent(subject, body); + if(attachment != null) { + bundle.setContent(subject, body, attachment); + } else { + bundle.setContent(subject, body); + } MailerResult result = mailManager.sendMessage(bundle); send = result.isSuccessful(); @@ -161,6 +229,9 @@ public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManage @Override public void deleteInfoMessage(InfoMessage infoMessage) { + if(StringHelper.containsNonWhitespace(infoMessage.getAttachmentPath())) { + deleteAttachments(Collections.singletonList(infoMessage.getAttachmentPath())); + } infoMessageManager.deleteInfoMessage(infoMessage); infoSubscriptionManager.markPublisherNews(infoMessage.getOLATResourceable(), infoMessage.getResSubPath()); } @@ -185,13 +256,18 @@ public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManage public void removeInfoMessagesAndSubscriptionContext(BusinessGroup group) { List<InfoMessage> messages = infoMessageManager.loadInfoMessageByResource(group, InfoMessageFrontendManager.businessGroupResSubPath, null, null, null, 0, 0); + List<String> pathToDelete = new ArrayList<>(); for (InfoMessage im : messages) { infoMessageManager.deleteInfoMessage(im); + if(StringHelper.containsNonWhitespace(im.getAttachmentPath())) { + pathToDelete.add(im.getAttachmentPath()); + } } String resName = group.getResourceableTypeName(); Long resId = group.getResourceableId(); SubscriptionContext subscriptionContext = new SubscriptionContext(resName, resId, ""); infoSubscriptionManager.deleteSubscriptionContext(subscriptionContext); + deleteAttachments(pathToDelete); } @Override diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageManagerImpl.java b/src/main/java/org/olat/commons/info/manager/InfoMessageManagerImpl.java index 8e4668e3ceca0bc99f37263645670c3653d6d1b2..6b7223164f36c2fdb0724ff5ca8944843f832f07 100644 --- a/src/main/java/org/olat/commons/info/manager/InfoMessageManagerImpl.java +++ b/src/main/java/org/olat/commons/info/manager/InfoMessageManagerImpl.java @@ -26,7 +26,8 @@ import java.util.List; import java.util.StringTokenizer; import org.olat.basesecurity.IdentityRef; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageManager; import org.olat.commons.info.model.InfoMessageImpl; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DBQuery; @@ -34,6 +35,8 @@ import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.util.StringHelper; import org.olat.group.BusinessGroupRef; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @@ -44,24 +47,11 @@ import org.olat.group.BusinessGroupRef; * Initial Date: 26 jul. 2010 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public class InfoMessageManagerImpl extends InfoMessageManager { +@Service("infoMessageManager") +public class InfoMessageManagerImpl implements InfoMessageManager { + @Autowired private DB dbInstance; - - /** - * [used by Spring] - */ - private InfoMessageManagerImpl() { - INSTANCE = this; - } - - /** - * [used by Spring] - * @param dbInstance - */ - public void setDbInstance(DB dbInstance) { - this.dbInstance = dbInstance; - } @Override public InfoMessage createInfoMessage(OLATResourceable ores, String subPath, String businessPath, Identity author) { diff --git a/src/main/java/org/olat/commons/info/manager/MailFormatter.java b/src/main/java/org/olat/commons/info/manager/MailFormatter.java index 008d76323b95e59f7b5c8aa9ba7ac0a5fb93818b..a7035a7bdf84451dc6031956000923a877e7401b 100644 --- a/src/main/java/org/olat/commons/info/manager/MailFormatter.java +++ b/src/main/java/org/olat/commons/info/manager/MailFormatter.java @@ -21,7 +21,7 @@ package org.olat.commons.info.manager; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; /** * @@ -37,6 +37,6 @@ public interface MailFormatter { public String getSubject(InfoMessage msg); public String getBody(InfoMessage msg); - //fxdiff VCRP-16: intern mail system + public String getBusinessPath(); } diff --git a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml b/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml deleted file mode 100644 index 8deb349cc00d3d959f7ce2181fd7472002f69f36..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE hibernate-mapping PUBLIC - "-//Hibernate/Hibernate Mapping DTD//EN" - "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> -<hibernate-mapping default-lazy="false"> - <class name="org.olat.commons.info.model.InfoMessageImpl" table="o_info_message"> - - <id name="key" type="long" column="info_id" unsaved-value="null"> - <generator class="enhanced-sequence"> - <param name="sequence_name">hibernate_unique_key</param> - <param name="force_table_use">true</param> - <param name="optimizer">legacy-hilo</param> - <param name="value_column">next_hi</param> - <param name="increment_size">32767</param> - <param name="initial_value">32767</param> - </generator> - </id> - - <version name="version" access="field" column="version"/> - <property name="creationDate" column="creationdate" type="timestamp" /> - <property name="modificationDate" column="modificationdate" type="timestamp" /> - - <property name="title" column="title" type="string" length="2048" not-null="false"/> - <property name="message" column="message" type="string" length="2048" not-null="false"/> - - <property name="resName" column="resname" type="string" not-null="true" length="50" index="mark_name_idx"/> - <property name="resId" column="resid" type="long" not-null="true" index="mark_id_idx" /> - <property name="resSubPath" column="ressubpath" type="string" length="2048" index="mark_subpath_idx" not-null="false"/> - <property name="businessPath" column="businesspath" type="string" length="2048" index="mark_businesspath_idx" not-null="false"/> - - <many-to-one name="author" class="org.olat.basesecurity.IdentityImpl" column="fk_author_id" outer-join="true" cascade="none" not-null="true"/> - <many-to-one name="modifier" class="org.olat.basesecurity.IdentityImpl" column="fk_modifier_id" outer-join="true" cascade="none" not-null="false"/> - </class> -</hibernate-mapping> \ No newline at end of file diff --git a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.java b/src/main/java/org/olat/commons/info/model/InfoMessageImpl.java index 67690ee93dfe986dedc59c30517380cad63bc160..42ed3313bbaeb5336dc69a4016a0d0b87c05e344 100644 --- a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.java +++ b/src/main/java/org/olat/commons/info/model/InfoMessageImpl.java @@ -36,6 +36,7 @@ import javax.persistence.TemporalType; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; import org.olat.basesecurity.IdentityImpl; +import org.olat.commons.info.InfoMessage; import org.olat.core.id.CreateInfo; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; @@ -77,6 +78,8 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable { private String title; @Column(name="message", nullable=true, insertable=true, updatable=true) private String message; + @Column(name="attachmentpath", nullable=true, insertable=true, updatable=true) + private String attachmentPath; @Column(name="resid", nullable=false, insertable=true, updatable=false) private Long resId; @@ -97,35 +100,63 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable { public InfoMessageImpl() { // } + + @Override + public Long getKey() { + return key; + } + + @Override + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate= creationDate; + } + + @Override public Date getModificationDate() { return modificationDate; } + @Override public void setModificationDate(Date modificationDate) { this.modificationDate = modificationDate; } - - public void setCreationDate(Date creationDate) { - this.creationDate= creationDate; - } + @Override public String getTitle() { return title; } + @Override public void setTitle(String title) { this.title = title; } + @Override public String getMessage() { return message; } + @Override public void setMessage(String message) { this.message = message; } + @Override + public String getAttachmentPath() { + return attachmentPath; + } + + @Override + public void setAttachmentPath(String attachmentPath) { + this.attachmentPath = attachmentPath; + } + + @Override public Long getResId() { return resId; } @@ -134,6 +165,7 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable { this.resId = resId; } + @Override public String getResName() { return resName; } @@ -142,6 +174,7 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable { this.resName = resName; } + @Override public String getResSubPath() { return resSubPath; } @@ -150,6 +183,7 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable { this.resSubPath = subPath; } + @Override public String getBusinessPath() { return businessPath; } @@ -158,6 +192,7 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable { this.businessPath = businessPath; } + @Override public Identity getAuthor() { return author; } @@ -166,14 +201,17 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable { this.author = author; } + @Override public Identity getModifier() { return modifier; } + @Override public void setModifier(Identity modifier) { this.modifier = modifier; } + @Override public OLATResourceable getOLATResourceable() { final String name = resName; final Long id = resId; @@ -210,15 +248,4 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable { public boolean equalsByPersistableKey(Persistable persistable) { return equals(persistable); } - - @Override - public Long getKey() { - return key; - } - - - @Override - public Date getCreationDate() { - return creationDate; - } } diff --git a/src/main/java/org/olat/commons/info/notification/InfoMessageNotificationHandler.java b/src/main/java/org/olat/commons/info/notification/InfoMessageNotificationHandler.java index 2c6c8baca41c00d56605cfd3cc17e201eb1f5021..4bfd1c14fc5096fb764f6d5b7dba3921068cb0d4 100644 --- a/src/main/java/org/olat/commons/info/notification/InfoMessageNotificationHandler.java +++ b/src/main/java/org/olat/commons/info/notification/InfoMessageNotificationHandler.java @@ -24,8 +24,8 @@ import java.util.Date; import java.util.List; import java.util.Locale; -import org.olat.commons.info.manager.InfoMessageManager; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.services.notifications.NotificationHelper; import org.olat.core.commons.services.notifications.NotificationsHandler; @@ -39,13 +39,16 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.BusinessControlFactory; -import org.olat.core.logging.LogDelegator; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @@ -56,10 +59,16 @@ import org.olat.repository.RepositoryManager; * Initial Date: 27 jul. 2010 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public class InfoMessageNotificationHandler extends LogDelegator implements NotificationsHandler { +@Service("org.olat.commons.info.notification.InfoMessageNotificationHandler") +public class InfoMessageNotificationHandler implements NotificationsHandler { + + private static final OLog log = Tracing.createLoggerFor(InfoMessageNotificationHandler.class); private static final String CSS_CLASS_ICON = "o_infomsg_icon"; + @Autowired + private InfoMessageManager infoMessageManager; + @Override public SubscriptionInfo createSubscriptionInfo(Subscriber subscriber, Locale locale, Date compareDate) { SubscriptionInfo si = null; @@ -96,7 +105,7 @@ public class InfoMessageNotificationHandler extends LogDelegator implements Noti si = new SubscriptionInfo(subscriber.getKey(), p.getType(), new TitleItem(title, CSS_CLASS_ICON), null); OLATResourceable ores = OresHelper.createOLATResourceableInstance(resName, resId); - List<InfoMessage> infos = InfoMessageManager.getInstance().loadInfoMessageByResource(ores, resSubPath, null, compareDate, null, 0, 0); + List<InfoMessage> infos = infoMessageManager.loadInfoMessageByResource(ores, resSubPath, null, compareDate, null, 0, 0); for(InfoMessage info:infos) { Identity ident = info.getAuthor(); String desc = translator.translate("notifications.entry", new String[] { info.getTitle(), NotificationHelper.getFormatedName(ident) }); @@ -108,7 +117,7 @@ public class InfoMessageNotificationHandler extends LogDelegator implements Noti si.addSubscriptionListItem(subListItem); } } catch (Exception e) { - logError("Unexpected exception", e); + log.error("Unexpected exception", e); si = NotificationsManager.getInstance().getNoSubscriptionInfo(); } } else { diff --git a/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManagerImpl.java b/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManagerImpl.java index 369d27aeb3b4c04b93873f15284fc9dffb0e3c5f..0e24fae845db538c1d1b02a7deab21b38912f68e 100644 --- a/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManagerImpl.java +++ b/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManagerImpl.java @@ -23,7 +23,8 @@ package org.olat.commons.info.notification; import java.util.Collections; import java.util.List; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoSubscriptionManager; import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.commons.services.notifications.Publisher; import org.olat.core.commons.services.notifications.PublisherData; @@ -33,6 +34,8 @@ import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.util.prefs.Preferences; import org.olat.core.util.resource.OresHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @@ -43,26 +46,13 @@ import org.olat.core.util.resource.OresHelper; * Initial Date: 27 jul. 2010 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public class InfoSubscriptionManagerImpl extends InfoSubscriptionManager { +@Service +public class InfoSubscriptionManagerImpl implements InfoSubscriptionManager { + + private static final String PUBLISHER_TYPE = OresHelper.calculateTypeName(InfoMessage.class); + @Autowired private NotificationsManager notificationsManager; - - private String PUBLISHER_TYPE = OresHelper.calculateTypeName(InfoMessage.class); - - /** - * [used by Spring] - */ - private InfoSubscriptionManagerImpl() { - INSTANCE = this; - } - - /** - * [user by Spring] - * @param notificationsManager - */ - public void setNotificationsManager(NotificationsManager notificationsManager) { - this.notificationsManager = notificationsManager; - } @Override public SubscriptionContext getInfoSubscriptionContext(OLATResourceable resource, String subPath) { diff --git a/src/main/java/org/olat/commons/info/notification/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/commons/info/notification/_i18n/LocalStrings_pl.properties index f64a29c268344687be7f2669f9d76707222290d9..6d3c7a0ad2a695813ebb1da5d5f1715e098ad09d 100644 --- a/src/main/java/org/olat/commons/info/notification/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/commons/info/notification/_i18n/LocalStrings_pl.properties @@ -1,2 +1,4 @@ -#Thu Sep 08 16:42:41 CEST 2011 +#Thu Jul 27 15:36:44 CEST 2017 notification.title=Powiadomienia w kursie "{0}" +notification.title.group=Powiadomienia w grupie "{0}" +notifications.entry=Wiadomo\u015B\u0107 "{0}" dodana przez {1} diff --git a/src/main/java/org/olat/commons/info/portlet/InfoMessagePortletRunController.java b/src/main/java/org/olat/commons/info/portlet/InfoMessagePortletRunController.java index 44293dc535dc9abad8dade68b7e8a82d1ca9df8d..1bfc7015b8698d05184a20e413b2c9c9ac0c14eb 100644 --- a/src/main/java/org/olat/commons/info/portlet/InfoMessagePortletRunController.java +++ b/src/main/java/org/olat/commons/info/portlet/InfoMessagePortletRunController.java @@ -28,8 +28,8 @@ import java.util.List; import java.util.Locale; import org.olat.NewControllerFactory; -import org.olat.commons.info.manager.InfoMessageFrontendManager; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.commons.services.notifications.SubscriptionInfo; import org.olat.core.commons.services.notifications.model.SubscriptionListItem; @@ -120,9 +120,9 @@ public class InfoMessagePortletRunController extends AbstractPortletRunControlle @Override protected SortingCriteria createDefaultSortingCriteria() { - SortingCriteria sortingCriteria = new SortingCriteria(sortingTermsList, getDefaultMaxEntries()); - sortingCriteria.setAscending(false); - return sortingCriteria; + SortingCriteria sortCriteria = new SortingCriteria(sortingTermsList, getDefaultMaxEntries()); + sortCriteria.setAscending(false); + return sortCriteria; } @Override diff --git a/src/main/java/org/olat/commons/info/restapi/InfoMessageVO.java b/src/main/java/org/olat/commons/info/restapi/InfoMessageVO.java index 63bb5b12c24d53a04e9486da5a77d768c4dba007..8002ab65c9d8f88ab6bb7eb0803c3741890a7776 100644 --- a/src/main/java/org/olat/commons/info/restapi/InfoMessageVO.java +++ b/src/main/java/org/olat/commons/info/restapi/InfoMessageVO.java @@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; @XmlAccessorType(XmlAccessType.FIELD) diff --git a/src/main/java/org/olat/commons/info/restapi/InfoMessageWebService.java b/src/main/java/org/olat/commons/info/restapi/InfoMessageWebService.java index 958b7a51d56c2f3946021de1f54bacffcd1f6d69..cf5907017c413a98c97565132fd674f78ca8710b 100644 --- a/src/main/java/org/olat/commons/info/restapi/InfoMessageWebService.java +++ b/src/main/java/org/olat/commons/info/restapi/InfoMessageWebService.java @@ -27,7 +27,7 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; /** * diff --git a/src/main/java/org/olat/commons/info/restapi/InfoMessagesWebService.java b/src/main/java/org/olat/commons/info/restapi/InfoMessagesWebService.java index 0fb513fc9e90eadf688649d9ea4f1dc3239c7dd3..27da63c69f2593851f8cd7dcae84de11610c057f 100644 --- a/src/main/java/org/olat/commons/info/restapi/InfoMessagesWebService.java +++ b/src/main/java/org/olat/commons/info/restapi/InfoMessagesWebService.java @@ -39,8 +39,8 @@ import javax.ws.rs.core.Response.Status; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; -import org.olat.commons.info.manager.InfoMessageFrontendManager; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.id.Identity; diff --git a/src/main/java/org/olat/commons/info/ui/CreateInfoStep.java b/src/main/java/org/olat/commons/info/ui/CreateInfoStep.java index c9eb9a331106b44a6a4de05ca3e8439d9ebf2225..02e42808380243588e621dd814ba0981c1dfe729 100644 --- a/src/main/java/org/olat/commons/info/ui/CreateInfoStep.java +++ b/src/main/java/org/olat/commons/info/ui/CreateInfoStep.java @@ -22,6 +22,7 @@ package org.olat.commons.info.ui; import java.util.List; +import org.olat.commons.info.InfoMessage; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.control.WindowControl; @@ -41,8 +42,11 @@ import org.olat.core.gui.control.generic.wizard.StepsRunContext; */ public class CreateInfoStep extends BasicStep { - public CreateInfoStep(UserRequest ureq, List<SendMailOption> options) { + private final InfoMessage message; + + public CreateInfoStep(UserRequest ureq, List<SendMailOption> options, InfoMessage message) { super(ureq); + this.message = message; setI18nTitleAndDescr("wizard.step0.title", "wizard.step0.description"); setNextStep(new SendMailStep(ureq, options)); } @@ -54,6 +58,6 @@ public class CreateInfoStep extends BasicStep { @Override public StepFormController getStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form form) { - return new CreateInfoStepController(ureq, wControl, runContext, form); + return new CreateInfoStepController(ureq, wControl, runContext, form, message); } } diff --git a/src/main/java/org/olat/commons/info/ui/CreateInfoStepController.java b/src/main/java/org/olat/commons/info/ui/CreateInfoStepController.java index ab8ffafcb685962b01b52dec4b72ec6032fd8752..cf626bf701cce990f283e45080da4eed7406a9b6 100644 --- a/src/main/java/org/olat/commons/info/ui/CreateInfoStepController.java +++ b/src/main/java/org/olat/commons/info/ui/CreateInfoStepController.java @@ -20,11 +20,13 @@ package org.olat.commons.info.ui; +import org.olat.commons.info.InfoMessage; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.impl.Form; 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.StepFormBasicController; import org.olat.core.gui.control.generic.wizard.StepsEvent; @@ -42,27 +44,26 @@ import org.olat.core.gui.control.generic.wizard.StepsRunContext; public class CreateInfoStepController extends StepFormBasicController { private final StepsRunContext runContext; - private final InfoEditFormController infoEditFormController; + private final InfoEditFormController editForm; - public CreateInfoStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form rootForm) { + public CreateInfoStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form rootForm, InfoMessage message) { super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null); this.runContext = runContext; - - infoEditFormController = new InfoEditFormController(ureq, wControl, rootForm, true); - listenTo(infoEditFormController); + editForm = new InfoEditFormController(ureq, wControl, rootForm, true, message); + listenTo(editForm); initForm(ureq); } @Override public FormItem getStepFormItem() { - return infoEditFormController.getInitialFormItem(); + return editForm.getInitialFormItem(); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - formLayout.add(infoEditFormController.getInitialFormItem()); + formLayout.add(editForm.getInitialFormItem()); } @Override @@ -70,15 +71,25 @@ public class CreateInfoStepController extends StepFormBasicController { // } + @Override + public void event(UserRequest ureq, Controller source, Event event) { + if(source == editForm) { + if(event == Event.CHANGED_EVENT) { + runContext.put(WizardConstants.PATH_TO_DELETE, editForm.getAttachmentPathToDelete()); + } + } + super.event(ureq, source, event); + } + @Override protected boolean validateFormLogic(UserRequest ureq) { - return infoEditFormController.validateFormLogic(ureq); + return editForm.validateFormLogic(ureq); } @Override protected void formOK(UserRequest ureq) { - runContext.put(WizardConstants.MSG_TITLE, infoEditFormController.getTitle()); - runContext.put(WizardConstants.MSG_MESSAGE, infoEditFormController.getMessage()); + runContext.put(WizardConstants.MSG, editForm.getInfoMessage()); + runContext.put(WizardConstants.PATH_TO_DELETE, editForm.getAttachmentPathToDelete()); fireEvent(ureq, StepsEvent.ACTIVATE_NEXT); } } diff --git a/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java b/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java index efb93bb893293c52ffa2806dd6fd2ce3b6b8344d..7b5baf0fb7173936eac77c73573314288984fd1b 100644 --- a/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java +++ b/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java @@ -22,14 +22,21 @@ package org.olat.commons.info.ui; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collection; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; -import org.olat.commons.info.manager.InfoMessageFrontendManager; +import javax.servlet.http.HttpServletRequest; + +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.commons.info.manager.MailFormatter; -import org.olat.commons.info.model.InfoMessage; -import org.olat.core.CoreSpringFactory; +import org.olat.core.commons.modules.bc.meta.MetaInfo; +import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; +import org.olat.core.dispatcher.mapper.Mapper; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.date.DateComponentFactory; import org.olat.core.gui.components.date.DateElement; @@ -38,6 +45,7 @@ import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; @@ -49,6 +57,8 @@ import org.olat.core.gui.control.generic.wizard.Step; import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; import org.olat.core.gui.control.generic.wizard.StepsMainRunController; import org.olat.core.gui.control.generic.wizard.StepsRunContext; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.gui.media.NotFoundMediaResource; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.User; @@ -62,11 +72,14 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.coordinate.LockResult; import org.olat.core.util.resource.OresHelper; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.VFSMediaResource; import org.olat.course.nodes.info.InfoCourseNodeConfiguration; import org.olat.group.BusinessGroup; import org.olat.modules.ModuleConfiguration; import org.olat.user.UserManager; import org.olat.util.logging.activity.LoggingResourceable; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -95,6 +108,9 @@ public class InfoDisplayController extends FormBasicController { private final OLATResourceable ores; private final String resSubPath; private final String businessPath; + private final String thumbnailMapper; + private final String attachmentMapper; + private Map<Long,VFSLeaf> infoKeyToAttachment; private int maxResults = 0; private int maxResultsConfig = 0; @@ -102,24 +118,26 @@ public class InfoDisplayController extends FormBasicController { private Date after = null; private Date afterConfig = null; - private final UserManager userManager; - private final InfoMessageFrontendManager infoMessageManager; + @Autowired + private UserManager userManager; + @Autowired + private InfoMessageFrontendManager infoMessageManager; private LockResult lockEntry; private MailFormatter sendMailFormatter; - private List<SendMailOption> sendMailOptions = new ArrayList<SendMailOption>(); + private List<SendMailOption> sendMailOptions = new ArrayList<>(); public InfoDisplayController(UserRequest ureq, WindowControl wControl, InfoSecurityCallback secCallback, BusinessGroup businessGroup, String resSubPath, String businessPath) { super(ureq, wControl, "display"); - userManager = CoreSpringFactory.getImpl(UserManager.class); - infoMessageManager = CoreSpringFactory.getImpl(InfoMessageFrontendManager.class); this.secCallback = secCallback; this.ores = businessGroup.getResource(); this.resSubPath = resSubPath; this.businessPath = businessPath; // default show 10 messages for groups maxResults = maxResultsConfig = 10; + thumbnailMapper = registerCacheableMapper(ureq, "InfoMessagesThumbnail", new ThumbnailMapper()); + attachmentMapper = registerCacheableMapper(ureq, "InfoMessages", new AttachmentMapper()); initForm(ureq); @@ -135,10 +153,10 @@ public class InfoDisplayController extends FormBasicController { this.resSubPath = resSubPath; this.businessPath = businessPath; - userManager = CoreSpringFactory.getImpl(UserManager.class); - infoMessageManager = CoreSpringFactory.getImpl(InfoMessageFrontendManager.class); maxResults = maxResultsConfig = getConfigValue(config, InfoCourseNodeConfiguration.CONFIG_LENGTH, 10); duration = getConfigValue(config, InfoCourseNodeConfiguration.CONFIG_DURATION, 90); + thumbnailMapper = registerCacheableMapper(ureq, "InfoMessagesThumbnail", new ThumbnailMapper()); + attachmentMapper = registerCacheableMapper(ureq, "InfoMessages", new AttachmentMapper()); if(duration > 0) { Calendar cal = Calendar.getInstance(); @@ -182,7 +200,7 @@ public class InfoDisplayController extends FormBasicController { } public List<SendMailOption> getSendMailOptions() { - return this.sendMailOptions; + return sendMailOptions; } public void addSendMailOptions(SendMailOption sendMailOption) { @@ -217,9 +235,14 @@ public class InfoDisplayController extends FormBasicController { List<InfoMessage> msgs = infoMessageManager.loadInfoMessageByResource(ores, resSubPath, businessPath, after, null, 0, maxResults); List<InfoMessageForDisplay> infoDisplays = new ArrayList<>(msgs.size()); + Map<Long,VFSLeaf> keyToDisplay = new HashMap<>(); for(InfoMessage info:msgs) { previousDisplayKeys.add(info.getKey()); - infoDisplays.add(createInfoMessageForDisplay(info)); + InfoMessageForDisplay infoDisplay = createInfoMessageForDisplay(info); + infoDisplays.add(infoDisplay); + if(infoDisplay.getAttachment() != null) { + keyToDisplay.put(info.getKey(), infoDisplay.getAttachment()); + } String dateCmpName = "info.date." + info.getKey(); DateElement dateEl = DateComponentFactory.createDateElementWithYear(dateCmpName, info.getCreationDate()); @@ -243,6 +266,7 @@ public class InfoDisplayController extends FormBasicController { } } flc.contextPut("infos", infoDisplays); + infoKeyToAttachment = keyToDisplay; int numOfInfos = infoMessageManager.countInfoMessageByResource(ores, resSubPath, businessPath, null, null); oldMsgsLink.setVisible((msgs.size() < numOfInfos)); @@ -275,9 +299,9 @@ public class InfoDisplayController extends FormBasicController { infos = translate("display.info.noauthor", new String[]{creationDate}); } else { infos = translate("display.info", new String[]{StringHelper.escapeHtml(authorName), creationDate}); - } - - return new InfoMessageForDisplay(info.getKey(), info.getTitle(), message, infos, modifier); + } + VFSLeaf attachment = infoMessageManager.getAttachment(info); + return new InfoMessageForDisplay(info.getKey(), info.getTitle(), message, attachment, infos, modifier); } @Override @@ -291,6 +315,12 @@ public class InfoDisplayController extends FormBasicController { oldMsgsLink.setElementCssClass("o_sel_course_info_old_msgs"); newMsgsLink = uifactory.addFormLink("display.new_messages", "display.new_messages", "display.new_messages", formLayout, Link.BUTTON); newMsgsLink.setElementCssClass("o_sel_course_info_new_msgs"); + + if(formLayout instanceof FormLayoutContainer) { + FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; + layoutCont.contextPut("thumbnailMapper", thumbnailMapper); + layoutCont.contextPut("attachmentMapper", attachmentMapper); + } } @Override @@ -356,7 +386,8 @@ public class InfoDisplayController extends FormBasicController { @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(source == newInfoLink) { - start = new CreateInfoStep(ureq, sendMailOptions); + InfoMessage msg = infoMessageManager.createInfoMessage(ores, resSubPath, businessPath, getIdentity()); + start = new CreateInfoStep(ureq, sendMailOptions, msg); newInfoWizard = new StepsMainRunController(ureq, getWindowControl(), start, new FinishedCallback(), new CancelCallback(), translate("create_message"), "o_sel_info_messages_create_wizard"); listenTo(newInfoWizard); @@ -380,6 +411,11 @@ public class InfoDisplayController extends FormBasicController { } } + @Override + protected void propagateDirtinessToContainer(FormItem fiSrc, FormEvent fe) { + //nothing to do + } + protected void popupDelete(UserRequest ureq, InfoMessage msg) { OLATResourceable mres = OresHelper.createOLATResourceableInstance(InfoMessage.class, msg.getKey()); lockEntry = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(mres, ureq.getIdentity(), ""); @@ -435,16 +471,13 @@ public class InfoDisplayController extends FormBasicController { @Override public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) { - String title = (String)runContext.get(WizardConstants.MSG_TITLE); - String message = (String)runContext.get(WizardConstants.MSG_MESSAGE); + InfoMessage msg = (InfoMessage)runContext.get(WizardConstants.MSG); @SuppressWarnings("unchecked") Set<String> selectedOptions = (Set<String>)runContext.get(WizardConstants.SEND_MAIL); - - InfoMessage msg = infoMessageManager.createInfoMessage(ores, resSubPath, businessPath, ureq.getIdentity()); - msg.setTitle(title); - msg.setMessage(message); - - List<Identity> identities = new ArrayList<Identity>(); + @SuppressWarnings("unchecked") + Collection<String> pathToDelete = (Set<String>)runContext.get(WizardConstants.PATH_TO_DELETE); + + List<Identity> identities = new ArrayList<>(); for(SendMailOption option:sendMailOptions) { if(selectedOptions != null && selectedOptions.contains(option.getOptionKey())) { identities.addAll(option.getSelectedIdentities()); @@ -452,6 +485,7 @@ public class InfoDisplayController extends FormBasicController { } infoMessageManager.sendInfoMessage(msg, sendMailFormatter, ureq.getLocale(), ureq.getIdentity(), identities); + infoMessageManager.deleteAttachments(pathToDelete); ThreadLocalUserActivityLogger.log(CourseLoggingAction.INFO_MESSAGE_CREATED, getClass(), LoggingResourceable.wrap(msg.getOLATResourceable(), OlatResourceableType.infoMessage)); @@ -463,7 +497,63 @@ public class InfoDisplayController extends FormBasicController { protected class CancelCallback implements StepRunnerCallback { @Override public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) { + @SuppressWarnings("unchecked") + Collection<String> pathToDelete = (Set<String>)runContext.get(WizardConstants.PATH_TO_DELETE); + infoMessageManager.deleteAttachments(pathToDelete); return Step.NOSTEP; } } + + private class AttachmentMapper implements Mapper { + @Override + public MediaResource handle(String relPath, HttpServletRequest request) { + if(infoKeyToAttachment == null) { + return new NotFoundMediaResource(relPath); + } + + String[] query = relPath.split("/"); + if(query.length > 1) { + try { + Long infoKey = Long.valueOf(Long.parseLong(query[1])); + VFSLeaf attachment = infoKeyToAttachment.get(infoKey); + return new VFSMediaResource(attachment); + } catch (NumberFormatException e) { + //ignore them + } + } + return new NotFoundMediaResource(relPath); + } + } + + private class ThumbnailMapper implements Mapper { + @Override + public MediaResource handle(String relPath, HttpServletRequest request) { + if(infoKeyToAttachment == null) { + return new NotFoundMediaResource(relPath); + } + + String[] query = relPath.split("/"); + if(query.length > 2) { + try { + Long infoKey = Long.valueOf(Long.parseLong(query[1])); + VFSLeaf attachment = infoKeyToAttachment.get(infoKey); + if(attachment != null) { + MetaInfo meta = ((MetaTagged)attachment).getMetaInfo(); + if (meta.getUUID().equals(query[2])) { + if (meta.isThumbnailAvailable()) { + VFSLeaf thumb = meta.getThumbnail(200, 200, false); + if(thumb != null) { + // Positive lookup, send as response + return new VFSMediaResource(thumb); + } + } + } + } + } catch (NumberFormatException e) { + //ignore them + } + } + return new NotFoundMediaResource(relPath); + } + } } diff --git a/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java b/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java index 59872431cbbbeb2815cc85020b2a30c188db1d12..7df8af9f57cb5a5ecd33ae78faaf4b502f15ae77 100644 --- a/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java +++ b/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java @@ -20,7 +20,7 @@ package org.olat.commons.info.ui; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; import org.olat.core.gui.translator.Translator; import org.olat.core.id.User; import org.olat.core.id.UserConstants; diff --git a/src/main/java/org/olat/commons/info/ui/InfoEditController.java b/src/main/java/org/olat/commons/info/ui/InfoEditController.java index b98ef00262bebaa7f4a6597e74ab97fd0a8ad8ab..bdc3164787e4c0f50ea5472562ff9d786ff992b8 100644 --- a/src/main/java/org/olat/commons/info/ui/InfoEditController.java +++ b/src/main/java/org/olat/commons/info/ui/InfoEditController.java @@ -20,11 +20,11 @@ package org.olat.commons.info.ui; +import java.util.Collection; import java.util.Date; -import org.olat.commons.info.manager.InfoMessageFrontendManager; -import org.olat.commons.info.model.InfoMessage; -import org.olat.core.CoreSpringFactory; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; @@ -36,11 +36,9 @@ import org.olat.core.logging.activity.CourseLoggingAction; import org.olat.core.logging.activity.OlatResourceableType; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.util.logging.activity.LoggingResourceable; +import org.springframework.beans.factory.annotation.Autowired; /** - * - * Description:<br> - * TODO: srosse Class Description for InfoEditController * * <P> * Initial Date: 24 aug. 2010 <br> @@ -48,33 +46,29 @@ import org.olat.util.logging.activity.LoggingResourceable; */ public class InfoEditController extends FormBasicController { - private final InfoMessage messageToEdit; + private InfoMessage messageToEdit; private final InfoEditFormController editForm; - private final InfoMessageFrontendManager infoFrontendManager; + + @Autowired + private InfoMessageFrontendManager infoFrontendManager; public InfoEditController(UserRequest ureq, WindowControl wControl, InfoMessage messageToEdit) { super(ureq, wControl, "edit"); - this.messageToEdit = messageToEdit; - infoFrontendManager = CoreSpringFactory.getImpl(InfoMessageFrontendManager.class); - editForm = new InfoEditFormController(ureq, wControl, mainForm, false); - editForm.setTitle(messageToEdit.getTitle()); - editForm.setMessage(messageToEdit.getMessage()); + editForm = new InfoEditFormController(ureq, wControl, mainForm, false, messageToEdit); listenTo(editForm); - initForm(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { FormLayoutContainer editCont = editForm.getInitialFormItem(); + flc.add("edit", editCont); final FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator()); editCont.add(buttonLayout); uifactory.addFormSubmitButton("submit", buttonLayout); uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl()); - - flc.add("edit", editCont); } @Override @@ -89,14 +83,13 @@ public class InfoEditController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { - String title = editForm.getTitle(); - String message = editForm.getMessage(); - - messageToEdit.setTitle(title); - messageToEdit.setMessage(message); + messageToEdit = editForm.getInfoMessage(); messageToEdit.setModificationDate(new Date()); messageToEdit.setModifier(getIdentity()); - infoFrontendManager.sendInfoMessage(messageToEdit, null, null, ureq.getIdentity(), null); + infoFrontendManager.sendInfoMessage(messageToEdit, null, null, getIdentity(), null); + + Collection<String> pathToDelete = editForm.getAttachmentPathToDelete(); + infoFrontendManager.deleteAttachments(pathToDelete); ThreadLocalUserActivityLogger.log(CourseLoggingAction.INFO_MESSAGE_UPDATED, getClass(), LoggingResourceable.wrap(messageToEdit.getOLATResourceable(), OlatResourceableType.infoMessage)); diff --git a/src/main/java/org/olat/commons/info/ui/InfoEditFormController.java b/src/main/java/org/olat/commons/info/ui/InfoEditFormController.java index fbddbb7bc80014255935a8e70839ecf5b4b59359..6af879aa265933b793378d002dbb532a94d95306 100644 --- a/src/main/java/org/olat/commons/info/ui/InfoEditFormController.java +++ b/src/main/java/org/olat/commons/info/ui/InfoEditFormController.java @@ -20,16 +20,31 @@ package org.olat.commons.info.ui; +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; 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.ValidationStatus; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -41,13 +56,23 @@ import org.olat.core.util.StringHelper; */ public class InfoEditFormController extends FormBasicController { - private TextElement title; - private RichTextElement message; + private TextElement titleEl; + private FileElement attachmentEl; + private RichTextElement messageEl; + + private String attachmentPath; + private Set<String> attachmentPathToDelete = new HashSet<>(); + private final boolean showTitle; + private final InfoMessage infoMessage; + + @Autowired + private InfoMessageFrontendManager infoMessageFrontendManager; - public InfoEditFormController(UserRequest ureq, WindowControl wControl, Form mainForm, boolean showTitle) { + public InfoEditFormController(UserRequest ureq, WindowControl wControl, Form mainForm, boolean showTitle, InfoMessage infoMessage) { super(ureq, wControl, LAYOUT_DEFAULT, null, mainForm); this.showTitle = showTitle; + this.infoMessage = infoMessage; initForm(ureq); } @@ -58,16 +83,28 @@ public class InfoEditFormController extends FormBasicController { setFormTitle("edit.title"); } - title = uifactory.addTextElement("info_title", "edit.info_title", 512, "", formLayout); - title.setElementCssClass("o_sel_info_title"); - title.setMandatory(true); - - message = uifactory.addRichTextElementForStringDataMinimalistic("edit.info_message", "edit.info_message", "", 6, 80, + String title = infoMessage.getTitle(); + titleEl = uifactory.addTextElement("info_title", "edit.info_title", 512, title, formLayout); + titleEl.setElementCssClass("o_sel_info_title"); + titleEl.setMandatory(true); + + String message = infoMessage.getMessage(); + messageEl = uifactory.addRichTextElementForStringDataMinimalistic("edit.info_message", "edit.info_message", message, 18, 80, formLayout, getWindowControl()); - message.getEditorConfiguration().setRelativeUrls(false); - message.getEditorConfiguration().setRemoveScriptHost(false); - message.setMandatory(true); - message.setMaxLength(2000); + messageEl.getEditorConfiguration().setRelativeUrls(false); + messageEl.getEditorConfiguration().setRemoveScriptHost(false); + messageEl.getEditorConfiguration().enableCharCount(); + messageEl.setMandatory(true); + messageEl.setMaxLength(2000); + + attachmentEl = uifactory.addFileElement(getWindowControl(), "attachment", formLayout); + attachmentEl.setDeleteEnabled(true); + attachmentEl.setMaxUploadSizeKB(5000, "attachment.max.size", new String[] { "5000" }); + attachmentEl.addActionListener(FormEvent.ONCHANGE); + if(infoMessage.getAttachmentPath() != null) { + attachmentPath = infoMessage.getAttachmentPath(); + attachmentPathToDelete.add(infoMessage.getAttachmentPath()); + } } @Override @@ -75,54 +112,76 @@ public class InfoEditFormController extends FormBasicController { // } - public String getTitle() { - return title.getValue(); - } - - public void setTitle(String titleStr) { - title.setValue(titleStr); - } - - public String getMessage() { - return message.getValue(); - } - - public void setMessage(String messageStr) { - message.setValue(messageStr); - } - @Override protected void formOK(UserRequest ureq) { // } + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(attachmentEl == source) { + if (attachmentEl.isUploadSuccess()) { + File uploadedFile = attachmentEl.getUploadFile(); + String uploadedFilename = attachmentEl.getUploadFileName(); + if(attachmentPath != null) { + attachmentPathToDelete.add(attachmentPath); + } + attachmentPath = infoMessageFrontendManager.storeAttachment(uploadedFile, uploadedFilename, infoMessage.getOLATResourceable(), infoMessage.getResSubPath()); + } else { + attachmentPathToDelete.add(attachmentPath); + } + this.fireEvent(ureq, Event.CHANGED_EVENT); + } + super.formInnerEvent(ureq, source, event); + } + @Override protected boolean validateFormLogic(UserRequest ureq) { - title.clearError(); - message.clearError(); + titleEl.clearError(); + messageEl.clearError(); boolean allOk = true; - String t = title.getValue(); + String t = titleEl.getValue(); if(!StringHelper.containsNonWhitespace(t)) { - title.setErrorKey("form.legende.mandatory", new String[] {}); + titleEl.setErrorKey("form.legende.mandatory", new String[] {}); allOk = false; } else if (t.length() > 500) { - title.setErrorKey("input.toolong", new String[] {"500", Integer.toString(t.length())}); + titleEl.setErrorKey("input.toolong", new String[] {"500", Integer.toString(t.length())}); allOk = false; } - String m = message.getValue(); + String m = messageEl.getValue(); if(!StringHelper.containsNonWhitespace(m)) { - message.setErrorKey("form.legende.mandatory", new String[] {}); + messageEl.setErrorKey("form.legende.mandatory", new String[] {}); allOk = false; } else if (m.length() > 2000) { - message.setErrorKey("input.toolong", new String[] {"2000", Integer.toString(m.length())}); + messageEl.setErrorKey("input.toolong", new String[] {"2000", Integer.toString(m.length())}); allOk = false; } - return allOk && super.validateFormLogic(ureq); + List<ValidationStatus> validation = new ArrayList<>(); + attachmentEl.validate(validation); + if(validation.size() > 0) { + allOk &= false; + } + return allOk & super.validateFormLogic(ureq); + } + + public InfoMessage getInfoMessage() { + infoMessage.setTitle(titleEl.getValue()); + infoMessage.setMessage(messageEl.getValue()); + infoMessage.setAttachmentPath(attachmentPath); + return infoMessage; + } + + public Collection<String> getAttachmentPathToDelete() { + if(attachmentPath != null) { + attachmentPathToDelete.remove(attachmentPath); + } + return attachmentPathToDelete; } + @Override public FormLayoutContainer getInitialFormItem() { return flc; } diff --git a/src/main/java/org/olat/commons/info/ui/InfoMessageForDisplay.java b/src/main/java/org/olat/commons/info/ui/InfoMessageForDisplay.java index 1aa3d4f550ea1e72af9be2c9710238c045d12157..bcf541804c0c2eabbac6b4a90e6b70a8f1643492 100644 --- a/src/main/java/org/olat/commons/info/ui/InfoMessageForDisplay.java +++ b/src/main/java/org/olat/commons/info/ui/InfoMessageForDisplay.java @@ -21,6 +21,7 @@ package org.olat.commons.info.ui; import org.olat.core.util.StringHelper; +import org.olat.core.util.vfs.VFSLeaf; /** * @@ -38,13 +39,15 @@ public class InfoMessageForDisplay { private final String message; private final String infos; private final String modifier; + private final VFSLeaf attachment; - public InfoMessageForDisplay(Long key, String title, String message, String infos, String modifier) { + public InfoMessageForDisplay(Long key, String title, String message, VFSLeaf attachment, String infos, String modifier) { this.key = key; this.title = title; this.infos = infos; this.message = message; this.modifier = modifier; + this.attachment = attachment; } public Long getKey() { @@ -62,6 +65,10 @@ public class InfoMessageForDisplay { public String getInfos() { return infos; } + + public VFSLeaf getAttachment() { + return attachment; + } public boolean isModified() { return StringHelper.containsNonWhitespace(modifier); diff --git a/src/main/java/org/olat/commons/info/ui/InfoSecurityCallback.java b/src/main/java/org/olat/commons/info/ui/InfoSecurityCallback.java index 562bed7e944b662618d4aa5557c757c60db2ce52..60d725499329bb2ec456b4210320f18332ad8bb9 100644 --- a/src/main/java/org/olat/commons/info/ui/InfoSecurityCallback.java +++ b/src/main/java/org/olat/commons/info/ui/InfoSecurityCallback.java @@ -20,7 +20,7 @@ package org.olat.commons.info.ui; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; /** * diff --git a/src/main/java/org/olat/commons/info/ui/SendInfoMailFormatter.java b/src/main/java/org/olat/commons/info/ui/SendInfoMailFormatter.java index edff133c6db5e5b50c675f49f07eb65ae914c1b2..b4fd472a2b01eea9d42f939fd685f85842fd2ce9 100644 --- a/src/main/java/org/olat/commons/info/ui/SendInfoMailFormatter.java +++ b/src/main/java/org/olat/commons/info/ui/SendInfoMailFormatter.java @@ -24,8 +24,8 @@ package org.olat.commons.info.ui; import java.text.DateFormat; import java.util.List; +import org.olat.commons.info.InfoMessage; import org.olat.commons.info.manager.MailFormatter; -import org.olat.commons.info.model.InfoMessage; import org.olat.core.gui.translator.Translator; import org.olat.core.helpers.Settings; import org.olat.core.id.UserConstants; diff --git a/src/main/java/org/olat/commons/info/ui/SendMailOption.java b/src/main/java/org/olat/commons/info/ui/SendMailOption.java index 4554d99b074b149500fb91ea32b5800beab6a556..c919d6f93fa7d5103eb74ac57e9f803af03390e4 100644 --- a/src/main/java/org/olat/commons/info/ui/SendMailOption.java +++ b/src/main/java/org/olat/commons/info/ui/SendMailOption.java @@ -21,7 +21,6 @@ package org.olat.commons.info.ui; import java.util.List; -import java.util.Locale; import org.olat.core.id.Identity; @@ -37,7 +36,7 @@ public interface SendMailOption { public String getOptionKey(); - public String getOptionTranslatedName(Locale locale); + public String getOptionName(); public List<Identity> getSelectedIdentities(); diff --git a/src/main/java/org/olat/commons/info/ui/SendMailStepController.java b/src/main/java/org/olat/commons/info/ui/SendMailStepController.java index d503830da8df3aff630921177b564b9e904c295b..628d80e39e455574d64518a07a00d2e498ae62ea 100644 --- a/src/main/java/org/olat/commons/info/ui/SendMailStepController.java +++ b/src/main/java/org/olat/commons/info/ui/SendMailStepController.java @@ -57,7 +57,7 @@ public class SendMailStepController extends StepFormBasicController { int count = 0; for(SendMailOption option:options) { sendOptionKeys[count] = option.getOptionKey(); - sendOptionValues[count++] = option.getOptionTranslatedName(ureq.getLocale()); + sendOptionValues[count++] = option.getOptionName(); } initForm(ureq); diff --git a/src/main/java/org/olat/commons/info/ui/SendSubscriberMailOption.java b/src/main/java/org/olat/commons/info/ui/SendSubscriberMailOption.java index 2d568e7c6a5d4a1687a9bafaed93dbf77beacd27..927c1bdd0f8e0d8f08c0c75de0f40a138f664717 100644 --- a/src/main/java/org/olat/commons/info/ui/SendSubscriberMailOption.java +++ b/src/main/java/org/olat/commons/info/ui/SendSubscriberMailOption.java @@ -23,8 +23,8 @@ package org.olat.commons.info.ui; import java.util.List; import java.util.Locale; -import org.olat.commons.info.manager.InfoMessageFrontendManager; -import org.olat.core.gui.translator.Translator; +import org.olat.commons.info.InfoMessageFrontendManager; +import org.olat.core.CoreSpringFactory; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.util.Util; @@ -40,14 +40,15 @@ import org.olat.core.util.Util; */ public class SendSubscriberMailOption implements SendMailOption { - private final OLATResourceable ores; + private final String label; private final String resSubPath; - private final InfoMessageFrontendManager messageManager; + private final OLATResourceable ores; - public SendSubscriberMailOption(OLATResourceable ores, String resSubPath, InfoMessageFrontendManager messageManager) { + public SendSubscriberMailOption(OLATResourceable ores, String resSubPath, Locale locale) { this.ores = ores; this.resSubPath = resSubPath; - this.messageManager = messageManager; + label = Util.createPackageTranslator(SendSubscriberMailOption.class, locale) + .translate("wizard.step1.send_option.subscriber"); } @Override @@ -56,14 +57,12 @@ public class SendSubscriberMailOption implements SendMailOption { } @Override - public String getOptionTranslatedName(Locale locale) { - Translator translator = Util.createPackageTranslator(SendSubscriberMailOption.class, locale); - return translator.translate("wizard.step1.send_option.subscriber"); + public String getOptionName() { + return label; } @Override public List<Identity> getSelectedIdentities() { - List<Identity> identities = messageManager.getInfoSubscribers(ores, resSubPath); - return identities; + return CoreSpringFactory.getImpl(InfoMessageFrontendManager.class).getInfoSubscribers(ores, resSubPath); } } diff --git a/src/main/java/org/olat/commons/info/ui/WizardConstants.java b/src/main/java/org/olat/commons/info/ui/WizardConstants.java index b0a030737781a67a252ffdebdc39dfb15bc6df56..31843c5b509697c7377dcee82e6bf43b01e3675a 100644 --- a/src/main/java/org/olat/commons/info/ui/WizardConstants.java +++ b/src/main/java/org/olat/commons/info/ui/WizardConstants.java @@ -21,9 +21,7 @@ package org.olat.commons.info.ui; /** - * - * Description:<br> - * TODO: srosse Class Description for WizardConstants + * * <P> * Initial Date: 28 jul. 2010 <br> @@ -32,11 +30,9 @@ package org.olat.commons.info.ui; public class WizardConstants { public static final String SEND_MAIL = "send"; - public static final String SEND_MAIL_ALL = "all"; - public static final String SEND_MAIL_GROUPS = "groups"; public static final String SEND_MAIL_SUBSCRIBERS = "subscribers"; - public static final String MSG_TITLE = "title"; - public static final String MSG_MESSAGE = "message"; + public static final String MSG = "message"; + public static final String PATH_TO_DELETE = "pathToDelete"; } diff --git a/src/main/java/org/olat/commons/info/ui/_content/display.html b/src/main/java/org/olat/commons/info/ui/_content/display.html index 07f554e7046853ee365991164b6b56e8131211fa..630a35bf982eb0d5a0f57739da41793280b46a72 100644 --- a/src/main/java/org/olat/commons/info/ui/_content/display.html +++ b/src/main/java/org/olat/commons/info/ui/_content/display.html @@ -34,6 +34,24 @@ </div> #if($info.getMessage()) <div class="o_content">$info.getMessage()</div> + #end + + #if($r.isNotEmpty($info.attachment)) + <div class="o_attachment"> + #set($attachment = $info.attachment) + #set($fname = $attachment.name) + <a href="${attachmentMapper}/$info.key/$fname" target="_blank"> + <div class="o_filename">$r.escapeHtml($fname)</div> + <div class="o_size"> + <i class="o_icon o_icon-fw $r.getFiletypeIconCss($fname)"></i> + $r.formatBytes($attachment.getSize()) + </div> + #if ($attachment.getMetaInfo() && $attachment.getMetaInfo().isThumbnailAvailable()) + <img src="${thumbnailMapper}/$info.key/$attachment.getMetaInfo().getUUID()/$fname" class="img-thumbnail" alt="$r.escapeHtml("$fname")" title="$r.escapeHtml("$fname")"/> + <i class="o_icon o_icon-lg o_icon_enlarge"> </i> + #end + </a> + </div> #end #if($r.available("info.delete.${info.getKey()}") or $r.available("info.edit.${info.getKey()}")) <div class="o_button_group"> diff --git a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_de.properties index e2bdfad10a7129d6c2b87a38aaa836c2aa28d55d..0736846e8d5b9992cd833babbca2f6769ddf4489 100644 --- a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_de.properties @@ -1,6 +1,8 @@ #Mon Mar 02 09:54:04 CET 2009 already.deleted=Diese Mitteilung wurde inzwischen durch einen anderen Benutzer gel\u00F6scht. already.edited=Diese Mitteilung wird zurzeit von Benutzer {0} bearbeitet. Versuchen Sie es sp\u00E4ter noch einmal. +attachment=Datei +attachment.max.size=$org.olat.commons.file.filechooser\:error.limit.exceeded new_message=Neue Mitteilung erstellen create_message=Mitteilung erstellen input.toolong=Leider ist Ihr gerade eingegebener Text mit {1} Zeichen zu lang. Bitte beschr\u00E4nken Sie sich auf maximal {0} Zeichen. diff --git a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_en.properties index 59c8bee1e71063c38ae7f6f74d0452dbe904c6aa..f043d1488b2981551e90b75d38ba57493285bfa1 100644 --- a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_en.properties @@ -1,6 +1,8 @@ #Wed Jan 05 12:37:20 CET 2011 already.deleted=This message has been deleted in the meantime by another user. already.edited=This message is being edited by user {0}. Please try again later. +attachment=File +attachment.max.size=$org.olat.commons.file.filechooser\:error.limit.exceeded create_message=Create message display.info=Published by {0} on {1} display.info.noauthor=Published on {0} diff --git a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_fr.properties index 95cac8ebadee20cedf0c8670b23f253771bca069..f808e680a5c5cff6a43c430bb4e43952add8d380 100644 --- a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_fr.properties @@ -1,6 +1,8 @@ -#Tue Apr 04 18:37:01 CEST 2017 +#Tue Aug 15 17:21:05 CEST 2017 already.deleted=Entretemps, cette communication a \u00E9t\u00E9 effac\u00E9 par un autre utilisateur. already.edited=Cette communication est actuellement en cours d'\u00E9laboration par l'utilisateur {0}. R\u00E9essayez plus tard, svp. +attachment=Fichier +attachment.max.size=$org.olat.commons.file.filechooser\:error.limit.exceeded create_message=Cr\u00E9er communication display.info=Publi\u00E9 par {0} le {1} display.info.noauthor=Publi\u00E9 le {0} diff --git a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_pl.properties index da623703bf5ef965b4d85a1272eed44c9e9dc9f8..2e3ea2743282cb36886d784bba62ba40aa97f34a 100644 --- a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_pl.properties @@ -1,8 +1,9 @@ -#Thu Sep 08 16:42:41 CEST 2011 +#Thu Jul 27 15:37:34 CEST 2017 already.deleted=Inny u\u017Cytkownik usun\u0105\u0142 t\u0119 wiadomo\u015B\u0107 w mi\u0119dzyczasie. already.edited=Ta wiadomo\u015B\u0107 jest obecnie edytowana przez u\u017Cytkownika {0}. Spr\u00F3buj ponownie p\u00F3\u017Aniej. create_message=Utw\u00F3rz wiadomo\u015B\u0107 display.info=Opublikowane przez {0} w {1} +display.info.noauthor=Opublikowano {0} display.modifier=zmodyfikowane przez {0} w {1} display.new_messages=Poka\u017C nowe wiadomo\u015Bci display.no_messages=Brak nowych wiadomo\u015Bci diff --git a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_pt_BR.properties index 3a8f81b8c139c7cd2d1e61b19b3e1155b27cdb29..988b0e12ac09aeb08a610283434d790c0db090bb 100644 --- a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,6 +1,8 @@ -#Tue May 02 23:14:33 CEST 2017 +#Tue Sep 05 19:08:40 CEST 2017 already.deleted=Esta mensagem foi apagada por outro usu\u00E1rio neste meio tempo. already.edited=Esta mensagem esta sendo editada pelo usu\u00E1rio {0}. Tente mais tarde. +attachment=Arquivo +attachment.max.size=$org.olat.commons.file.filechooser\:error.limit.exceeded create_message=Criar mensagem display.info=Publicada por {0} em {1} display.info.noauthor=Publicado em {0} diff --git a/src/main/java/org/olat/commons/memberlist/manager/MembersExportManager.java b/src/main/java/org/olat/commons/memberlist/manager/MembersExportManager.java index d33b004e60fbb2585ff7785e3cec2437cff90338..efb5025e93faa5ef3b516ee5fdf561fafc0f6132 100644 --- a/src/main/java/org/olat/commons/memberlist/manager/MembersExportManager.java +++ b/src/main/java/org/olat/commons/memberlist/manager/MembersExportManager.java @@ -25,12 +25,12 @@ import java.util.List; import java.util.Map; import org.olat.basesecurity.BaseSecurity; +import org.olat.commons.memberlist.ui.MembersTableController; import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.util.Util; import org.olat.course.nodes.members.Member; -import org.olat.course.nodes.members.MembersCourseNodeRunController; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupMembership; import org.olat.group.BusinessGroupService; @@ -51,7 +51,7 @@ import org.springframework.stereotype.Service; @Service public class MembersExportManager { - public static final String USER_PROPS_ID = MembersCourseNodeRunController.class.getName(); + public static final String USER_PROPS_ID = MembersTableController.class.getName(); public static final int USER_PROPS_OFFSET = 500; diff --git a/src/main/java/org/olat/commons/memberlist/ui/MembersDisplayRunController.java b/src/main/java/org/olat/commons/memberlist/ui/MembersDisplayRunController.java index 492f3b67eb7122c5d824a226a08ebcaeb6a6ee61..bb2759ff1bfbdd4d907785bc5ec84738b52faae3 100644 --- a/src/main/java/org/olat/commons/memberlist/ui/MembersDisplayRunController.java +++ b/src/main/java/org/olat/commons/memberlist/ui/MembersDisplayRunController.java @@ -33,7 +33,6 @@ import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.util.prefs.Preferences; -import org.olat.course.nodes.members.MembersCourseNodeRunController; import org.olat.course.run.environment.CourseEnvironment; import org.olat.group.BusinessGroup; @@ -44,7 +43,7 @@ import org.olat.group.BusinessGroup; public class MembersDisplayRunController extends BasicController { // User property context ID's used in all the child controllers defined here static final String USER_PROPS_LIST_ID = MembersTableController.class.getName(); - static final String USER_PROPS_PRINT_ID = MembersCourseNodeRunController.class.getName(); //MembersPrintController.class.getName(); //MembersCourseNodeRunController + static final String USER_PROPS_PRINT_ID = MembersPrintController.class.getName(); static final String USER_PROPS_AVATAR_ID = MembersAvatarDisplayRunController.class.getName(); private static final String GUIPREF_KEY_GROUPMEMBER = "groupmemberdisplay"; diff --git a/src/main/java/org/olat/commons/memberlist/ui/MembersPrintController.java b/src/main/java/org/olat/commons/memberlist/ui/MembersPrintController.java index 1853ab223d35ee46333a79973b41a38dd366fb53..32813d6dbec78a0f6e4b70d183646667ab37c79a 100644 --- a/src/main/java/org/olat/commons/memberlist/ui/MembersPrintController.java +++ b/src/main/java/org/olat/commons/memberlist/ui/MembersPrintController.java @@ -137,7 +137,6 @@ public class MembersPrintController extends BasicController { private class UserAvatarHQMapper implements Mapper { @Override public MediaResource handle(String relPath, HttpServletRequest request) { - MediaResource rsrc = null; if(relPath != null) { if(relPath.startsWith("/")) { relPath = relPath.substring(1, relPath.length()); @@ -154,13 +153,12 @@ public class MembersPrintController extends BasicController { portrait = meta.getThumbnail(300, 300, false); } - if(portrait == null) { - return new NotFoundMediaResource(relPath); + if(portrait != null) { + return new VFSMediaResource(portrait); } - return new VFSMediaResource(portrait); } } - return rsrc; + return new NotFoundMediaResource(relPath); } } } diff --git a/src/main/java/org/olat/commons/memberlist/ui/_content/memberList.html b/src/main/java/org/olat/commons/memberlist/ui/_content/memberList.html index 1e65e4c6353cfa508890759236c2a7eb7fc7a298..172692456820965ca21debae47e68758d495a3e0 100644 --- a/src/main/java/org/olat/commons/memberlist/ui/_content/memberList.html +++ b/src/main/java/org/olat/commons/memberlist/ui/_content/memberList.html @@ -3,7 +3,7 @@ <div class="clearfix"> <div class="o_portrait"> #if($member.isPortraitAvailable()) - <img src="$r.staticLink("images/transparent.gif")" class="$member.getPortraitCssClass()" style="background-image: url('$avatarBaseURL/$member.getKey()/portrait.jpg')" alt="$r.escapeHtml("$member.getFullName()")" /> + <img src="$r.staticLink("images/transparent.gif")" class="$member.getPortraitCssClass()" style="background-image: url('$avatarBaseURL/${member.getKey()}/portrait.jpg')" alt="$r.escapeHtml("$member.getFullName()")" /> #else <img src="$r.staticLink("images/transparent.gif")" class="$member.getPortraitCssClass()" alt="$r.escapeHtml("$member.getFullName()")" /> #end diff --git a/src/main/java/org/olat/commons/memberlist/ui/_content/print.html b/src/main/java/org/olat/commons/memberlist/ui/_content/print.html index 016919128017bb94214e2a67250a781af830dc2e..6b3bd1d97a8059c5583cd3e3de0adf21424a6beb 100644 --- a/src/main/java/org/olat/commons/memberlist/ui/_content/print.html +++ b/src/main/java/org/olat/commons/memberlist/ui/_content/print.html @@ -30,14 +30,16 @@ } else { jQuery("#o_print_brand").empty(); } - + jQuery(".o_cmembers_print .o_portrait img").each(function(index, el) { //workaround caching of images var imgEl = jQuery(el).get(0); - if(imgEl.height > 2) { + //28x30 is the default size of images by IE + if(imgEl.width >= 100 && imgEl.height > 2 && imgEl.height < 100 && imgEl.height != 30 && imgEl.width != 28) { var margin = 100 - imgEl.height; jQuery(el).css("margin-top", (margin / 2) + "px"); } + jQuery(el).load(function() { var imgEl = jQuery(el).get(0); var margin = 100 - imgEl.height; @@ -46,7 +48,10 @@ } }); }); + + setTimeout(function() { + window.print(); + }, 300) }) - window.print(); /* ]]> */ </script> \ No newline at end of file diff --git a/src/main/java/org/olat/commons/memberlist/ui/_content/printList.html b/src/main/java/org/olat/commons/memberlist/ui/_content/printList.html index 9a2b6f516b29e005b6c7dfdb651fdbe91aae82f3..51669dfca48da6240a8925ce0dc6ec9e9ce2e633 100644 --- a/src/main/java/org/olat/commons/memberlist/ui/_content/printList.html +++ b/src/main/java/org/olat/commons/memberlist/ui/_content/printList.html @@ -5,7 +5,7 @@ <div class="clearfix"> <div class="o_portrait"> #if(${member.isPortraitAvailable()}) - <img src="$avatarBaseURL/$member.getKey()/portrait.jpg"> + <img src="$avatarBaseURL/${member.getKey()}/portrait_hq_${member.getKey()}.jpg"> #elseif(${member.getGender().equals("female")}) <img src='$r.staticLink("themes/light/images/portrait/dummy_female_big.png")'> #elseif(${member.getGender().equals("male")}) diff --git a/src/main/java/org/olat/commons/memberlist/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/commons/memberlist/ui/_i18n/LocalStrings_pl.properties index 1943f12213f7ba925f55b6721abc8c694cab4d4e..0509c331dcbf6f4085109581a3fbcc358b6868db 100644 --- a/src/main/java/org/olat/commons/memberlist/ui/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/commons/memberlist/ui/_i18n/LocalStrings_pl.properties @@ -1,5 +1,5 @@ -#Wed Jan 15 13:44:33 CET 2014 +#Thu Jul 27 15:38:29 CEST 2017 +nomembers=Brak cz\u0142onk\u00F3w table.header.firstTime=Rejestracja table.header.lastTime=Ostatnia wizyta table.header.online=$org.olat.group.ui.main\:table.header.online -nomembers=No members diff --git a/src/main/java/org/olat/core/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/_i18n/LocalStrings_de.properties index 87fb368e431e68af3cbe3275d5eee89dd697fc0d..cf55a456f8e40fcd6ede1888a0053aea7f246cc3 100644 --- a/src/main/java/org/olat/core/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/_i18n/LocalStrings_de.properties @@ -22,6 +22,12 @@ finish=Fertigstellen form.checkall=Alle ausw\u00E4hlen form.date.datevalid=Das Datum muss g\u00FCltig sein. form.dirty=Achtung! Sie haben noch ungespeicherte Formulardaten. Wenn Sie OK dr\u00FCcken verlassen Sie das Formular ohne zu speichern. Die enthaltenen \u00C4nderungen gehen damit verloren. +form.dirty.title=Ungespeicherte Formulardaten +form.dirty.button.back=Zurück zum Formular +form.dirty.button.ignore=Daten nicht speichern +form.dirty.intro=Achtung! Sie haben noch ungespeicherte Formulardaten +form.dirty.ignore=Wenn Sie die Schaltfläche <strong>$:form.dirty.button.ignore</strong> dr\u00FCcken verlassen Sie das Formular ohne zu speichern. <strong>Die enthaltenen \u00C4nderungen gehen damit verloren</strong>. +form.dirty.back=Wenn Sie die Schaltfläche <strong>$:form.dirty.button.back</strong> dr\u00FCcken gelangen Sie zurück zum Formular und können dieses abspeichern. form.error.nointeger=Ung\u00FCltige Zahl. Es muss eine Zahl eingegeben werden. form.general.error=Es sind Eingabefehler aufgetreten. Bitte beachten Sie den Hinweis bei den Eingabefeldern. form.legende.mandatory=<i>Bitte füllen Sie dieses Feld aus</i>. diff --git a/src/main/java/org/olat/core/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/_i18n/LocalStrings_en.properties index d6ee7d250d4f231a1d24ca2c80e809545d8c3cba..d3b14185c31d276101bdaaad6600be67d3b947fb 100644 --- a/src/main/java/org/olat/core/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/_i18n/LocalStrings_en.properties @@ -23,6 +23,12 @@ finish=Finish form.checkall=Select all form.date.datevalid=Date must be valid form.dirty=Attention\! You have not saved this form yet. By clicking OK your modifications will be lost. +form.dirty.title=Unsaved form data +form.dirty.button.back=Back to form +form.dirty.button.ignore=Do not save data +form.dirty.intro=Attention! You have not saved this form yet. +form.dirty.ignore=By clicking <strong>$:form.dirty.button.ignore</strong> you will exit the form without saving. <strong>Changes you made on this page will be lost</strong> +form.dirty.back=By clicking <strong>$:form.dirty.button.back</strong> you will get back to the form where you can save it. form.error.nointeger=Illegal number. Please enter an integer. form.general.error=There are typing errors. Please consider the information next to the input fields. form.legende.mandatory=<i>Please fill in this field.</i> diff --git a/src/main/java/org/olat/core/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/_i18n/LocalStrings_fr.properties index 1b562409b526196eea7fc0ed340d14793b471d71..03e732f3d4c9dd180b99a3b5fb562c422b33b622 100644 --- a/src/main/java/org/olat/core/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/core/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Sun Nov 08 11:46:23 CET 2015 +#Fri Aug 18 09:02:02 CEST 2017 alert=Veuillez s\u00E9lectionner au moins un objet pour l'action d\u00E9sir\u00E9e, svp. back=Pr\u00E9c\u00E9dent calendar.choose=S\u00E9lectionnez une date dans le mini-calendrier @@ -23,6 +23,12 @@ finish=Terminer form.checkall=Tout s\u00E9lectionner form.date.datevalid=La date doit \u00EAtre valide form.dirty=Attention\! Vous avez des entr\u00E9es de formulaires non sauvegard\u00E9es. Si vous cliquez ok, les modifications seront perdues. +form.dirty.back=Appuyez sur le bouton <strong>$\:form.dirty.button.back</ strong> pour revenir au formulaire et l'enregistrer. +form.dirty.button.back=Retour au formulaire +form.dirty.button.ignore=Ne pas enregistrer les donn\u00E9es +form.dirty.ignore=Si vous appuyez sur le bouton <strong>$\:form.dirty.button.ignore</strong>, vous quittez le formulaire sans le sauvegarder. <strong>Les changements seront perdus</strong>. +form.dirty.intro=Attention\! Le formulaire contient encore des donn\u00E9es que vous n'avez pas enregistr\u00E9es. +form.dirty.title=Donn\u00E9es non-enregistr\u00E9es form.error.nointeger=Nombre invalide. Il faut indiquer un nombre. form.general.error=Des erreurs de saisie sont survenues. Suivez les indications relatives aux champs, svp. form.legende.mandatory=<i>Veuillez remplir ce champ.</i> diff --git a/src/main/java/org/olat/core/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/_i18n/LocalStrings_pl.properties index f3ab69412682c23d1cfcdac38a8aaa472dca4935..4d2318d1cc531d24e8b91ed1b48c0e9f1deecb3d 100644 --- a/src/main/java/org/olat/core/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/core/_i18n/LocalStrings_pl.properties @@ -1,4 +1,4 @@ -#Tue Mar 01 16:20:46 CET 2016 +#Mon Aug 21 14:31:34 CEST 2017 alert=Wybierz co najmniej jeden obiekt. back=Wstecz calendar.choose=Pobierz dat\u0119 z mini kalendarza @@ -11,15 +11,19 @@ confirmation.yes.toolHelp=Tak contact=Kontakt delete=Usu\u0144 edit=Edytuj +enabled=W\u0142\u0105czony error.header=B\u0142\u0105d error.jpbwrapper.renderfailed=Ten komponent nie mo\u017Ce zosta\u0107 wy\u015Bwietlony ponownie. Spr\u00F3buj uruchomi\u0107 komponent ponownie. error.noformpostdata=Uwaga\! W zwi\u0105zku z problemami dotycz\u0105cymi Internet Explorer'a dane mog\u0105 nie zosta\u0107 przes\u0142ane. Wci\u015Bnij przycisk "wstecz" i spr\u00F3buj ponownie. +error.post.method.mandatory=U\u017Cyj przegl\u0105darki\! expand=Rozszerz +export=Eksportuj extsearch=Szukanie zaawansowane finish=Zako\u0144cz form.checkall=Zaznacz wszystkie form.date.datevalid=Data musi by\u0107 poprawna form.dirty=Uwaga\! Nie zapisa\u0142e\u015B danych wprowadzonych do tego formularza. Klikaj\u0105c OK Twoje zmiany nie zostan\u0105 zapisane. +form.error.nointeger=Nieprawid\u0142owa liczba. Prosz\u0119 poda\u0107 liczb\u0119 ca\u0142kowit\u0105. form.general.error=Dane w formularzu s\u0105 nieprawid\u0142owe. form.legende.mandatory=<i>Uzupe\u0142nij to pole.</i> form.legende.wikiMarkup=<i>To pole umo\u017Cliwia wej\u015Bcie sformatowane z u\u017Cyciem j\u0119zyka znacznik\u00F3w wiki.</i> </br >*<b>bold</b>*<br>_<i>italic</i>_<br>* List items @@ -27,11 +31,15 @@ form.mandatory.hover=To pole jest obowi\u0105zkowe form.uncheckall=Usu\u0144 wszystkie zaznaczenia form.wiki.hover=To pole mo\u017Ce by\u0107 formatowane z u\u017Cyciem znacznik\u00F3w j\u0119zyka Wiki help=Pomoc +help.button=Otw\u00F3rz pomoc dla tej funkcji w instrukcji +help.manual=Instrukcja +help.tooltip.link=Aby uzyska\u0107 wi\u0119cej informacji kliknij na {0} info.header=Informacje info.saved=Twoje zmiany zosta\u0142y zapisane. input.toolong=Dane wej\u015Bciowe zbyt d\u0142ugie logout=Wyloguj module.change.warning=Uruchom ponownie OpenOLAT \u017Ceby zastosowa\u0107 zmiany +new=nowy new.form.mandatory=To pole jest obowi\u0105zkowe. next=Dalej no=Nie @@ -42,6 +50,7 @@ page.appname=OpenOLAT page.title=infinite learning placeholder={0} print=Drukuj +quick.search=Proste wyszukiwanie rating.1.1=Tak rating.2.1=\u0179le rating.2.2=Dobrze @@ -60,6 +69,7 @@ rating.5.5=\u015Awietnie rating.explanation=Kliknij, \u017Ceby oceni\u0107 reset=Resetuj save=Zapisz +save.admin.settings=Konfiguracja zosta\u0142a zapisana save.close=Zapisz i zamknij savesas=Zapisz jako search=Szukaj @@ -82,14 +92,14 @@ table.showall=Poka\u017C wszystko table.showpages=Strony this.language.in.english=Polish this.language.translated=Polski -this.language.translator.names=Bartlomiej Gajc, Piotr Kowalski, Daniel Majchrzak, Adam Jaworski +this.language.translator.names=Bartlomiej Gajc, Piotr Kowalski, Daniel Majchrzak, Adam Jaworski, Jakub Wasielewski tomcat.options.restart=Uruchom ponownie teraz tomcat.options.restartonidle=Uruchom ponownie, gdy wszyscy u\u017Cytkownicy wyloguj\u0105 si\u0119 toolbox.actions=Akcje toolbox.tools=Narz\u0119dzia -top=do g\u00F3ry +top=Id\u017A do g\u00F3ry top.alt=Id\u017A do g\u00F3ry strony -user.guest=gosc +user.guest=Go\u015B\u0107 warn.beta.feature=Uwaga, funkcja w fazie beta\! B\u0105d\u017A \u015Bwiadomy, \u017Ce jej u\u017Cycie mo\u017Ce powodowa\u0107 nieoczekiwane zachowanie przegl\u0105darki. warn.header=Ostrze\u017Cenie warn.notdispatched=Ta strona zosta\u0142a zmodyfikowana. diff --git a/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties index 63958964a93361774e6a9372edf84a2a7ebcf9b8..d2fbb873ef3d2d5d2551295fe62aaf40c46919d9 100644 --- a/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Mon Nov 21 15:06:56 CET 2016 +#Tue Sep 05 19:07:58 CEST 2017 alert=Favor selecionar no m\u00EDnimo um objeto para sua a\u00E7\u00E3o. back=Voltar calendar.choose=Escolha uma data do mini calend\u00E1rio @@ -23,6 +23,12 @@ finish=Finalizar form.checkall=Selecionar tudo form.date.datevalid=A data deve ser v\u00E1lida form.dirty=Aten\u00E7\u00E3o\! Voc\u00EA n\u00E3o salvou o formul\u00E1rio. Pressionando OK as suas modifica\u00E7\u00F5es ser\u00E3o perdidas. +form.dirty.back=Ao clicar em <strong>$\:form.dirty.button.back</strong>, voc\u00EA retornar\u00E1 ao formul\u00E1rio onde poder\u00E1 salv\u00E1-lo. +form.dirty.button.back=Voltar ao formul\u00E1rio +form.dirty.button.ignore=N\u00E3o guardar dados +form.dirty.ignore=Ao clicar em <strong>$\:form.dirty.button.ignore</strong>, voc\u00EA ir\u00E1 sair do formul\u00E1rio sem salvar. <strong>As altera\u00E7\u00F5es feitas nesta p\u00E1gina ser\u00E3o perdidas</strong> +form.dirty.intro=Aten\u00E7\u00E3o\! Voc\u00EA ainda n\u00E3o salvou este formul\u00E1rio. +form.dirty.title=Dados do formul\u00E1rio n\u00E3o salvos form.error.nointeger=N\u00FAmero inv\u00E1lido. Por favor insira um n\u00FAmero inteiro. form.general.error=Formul\u00E1rio de dados n\u00E3o \u00E9 v\u00E1lido. form.legende.mandatory=<i>Favor preencher este campo.</i> diff --git a/src/main/java/org/olat/core/_spring/mainCorecontext.xml b/src/main/java/org/olat/core/_spring/mainCorecontext.xml index 3ab96ee70d045240e182c00507d78409963090c8..69bc796fff36ed6c7cb3bc45ad506b67a17e9ad7 100644 --- a/src/main/java/org/olat/core/_spring/mainCorecontext.xml +++ b/src/main/java/org/olat/core/_spring/mainCorecontext.xml @@ -8,12 +8,11 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - <context:component-scan base-package="org.olat.core.dispatcher.mapper,org.olat.core.id.context,org.olat.core.commons.controllers.impressum,org.olat.core.gui.render.velocity" /> + <context:component-scan base-package="org.olat.core.dispatcher.mapper,org.olat.core.id.context,org.olat.core.commons.controllers.impressum,org.olat.core.helpers,org.olat.core.gui.render.velocity" /> <bean id="coreSpringFactory" class="org.olat.core.CoreSpringFactory" /> <import resource="classpath:/org/olat/core/util/vfs/version/_spring/versioningCorecontext.xml"/> - <import resource="classpath:/org/olat/core/util/i18n/_spring/i18nCorecontext.xml"/> <import resource="classpath:/org/olat/core/util/_spring/utilCorecontext.xml"/> <import resource="classpath:/org/olat/core/util/i18n/devtools/_spring/devtoolsCorecontext.xml"/> <import resource="classpath:/org/olat/core/util/event/_spring/frameworkStartedEventCorecontext.xml"/> @@ -41,13 +40,13 @@ <property name="parserPoolSize" value="${velocity.parser.pool.size}" /> </bean> - <bean id="mapperSlayerTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="mapperSlayerTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="mapperSlayerJob" /> <property name="cronExpression" value="0 5 0/1 * * ?" /> <property name="startDelay" value="200000" /> </bean> - <bean id="mapperSlayerJob" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="mapperSlayerJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.core.dispatcher.mapper.manager.MapperZombieSlayerJob" /> </bean> diff --git a/src/main/java/org/olat/core/commons/controllers/filechooser/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/commons/controllers/filechooser/_i18n/LocalStrings_pl.properties index 83f34422fbc325cd32708ab8b55a3bbf7d87f77a..69e417d42688e6b4d96fb4d3f67ba63e75b68131 100644 --- a/src/main/java/org/olat/core/commons/controllers/filechooser/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/core/commons/controllers/filechooser/_i18n/LocalStrings_pl.properties @@ -1,7 +1,28 @@ -#Fri Jun 19 18:33:12 CEST 2009 +#Thu Jul 27 14:32:13 CEST 2017 +button.create=Utw\u00F3rz +calloutTrigerLink.select.site=Wybierz stron\u0119 +calloutTriggerLink=Wybierz, utw\u00F3rz lub prze\u015Blij plik +calloutTriggerLink.replace=Zast\u0105p stron\u0119 +chooseLink=Wybierz plik +command.create=Utw\u00F3rz stron\u0119 i otw\u00F3rz w edytorze +command.edit=Otw\u00F3rz stron\u0119 w edytorze +command.preview.label=Wybierz plik HTML +createLink=Utw\u00F3rz plik +error.deleted=Skonfigurowany plik nie istnieje. Utw\u00F3rz plik ponownie lub wybierz inny. +error.name.empty=Prosz\u0119 wpisa\u0107 nazw\u0119 tworzonego pliku filechooser.select.internallink.title=Wybierz wewn\u0119trzny link filechooser.select.title=Wybierz istniej\u0105cy plik filechooser.tree.error.only.leafs=Nie mo\u017Cna wybra\u0107 katalogu {0}. Wybierz plik zamiast katalogu. filechooser.tree.select.intro=Wska\u017C element z drzewa i wci\u015Bnij przycisk "Wybierz". filechooser.tree.select.title=Wybierz plik filechooser.upload.title=Za\u0142aduj plik +filecreator.filename=Nazwa pliku +filecreator.filename.placeholder=Wpisz tutaj nazw\u0119 pliku, np. moj_plik.html +filecreator.text.newfile=Utw\u00F3rz now\u0105 stron\u0119 HTML +flexi.form.file=Plik +flexi.form.filetobig=Plik jest za du\u017Cy +flexi.form.mustbefilled=obowi\u0105zkowe +no.file.chosen=Nie wybrano \u017Cadnego pliku +uploadLink=Przeka\u017C plik +warning.already.exists=Czy chcesz utworzy\u0107 nowy folder "{0}" ? +warning.already.exists.title=Folder "{0}" ju\u017C istnieje diff --git a/src/main/java/org/olat/core/commons/controllers/impressum/ImpressumAdminController.java b/src/main/java/org/olat/core/commons/controllers/impressum/ImpressumAdminController.java index ee7371c11b58f85694d58ab98391d880e551939e..08c97ecef816ba3acc436d92dd6b61cf2fa0d7b7 100644 --- a/src/main/java/org/olat/core/commons/controllers/impressum/ImpressumAdminController.java +++ b/src/main/java/org/olat/core/commons/controllers/impressum/ImpressumAdminController.java @@ -73,6 +73,8 @@ public class ImpressumAdminController extends FormBasicController { private final VFSContainer impressumDir; private final VFSContainer termsOfUseDir; + @Autowired + private I18nModule i18nModule; @Autowired private I18nManager i18nManager; @Autowired @@ -116,7 +118,7 @@ public class ImpressumAdminController extends FormBasicController { List<ButtonGroup> impressumButtons = new ArrayList<>(); impressumCont.contextPut("buttons", impressumButtons); - for(String lang:I18nModule.getEnabledLanguageKeys()) { + for(String lang:i18nModule.getEnabledLanguageKeys()) { FormLink editLink = uifactory .addFormLink("impressum." + lang, "impressum", getTranslated(lang), "impressum.file", impressumCont, Link.BUTTON | Link.NONTRANSLATED); editLink.setLabel(null, null); @@ -146,7 +148,7 @@ public class ImpressumAdminController extends FormBasicController { List<ButtonGroup> termsOfUseButtons = new ArrayList<>(); termsCont.contextPut("buttons", termsOfUseButtons); - for(String lang:I18nModule.getEnabledLanguageKeys()) { + for(String lang:i18nModule.getEnabledLanguageKeys()) { FormLink editLink = uifactory.addFormLink("termofuser." + lang, "termsofuse", getTranslated(lang), "termofuse.file", termsCont, Link.BUTTON | Link.NONTRANSLATED); editLink.setLabel(null, null); String filePath = "index_" + lang + ".html"; diff --git a/src/main/java/org/olat/core/commons/controllers/impressum/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/commons/controllers/impressum/_i18n/LocalStrings_pl.properties index b559136cebbf7bdd14b24a6cac4d328a54f0d509..7f605a8f1fd5a20579999372d54c5a409fa547d6 100644 --- a/src/main/java/org/olat/core/commons/controllers/impressum/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/core/commons/controllers/impressum/_i18n/LocalStrings_pl.properties @@ -1,9 +1,18 @@ -#Sun Dec 23 19:13:46 CET 2012 +#Thu Jul 27 14:37:23 CEST 2017 ContactController.menu.title=Kontakt ContactController.menu.title.alt=Kontakt +ImpressumController.menu.title=$\:menu.impressum ImpressumController.menu.title.alt=Imprint TermsOfUseController.menu.title=Warunki u\u017Cytkowania TermsOfUseController.menu.title.alt=Warunki korzystania +config.hint=Tutaj mo\u017Cesz w\u0142\u0105czy\u0107 lub wy\u0142\u0105czy\u0107 znak wodny na stronie, wybierz po\u0142o\u017Cenie i zmie\u0144 tekst znaku wodnego. contact.to=Sekretariat contactform.intro=Formularz kontaktowy dla og\u00F3lnych zapyta\u0144 contactform.title=Kontakt +enable=w\u0142\u0105czone +enable.impressum=W\u0142\u0105cz znak wodny +main.menu.title=$\:menu.impressum +position=Pozycja +position.footer=Stopka +position.top=G\u00F3ra +termofuse.file=Warunki korzystania diff --git a/src/main/java/org/olat/core/commons/controllers/resume/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/commons/controllers/resume/_i18n/LocalStrings_pl.properties index e8cdf3b8f0f8fd91e4966909b067d91b696c952e..9cf10485ea1804d5979f78230ca3b48d19570ac2 100644 --- a/src/main/java/org/olat/core/commons/controllers/resume/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/core/commons/controllers/resume/_i18n/LocalStrings_pl.properties @@ -1,5 +1,6 @@ -#Sun Apr 08 14:48:34 CEST 2012 +#Thu Jul 27 14:38:39 CEST 2017 askagain.label=Nie pytaj ponownie resume=Czy chcesz wznowi\u0107 poprzedni\u0105 sesj\u0119? resume.button=Tak resume.button.cancel=Nie +resume.button.landing=Strona startowa diff --git a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java index 717d796a5e5857bb2b97864f899d1f15085d3c67..8b2f579b3605ac38a12433cdb5fc2d6a81a6eaf0 100644 --- a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java +++ b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java @@ -114,6 +114,7 @@ import org.olat.course.assessment.ui.mode.AssessmentModeGuardController; import org.olat.course.assessment.ui.mode.ChooseAssessmentModeEvent; import org.olat.gui.control.UserToolsMenuController; import org.olat.home.HomeSite; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -185,6 +186,11 @@ public class BaseFullWebappController extends BasicController implements DTabs, private final boolean isAdmin; private final int maxTabs = 20; + @Autowired + private I18nModule i18nModule; + @Autowired + private I18nManager i18nManager; + public BaseFullWebappController(UserRequest ureq, BaseFullWebappControllerParts baseFullWebappControllerParts) { // only-use-in-super-call, since we define our own super(ureq, null); @@ -350,14 +356,15 @@ public class BaseFullWebappController extends BasicController implements DTabs, // will start the translation tool in translation mode, if the overlay // feature is enabled it will start in customizing mode // fxdiff: allow user-managers to use the inline translation also. - if (ureq.getUserSession().isAuthenticated() - && (ureq.getUserSession().getRoles().isOLATAdmin() || ureq.getUserSession().getRoles().isUserManager()) - && (I18nModule.isTransToolEnabled() || I18nModule.isOverlayEnabled())) { + UserSession usess = ureq.getUserSession(); + if (usess.isAuthenticated() + && (usess.getRoles().isOLATAdmin() || usess.getRoles().isUserManager()) + && (i18nModule.isTransToolEnabled() || i18nModule.isOverlayEnabled())) { inlineTranslationC = wbo.createInlineTranslationDispatcherController(ureq, getWindowControl()); Preferences guiPrefs = ureq.getUserSession().getGuiPreferences(); Boolean isInlineTranslationEnabled = (Boolean) guiPrefs.get(I18nModule.class, I18nModule.GUI_PREFS_INLINE_TRANSLATION_ENABLED, Boolean.FALSE); - I18nManager.getInstance().setMarkLocalizedStringsEnabled(ureq.getUserSession(), isInlineTranslationEnabled); + i18nManager.setMarkLocalizedStringsEnabled(ureq.getUserSession(), isInlineTranslationEnabled); mainVc.put("inlineTranslation", inlineTranslationC.getInitialComponent()); } @@ -1198,6 +1205,23 @@ public class BaseFullWebappController extends BasicController implements DTabs, return true; } + @Override + public void updateDTabTitle(OLATResourceable ores, String newTitle) { + DTab dTab = getDTab(ores); + if (dTab != null) { + dTab.getNavElement().setTitle(newTitle); + // search all dtab links and find the one with the correct dtab as user object + for (int i = 0; i <= dtabCreateCounter; i++) { + Link link = (Link)navTabsVc.getComponent("a" + i); + if (link != null && dTab.equals(link.getUserObject())) { + // correct link found - updte titel and we are done + link.setCustomDisplayText(newTitle); + return; + } + } + } + } + /** * Activating a tab is like focusing a new window - we need to adjust the * guipath since e.g. the button triggering the activation is not diff --git a/src/main/java/org/olat/core/commons/fullWebApp/_content/fullwebapplayout.html b/src/main/java/org/olat/core/commons/fullWebApp/_content/fullwebapplayout.html index c85948e4d1338e211901a6698038053f51258bf1..cf1a3feb375edf69eb45272be31de6ecaab514d7 100644 --- a/src/main/java/org/olat/core/commons/fullWebApp/_content/fullwebapplayout.html +++ b/src/main/java/org/olat/core/commons/fullWebApp/_content/fullwebapplayout.html @@ -25,6 +25,7 @@ o_info.uriprefix="$r.relWinLink()"; o_info.bc="$o_bc"; o_info.businessPath=""; o_info.serverUri="$o_serverUri" +## Legacy form-dirty message displayed by o2cl() o_info.dirty_form = "$r.escapeDoubleQuotes($r.translate("form.dirty"))"; o_info.locale = "$r.getLanguageCode()"; o_info.lastClickTime = new Date().getTime(); @@ -51,29 +52,30 @@ function o_start() { o_info.initialPageLoadFinished = true; } function o_mathjax(fct_success) { - jQuery.ajax("${r.mathJaxCdn()}MathJax.js?config=TeX-AMS-MML_HTMLorMML", { + window.MathJax = { + extensions: ["jsMath2jax.js"], + messageStyle: 'none', + showProcessingMessages: false, + showMathMenu: false, + menuSettings: { }, + jsMath2jax: { + preview: "none" + }, + tex2jax: { + ignoreClass: "math" + }, + "HTML-CSS": { + EqnChunk: 5, EqnChunkFactor: 1, EqnChunkDelay: 100 + }, + "fast-preview": { + disabled: true + } + } + jQuery.ajax("${r.mathJaxCdn()}MathJax.js?config=${r.mathJaxConfig()}", { cache: true, dataType: "script", + crossDomain: true, success: function() { - MathJax.Hub.Config({ - extensions: ["jsMath2jax.js"], - messageStyle: 'none', - showProcessingMessages: false, - showMathMenu: false, - menuSettings: { }, - jsMath2jax: { - preview: "none" - }, - tex2jax: { - ignoreClass: "math" - }, - "HTML-CSS": { - EqnChunk: 5, EqnChunkFactor: 1, EqnChunkDelay: 100 - }, - "fast-preview": { - disabled: true - } - }); if(!(typeof fct_success === "undefined")) { fct_success(); } @@ -328,6 +330,34 @@ $r.render("stickymsg") $r.render("modalpanel") ## ---- END #o_modal --- +## ----- START #o_form_dirty_message ---------- +<div class="modal fade" tabindex="-1" role="dialog" id="o_form_dirty_message"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title">$r.translate("form.dirty.title")</h4> + </div> + <div class="modal-body"> + <p class="o_warning"> + $r.escapeDoubleQuotes($r.translate("form.dirty.intro")) + </p> + <p> + $r.escapeDoubleQuotes($r.translate("form.dirty.ignore")) + </p> + <p> + $r.escapeDoubleQuotes($r.translate("form.dirty.back")) + </p> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-primary pull-left o_form_dirty_back" data-dismiss="modal"><i class="o_icon o_icon-fw o_icon_back"> </i>$r.translate("form.dirty.button.back")</button> + <button type="button" class="btn btn btn-danger o_form_dirty_ignore"><i class="o_icon o_icon-fw o_icon_clear_all"> </i>$r.translate("form.dirty.button.ignore")</button> + </div> + </div> + </div> +</div> +## ---- END #o_form_dirty_message --- + ## the div for the busy-wait animated-gif <div id="o_ajax_busy"><i class="o_icon o_icon_busy o_icon-5x o_icon-spin"></i></div> @@ -340,4 +370,4 @@ jQuery(function() { o_initEmPxFactor(); }); /* ]]> */ -</script></div></body></html> \ No newline at end of file +</script></div></body></html> diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java index 30b8ad99215483b45c3545bdc8279c1c4e2db42a..32b534fa6a7beb86abac31e363b43ce71bf2907f 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java +++ b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java @@ -151,8 +151,6 @@ public class FileUploadController extends FormBasicController { @Autowired private ImageService imageHelper; @Autowired - private FilesInfoMBean fileInfoMBean; - @Autowired private VFSLockManager vfsLockManager; @Autowired private MetaInfoFactory metaInfoFactory; @@ -716,7 +714,6 @@ public class FileUploadController extends FormBasicController { if (success) { String filePath = (uploadRelPath == null ? "" : uploadRelPath + "/") + newFile.getName(); finishSuccessfullUpload(filePath, newFile, ureq); - fileInfoMBean.logUpload(newFile.getSize()); fireEvent(ureq, Event.DONE_EVENT); } else { showError("failed"); @@ -731,7 +728,6 @@ public class FileUploadController extends FormBasicController { VFSItem item = currentContainer.resolve(filePath); if(item != null) { finishSuccessfullUpload(filePath, item, ureq); - fileInfoMBean.logUpload(newFile.getSize()); } else { logWarn("Upload with error:" + filePath, null); } diff --git a/src/main/java/org/olat/core/commons/modules/bc/FilesInfoMBean.java b/src/main/java/org/olat/core/commons/modules/bc/FilesInfoMBean.java deleted file mode 100644 index 54774300276c220f46cb0b4a0b14e4cfe8aa89d7..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/commons/modules/bc/FilesInfoMBean.java +++ /dev/null @@ -1,90 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ -package org.olat.core.commons.modules.bc; - - -/** - * JMX MBean class to collect infos about file access (upload:client to server , - * download : server to client). - * @author Christian Guretzki - */ -public class FilesInfoMBean { - private long numberOfUploadedFiles = 0; - private long sizeOfUploadedFiles = 0; - private long numberOfDownloadedFiles = 0; - private long sizeOfDownloadedFiles = 0; - - - /** - * Call this method when some file was upload into olat. - * @param size Uploaded-file-size - */ - public synchronized void logUpload(long size) { - numberOfUploadedFiles++; - sizeOfUploadedFiles += size; - } - - /** - * Call this method when some file was downloaded from olat. - * @param size Downloaded-file-size - */ - public synchronized void logDownload(long size) { - numberOfDownloadedFiles++; - sizeOfDownloadedFiles += size; - } - - // JMX MBean Methods - //////////////////// - /** - * @return Number of uploaded file since system start. - */ - public long getNumberOfUploadedFiles() { - return numberOfUploadedFiles; - } - - /** - * @return Overall size of uploaded files since system start. - */ - public long getSizeOfUploadedFiles() { - return sizeOfUploadedFiles; - } - - /** - * @return Number of downloaded file since system start. - */ - public long getNumberOfDownloadedFiles() { - return numberOfDownloadedFiles; - } - - /** - * @return Overall size of downloaded file since system start. - */ - public long getSizeOfDownloadedFiles() { - return sizeOfDownloadedFiles; - } - -} - diff --git a/src/main/java/org/olat/core/commons/modules/bc/FolderManager.java b/src/main/java/org/olat/core/commons/modules/bc/FolderManager.java index 3e67e7bfc9bb7ceadfc0805f246353b193ca05d6..db96efb83f13d74b3c2d5b22a5da6e4965723622 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/FolderManager.java +++ b/src/main/java/org/olat/core/commons/modules/bc/FolderManager.java @@ -48,6 +48,8 @@ import org.olat.core.util.vfs.filters.SystemItemFilter; * @author Mike Stock */ public class FolderManager extends BasicManager { + + private static FolderModule folderModule; /** * Get this path as a full WebDAV link @@ -100,4 +102,35 @@ public class FolderManager extends BasicManager { } } + /** + * Check if a file is offered as a download or as inline rendered. If + * security is enabled in the module, this will return true for all file + * types. If disabled it will depend on the mime type. + * + * @param name the File name (including mime type extension, e.g. "index.html" + * @return true: force file download; false: open in new browser window + */ + public static boolean isDownloadForcedFileType(String name) { + if (folderModule == null) { + // Load only once and keep. Not best practice, in the long run the + // folder manager needs a full spring bean refactoring, but for now + // this is good enough. The not synchronized nature of the + // assignment is not a problem here. + folderModule = CoreSpringFactory.getImpl(FolderModule.class); + } + // If enabled in module, no further checks necessary. + boolean download = folderModule.isForceDownload(); + if (!download) { + // Additional check if not an html or txt page. Only HTML pages are + // displayed in browser, all other should be downloaded. + // Excel, Word and PowerPoint not allowed to open inline, they will show + // an unsupported WebDAV loginpromt! + String mimeType = WebappHelper.getMimeType(name); + if (mimeType != null && !"text/html".equals(mimeType) && !"application/xhtml+xml".equals(mimeType)) { + download = true; + } + } + return download; + } + } diff --git a/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java b/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java index 5593c95a19f8c603bb000c15a471aa757e9ca8e8..216e9957eed28f6537e3def347febe4c6288cc5b 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java +++ b/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java @@ -60,6 +60,7 @@ import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.id.OLATResourceable; +import org.olat.core.id.Roles; import org.olat.core.id.context.BusinessControl; import org.olat.core.id.context.BusinessControlFactory; import org.olat.core.id.context.ContextEntry; @@ -70,6 +71,7 @@ import org.olat.core.logging.activity.CoreLoggingResourceable; import org.olat.core.logging.activity.ILoggingAction; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.StringHelper; +import org.olat.core.util.UserSession; import org.olat.core.util.resource.OresHelper; import org.olat.core.util.vfs.OlatRelPathImpl; import org.olat.core.util.vfs.Quota; @@ -80,10 +82,12 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSManager; import org.olat.core.util.vfs.callbacks.VFSSecurityCallback; import org.olat.core.util.vfs.filters.VFSItemFilter; +import org.olat.search.SearchModule; import org.olat.search.SearchServiceUIFactory; import org.olat.search.SearchServiceUIFactory.DisplayOption; import org.olat.search.ui.SearchInputController; import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -112,6 +116,9 @@ public class FolderRunController extends BasicController implements Activateable private FolderCommand folderCommand; private CloseableModalController cmc; private Link editQuotaButton; + + @Autowired + private SearchModule searchModule; /** * Default Constructor, results in showing users personal folder, used by Spring @@ -282,7 +289,8 @@ public class FolderRunController extends BasicController implements Activateable } } - if(!ureq.getUserSession().getRoles().isGuestOnly() && displaySearch) { + Roles roles = ureq.getUserSession().getRoles(); + if(displaySearch && searchModule.isSearchAllowed(roles)) { SearchServiceUIFactory searchUIFactory = (SearchServiceUIFactory)CoreSpringFactory.getBean(SearchServiceUIFactory.class); searchC = searchUIFactory.createInputController(ureq, wControl, DisplayOption.STANDARD, null); listenTo(searchC); // register for auto-dispose @@ -290,7 +298,7 @@ public class FolderRunController extends BasicController implements Activateable } - boolean isGuest = ureq.getUserSession().getRoles().isGuestOnly(); + boolean isGuest = roles.isGuestOnly(); folderComponent = new FolderComponent(ureq, "foldercomp", rootContainer, filter, customLinkTreeModel, externContainerForCopy); folderComponent.setCanMail(isGuest ? false : canMail); // guests can never send mail folderComponent.addListener(this); @@ -496,12 +504,13 @@ public class FolderRunController extends BasicController implements Activateable private void enableDisableQuota(UserRequest ureq) { //prevent a timing condition if the user logout while a thumbnail is generated - if (ureq.getUserSession() == null || ureq.getUserSession().getRoles() == null) { + UserSession usess = ureq.getUserSession(); + if (usess == null || usess.getRoles() == null) { return; } Boolean newEditQuota = Boolean.FALSE; - if (ureq.getUserSession().getRoles().isOLATAdmin() || ureq.getUserSession().getRoles().isInstitutionalResourceManager()) { + if (usess.getRoles().isOLATAdmin() || usess.getRoles().isInstitutionalResourceManager()) { // Only sys admins or institutonal resource managers can have the quota button Quota q = VFSManager.isTopLevelQuotaContainer(folderComponent.getCurrentContainer()); newEditQuota = (q == null)? Boolean.FALSE : Boolean.TRUE; diff --git a/src/main/java/org/olat/core/commons/modules/bc/_spring/folderModuleCorecontext.xml b/src/main/java/org/olat/core/commons/modules/bc/_spring/folderModuleCorecontext.xml index f4b67e20235268f4ee61cdf91b427e618212c188..c088f30758bbd4b731b472b5803b1a2207ed9a08 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/_spring/folderModuleCorecontext.xml +++ b/src/main/java/org/olat/core/commons/modules/bc/_spring/folderModuleCorecontext.xml @@ -10,9 +10,6 @@ <context:component-scan base-package="org.olat.core.commons.modules.bc" /> - - <bean id="org.olat.core.commons.modules.bc.FilesInfoMBean" class="org.olat.core.commons.modules.bc.FilesInfoMBean" /> - <bean id="metaInfoFactory" class="org.olat.core.commons.modules.bc.meta.MetaInfoFactory"> <property name="thumbnailService" ref="thumbnailService" /> </bean> diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java index 817a0a4327135c8b40f767f188e6223ccecad7ac..3a629518960a889d62da6772c364ad4731505c95 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java +++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java @@ -63,7 +63,8 @@ public class CmdEditQuota extends DefaultController implements FolderCommand, Co // cleanup old controller first if (quotaEditController != null) quotaEditController.dispose(); // create a edit controller - quotaEditController = QuotaManager.getInstance().getQuotaEditorInstance(ureq, wControl, currentSecCallback.getQuota().getPath(), true); quotaEditController.addControllerListener(this); + quotaEditController = QuotaManager.getInstance().getQuotaEditorInstance(ureq, wControl, currentSecCallback.getQuota().getPath()); + quotaEditController.addControllerListener(this); if (quotaEditController != null) { setInitialComponent(quotaEditController.getInitialComponent()); return this; diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdServeResource.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdServeResource.java index e643a57cbb9cf054ea41931cc4892183e7403cf3..05b3049dfd9c9d08ed7e3fc52824d9533436b6e4 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdServeResource.java +++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdServeResource.java @@ -30,9 +30,8 @@ import java.io.InputStream; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.FolderLoggingAction; -import org.olat.core.commons.modules.bc.FolderModule; +import org.olat.core.commons.modules.bc.FolderManager; import org.olat.core.commons.modules.bc.components.FolderComponent; import org.olat.core.commons.modules.bc.meta.MetaInfo; import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; @@ -82,9 +81,9 @@ public class CmdServeResource implements FolderCommand { } else if(!(vfsitem instanceof VFSLeaf)) { mr = new NotFoundMediaResource(path); } else { - boolean forceDownload = CoreSpringFactory.getImpl(FolderModule.class).isForceDownload(); VFSLeaf vfsfile = (VFSLeaf)vfsitem; + boolean forceDownload = FolderManager.isDownloadForcedFileType(vfsfile.getName()); if (path.toLowerCase().endsWith(".html") || path.toLowerCase().endsWith(".htm")) { // setCurrentURI(path); // set the http content-type and the encoding @@ -119,6 +118,9 @@ public class CmdServeResource implements FolderCommand { smr.setContentType(mimetype); smr.setEncoding(enc); smr.setData(page); + if(forceDownload) { + smr.setDownloadable(true, vfsfile.getName()); + } mr = smr; } else { // found a new charset other than iso-8859-1 -> let it load again @@ -158,10 +160,7 @@ public class CmdServeResource implements FolderCommand { } else { // binary data: not .html, not .htm, not .js -> treated as is VFSMediaResource vmr = new VFSMediaResource(vfsfile); - // This is to prevent the login prompt in Excel, Word and PowerPoint - if (path.endsWith(".xlsx") || path.endsWith(".pptx") || path.endsWith(".docx")) { - vmr.setDownloadable(true); - } else if(forceDownload) { + if(forceDownload) { vmr.setDownloadable(true); } mr = vmr; diff --git a/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java b/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java index 3d994d8aac5b36666ae23fb8b9a787012d082b6e..7e21b0ba96b542e79fcd4e561d58e4c005e4f974 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java +++ b/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java @@ -33,6 +33,7 @@ import java.util.List; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.FileSelection; import org.olat.core.commons.modules.bc.FolderConfig; +import org.olat.core.commons.modules.bc.FolderManager; import org.olat.core.commons.modules.bc.meta.MetaInfo; import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; import org.olat.core.gui.components.form.flexible.impl.NameValuePair; @@ -248,7 +249,14 @@ public class ListRenderer { } else { // for files, add PARAM_SERV command sb.append(" href=\""); ubu.buildURI(sb, new String[] { PARAM_SERV }, new String[] { "x" }, pathAndName, AJAXFlags.MODE_NORMAL); - sb.append("\" target=\"_blank\" download=\"").append(name).append("\""); + sb.append("\""); + + boolean download = FolderManager.isDownloadForcedFileType(name); + if (download) { + sb.append(" download=\"").append(StringHelper.escapeHtml(name)).append("\""); + } else { + sb.append(" target=\"_blank\""); + } } sb.append(">"); diff --git a/src/main/java/org/olat/core/commons/modules/bc/meta/_content/external_url.html b/src/main/java/org/olat/core/commons/modules/bc/meta/_content/external_url.html index b9404aa6a8665febb55c0bb5b50fa1606e6601ba..f198a6d78c0f8049529ba555f35d86c25050993c 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/meta/_content/external_url.html +++ b/src/main/java/org/olat/core/commons/modules/bc/meta/_content/external_url.html @@ -1,4 +1,4 @@ -<div class="o_copy_code o_nowrap form-control-static"><a href="javascript:;" id="o_extlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"></i></a>$resourceUrl</div> +<div class="o_copy_code o_nowrap form-control-static"><a href="javascript:;" id="o_extlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"> </i></a><input type="text" value="$resourceUrl" onclick="this.select()"/></div> <script type="text/javascript"> /* <![CDATA[ */ jQuery(function() { diff --git a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_fr.properties index 1c15bf25fe4fea0925228c0f85a7a570c8957cd1..00dd83b593a99b5ddf9a2d02443b235bdf6472d2 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_fr.properties @@ -2,7 +2,7 @@ cfile.name.notvalid=$org.olat.core.commons.modules.bc\:cfile.name.notvalid external.url=Lien externe vers cette ressource file.name.notvalid=Ce nom de fichier contient des caract\u00E8res non permis, veuillez \u00E9liminer tous les caract\u00E8res sp\u00E9ciaux comme /, \:, etc. -folder.name.notvalid=Le nom de ce dossier contient des caract\u00E8res d\u00E9conseill\u00E9s. Enlever s'il-vous-pla\u00EEt les caract\u00E8res sp\u00E9ciaux comme /,\: etc. +folder.name.notvalid=Le nom de ce dossier contient des caract\u00E8res d\u00E9conseill\u00E9s. Enlever s'il vous pla\u00EEt les caract\u00E8res sp\u00E9ciaux comme /,\: etc. mf.author=Cr\u00E9er par mf.cancel=Interrompre mf.city=Lieu diff --git a/src/main/java/org/olat/core/commons/persistence/DBQueryImpl.java b/src/main/java/org/olat/core/commons/persistence/DBQueryImpl.java index 8f5c2d4b8190b9a30b553e4075c3660bfff6d7e0..d4e45d03914154accd55a25d4fbb6313e4190867 100644 --- a/src/main/java/org/olat/core/commons/persistence/DBQueryImpl.java +++ b/src/main/java/org/olat/core/commons/persistence/DBQueryImpl.java @@ -31,14 +31,10 @@ import java.math.BigDecimal; import java.util.Calendar; import java.util.Collection; import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; import org.hibernate.FlushMode; import org.hibernate.HibernateException; @@ -59,18 +55,6 @@ public class DBQueryImpl implements DBQuery { private static final OLog log = Tracing.createLoggerFor(DBQueryImpl.class); private Query query = null; - - public final static Map<String, SimpleProbe> listTableStatsMap_ = new HashMap<String, SimpleProbe>(); - - public final static Set<String> registeredTables_ = new HashSet<String>(); - - static { - registeredTables_.add("org.olat.basesecurity.SecurityGroupMembershipImpl"); - registeredTables_.add("org.olat.group.area.BGAreaImpl"); - registeredTables_.add("org.olat.group.BusinessGroupImpl"); - registeredTables_.add("org.olat.resource.OLATResourceImpl"); - registeredTables_.add("org.olat.commons.lifecycle.LifeCycleEntry"); - } /** * Default construcotr. @@ -118,63 +102,8 @@ public class DBQueryImpl implements DBQuery { * @see org.olat.core.commons.persistence.DBQuery#list() */ public List list() { - final long startTime = System.currentTimeMillis(); try{ - boolean doLog = log.isDebug(); - long start = 0; - if (doLog) start = System.currentTimeMillis(); - List li = query.list(); - if (doLog) { - long time = (System.currentTimeMillis() - start); - log.debug("list dbquery (time "+time+") query "+getQueryString()); - } - String queryString = query.getQueryString().trim(); - String queryStringToLowerCase = queryString.toLowerCase(); - if (queryStringToLowerCase.startsWith("from ")) { - queryString = queryString.substring(5).trim(); - queryStringToLowerCase = queryString.toLowerCase(); - } else if (queryStringToLowerCase.startsWith("select ") && (queryStringToLowerCase.contains(" from "))) { - queryString = queryString.substring(queryStringToLowerCase.indexOf(" from ")+6).trim(); - queryStringToLowerCase = queryString.toLowerCase(); - } else { - queryString = null; - } - if (queryString!=null) { - final long endTime = System.currentTimeMillis(); - final long diff = endTime - startTime; - int wherePos = queryStringToLowerCase.indexOf(" where "); - if (wherePos!=-1) { - queryString = queryString.substring(0, wherePos); - } - queryString = queryString.trim(); - StringTokenizer st = new StringTokenizer(queryString, ","); - while(st.hasMoreTokens()) { - String aTable = st.nextToken(); - aTable = aTable.trim(); - int spacePos = aTable.toLowerCase().indexOf(" "); - if (spacePos!=-1) { - aTable = aTable.substring(0, spacePos); - } - aTable = aTable.trim(); - SimpleProbe probe = listTableStatsMap_.get(aTable); - if (probe==null) { - probe = new SimpleProbe(); - listTableStatsMap_.put(aTable, probe); - } - probe.addMeasurement(diff); - if (!registeredTables_.contains(aTable)) { - aTable = "THEREST"; - probe = listTableStatsMap_.get(aTable); - if (probe==null) { - probe = new SimpleProbe(); - listTableStatsMap_.put(aTable, probe); - } - probe.addMeasurement(diff); - } - //System.out.println(" A TABLE: "+aTable+" stats: "+probe); - } - } - return li; + return query.list(); } catch (HibernateException he) { String msg ="Error in list()" ; diff --git a/src/main/java/org/olat/core/commons/persistence/PersistenceHelper.java b/src/main/java/org/olat/core/commons/persistence/PersistenceHelper.java index 98eeab3928b78345856e01ebcb83cca2d15a3fa7..47f2b6911162a752f05568cc455eabe44c64d578 100644 --- a/src/main/java/org/olat/core/commons/persistence/PersistenceHelper.java +++ b/src/main/java/org/olat/core/commons/persistence/PersistenceHelper.java @@ -34,6 +34,7 @@ import java.util.Properties; import org.olat.core.id.Persistable; import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; import org.olat.core.util.filter.FilterFactory; /** @@ -395,4 +396,17 @@ public class PersistenceHelper { Object obj = results[pos]; return obj == null ? null : ((Boolean)obj).booleanValue(); } + + public static final String convert(String content) { + if(StringHelper.containsNonWhitespace(content)) { + StringBuilder sb = new StringBuilder(content.length() + 100); + for(char ch : content.toCharArray()) { + if(ch < 55000) { + sb.append(ch); + } + } + return sb.toString(); + } + return content; + } } diff --git a/src/main/java/org/olat/core/commons/persistence/SimpleProbe.java b/src/main/java/org/olat/core/commons/persistence/SimpleProbe.java deleted file mode 100644 index 8f1b0cb2e7844d7b139b643bd6050cdb5c194bb9..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/commons/persistence/SimpleProbe.java +++ /dev/null @@ -1,66 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.core.commons.persistence; - -public class SimpleProbe { - - private long total_; - private int num_; - private long max_; - - public synchronized void addMeasurement(long value) { - total_ += value; - num_++; - if (value>max_) { - max_ = value; - } - } - - public int getAvg() { - return Math.round((float)total_/(float)num_); - } - - public long getMax() { - return max_; - } - - public int getNum() { - return num_; - } - - public synchronized void reset() { - total_ = 0; - num_ = 0; - max_ = 0; - } - - public String toString() { - return "[num="+num_+", max="+max_+", avg="+getAvg()+"]"; - } - - public long getSum() { - return total_; - } -} diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImpl.java b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImpl.java index f0af0e22c6948b6cb6c90a9e9a6adecc6bf97e27..8a12a5ab300b2b2301053d16809695177c481c28 100644 --- a/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImpl.java +++ b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImpl.java @@ -27,6 +27,7 @@ import org.olat.core.commons.services.commentAndRating.model.OLATResourceableRat import org.olat.core.commons.services.commentAndRating.model.UserComment; import org.olat.core.commons.services.commentAndRating.model.UserCommentsCount; import org.olat.core.commons.services.commentAndRating.model.UserRating; +import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.AssertException; @@ -41,18 +42,19 @@ import org.springframework.stereotype.Service; * the interface for an code example) * <P> * Initial Date: 24.11.2009 <br> - * + * * @author gnaegi */ @Service public class CommentAndRatingServiceImpl implements CommentAndRatingService { + @Autowired private UserRatingsDAO userRatingsDao; @Autowired private UserCommentsDAO userCommentsDao; - + @Autowired + private NotificationsManager notificationsManager; - @Override public Long countRatings(OLATResourceable ores, String resSubPath) { @@ -122,7 +124,9 @@ public class CommentAndRatingServiceImpl implements CommentAndRatingService { @Override public UserComment createComment(Identity creator, OLATResourceable ores, String resSubPath, String commentText) { - return userCommentsDao.createComment(creator, ores, resSubPath, commentText); + UserComment comment = userCommentsDao.createComment(creator, ores, resSubPath, commentText); + markPublisherNews(comment); + return comment; } @Override @@ -132,12 +136,16 @@ public class CommentAndRatingServiceImpl implements CommentAndRatingService { @Override public UserComment replyTo(UserComment originalComment, Identity creator, String replyCommentText) { - return userCommentsDao.replyTo(originalComment, creator, replyCommentText); + UserComment reply = userCommentsDao.replyTo(originalComment, creator, replyCommentText); + markPublisherNews(reply); + return reply; } @Override public UserComment updateComment(UserComment comment, String newCommentText) { - return userCommentsDao.updateComment(comment, newCommentText); + UserComment updatedComment = userCommentsDao.updateComment(comment, newCommentText); + markPublisherNews(updatedComment); + return updatedComment; } @Override @@ -148,6 +156,7 @@ public class CommentAndRatingServiceImpl implements CommentAndRatingService { /** * @see org.olat.core.commons.services.commentAndRating.CommentAndRatingService#deleteAll() */ + @Override public int deleteAll(OLATResourceable ores, String resSubPath) { if (ores == null) { throw new AssertException("CommentAndRatingService must be initialized first, call init method"); @@ -158,9 +167,10 @@ public class CommentAndRatingServiceImpl implements CommentAndRatingService { } /** - * + * * @see org.olat.core.commons.services.commentAndRating.CommentAndRatingService#deleteAllIgnoringSubPath() */ + @Override public int deleteAllIgnoringSubPath(OLATResourceable ores) { if (ores == null) { throw new AssertException("CommentAndRatingService must be initialized first, call init method"); @@ -169,4 +179,14 @@ public class CommentAndRatingServiceImpl implements CommentAndRatingService { delCount += userRatingsDao.deleteAllRatingsIgnoringSubPath(ores); return delCount; } + + private void markPublisherNews(UserComment comment) { + if (comment == null) return; + + notificationsManager.markPublisherNews( + comment.getResName(), + comment.getResId().toString(), + null, + false); + } } diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentFormController.java b/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentFormController.java index b946686b3e6930e0d1894c48617fd9d43e9c129f..4f0eaa33ae72bb10bf1e8897a8b34dfff392e94e 100644 --- a/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentFormController.java +++ b/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentFormController.java @@ -52,15 +52,15 @@ import org.olat.core.util.StringHelper; * </ul> * <P> * Initial Date: 24.11.2009 <br> - * + * * @author gnaegi */ public class UserCommentFormController extends FormBasicController { private UserComment parentComment; private UserComment toBeUpdatedComment; - // + // private RichTextElement commentElem; - + private final String resSubPath; private final OLATResourceable ores; private final CommentAndRatingService commentAndRatingService; @@ -68,7 +68,7 @@ public class UserCommentFormController extends FormBasicController { /** * Constructor for a user comment form controller. Use the * UserCommentsAndRatingsController to work with user comments. - * + * * @param ureq * @param wControl * @param parentComment @@ -82,7 +82,7 @@ public class UserCommentFormController extends FormBasicController { this.ores = ores; this.resSubPath = resSubPath; commentAndRatingService = CoreSpringFactory.getImpl(CommentAndRatingService.class); - + this.parentComment = parentComment; this.toBeUpdatedComment = toBeUpdatedComment; // @@ -139,26 +139,26 @@ public class UserCommentFormController extends FormBasicController { if (toBeUpdatedComment == null) { if (parentComment == null) { // create new comment - toBeUpdatedComment = commentAndRatingService.createComment(getIdentity(), ores, resSubPath, commentText); + toBeUpdatedComment = commentAndRatingService.createComment(getIdentity(), ores, resSubPath, commentText); // notify listeners that we finished. - fireEvent(ureq, Event.CHANGED_EVENT); + fireEvent(ureq, Event.CHANGED_EVENT); } else { // reply to parent comment toBeUpdatedComment = commentAndRatingService.replyTo(parentComment, getIdentity(), commentText); if (toBeUpdatedComment == null) { showError("comments.coment.reply.error"); - fireEvent(ureq, Event.FAILED_EVENT); + fireEvent(ureq, Event.FAILED_EVENT); } else { - fireEvent(ureq, Event.CHANGED_EVENT); + fireEvent(ureq, Event.CHANGED_EVENT); } } } else { toBeUpdatedComment = commentAndRatingService.updateComment(toBeUpdatedComment, commentText); if (toBeUpdatedComment == null) { - showError("comments.coment.update.error"); - fireEvent(ureq, Event.FAILED_EVENT); + showError("comments.coment.update.error"); + fireEvent(ureq, Event.FAILED_EVENT); } else { - fireEvent(ureq, Event.CHANGED_EVENT); + fireEvent(ureq, Event.CHANGED_EVENT); } } } diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentsAndRatingsController.java b/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentsAndRatingsController.java index d93c7f2171ff7ee098c0c6ebb51c007762b20e55..c452bc261172854f1e79f289fd858da81a0d84eb 100644 --- a/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentsAndRatingsController.java +++ b/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentsAndRatingsController.java @@ -218,7 +218,7 @@ public class UserCommentsAndRatingsController extends BasicController implements * * @return */ - long getCommentsCount() { + public long getCommentsCount() { if (commentsCount != null) { return commentsCount.longValue(); } else { diff --git a/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml b/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml index 4d026f0150bc0244395a4e726bd34e5e2687f387..3eeefcd69a1fe89539b3235b3ef5cce9d201a7ed 100644 --- a/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml +++ b/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml @@ -14,7 +14,6 @@ <bean id="org.olat.course.nodes.ta.SolutionFileUploadNotificationHandler" class="org.olat.course.nodes.ta.SolutionFileUploadNotificationHandler"/> <bean id="org.olat.modules.wiki.WikiPageChangeOrCreateNotificationHandler" class="org.olat.modules.wiki.WikiPageChangeOrCreateNotificationHandler" /> <bean id="org.olat.user.notification.NewUsersNotificationHandler" class="org.olat.user.notification.NewUsersNotificationHandler" /> - <bean id="org.olat.commons.info.notification.InfoMessageNotificationHandler" class="org.olat.commons.info.notification.InfoMessageNotificationHandler" /> <bean id="notificationsManager" class="org.olat.core.commons.services.notifications.manager.NotificationsManagerImpl" > <property name="dbInstance" ref="database"/> @@ -63,7 +62,7 @@ is 10min after midnight. --> - <bean id="sendNotificationsEmailTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="sendNotificationsEmailTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="org.olat.notifications.job.${cluster.singleton.services}" /> <!-- adjust cron style syntax for your notification needs "0 10 0 * *" e.g. 10 minutes after midnight @@ -87,12 +86,12 @@ <property name="startDelay" value="300000" /> </bean> - <bean id="org.olat.notifications.job.enabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="org.olat.notifications.job.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.core.commons.services.notifications.manager.EmailNotificationJob" /> </bean> <!-- dummy bean --> - <bean id="org.olat.notifications.job.disabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="org.olat.notifications.job.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" /> </bean> diff --git a/src/main/java/org/olat/core/commons/services/notifications/restapi/NotificationsWebService.java b/src/main/java/org/olat/core/commons/services/notifications/restapi/NotificationsWebService.java index 9df1fb79ce329d53af4e518a623d55b8706b2cc9..001f7bd92e8a05c6c51a40a4d5c2afa4c7d5d0e5 100644 --- a/src/main/java/org/olat/core/commons/services/notifications/restapi/NotificationsWebService.java +++ b/src/main/java/org/olat/core/commons/services/notifications/restapi/NotificationsWebService.java @@ -1,4 +1,6 @@ /** + + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -21,12 +23,9 @@ package org.olat.core.commons.services.notifications.restapi; import static org.olat.restapi.security.RestSecurityHelper.isAdmin; +import static org.olat.restapi.security.RestSecurityHelper.parseDate; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Locale; @@ -241,49 +240,4 @@ public class NotificationsWebService { } return infoVO; } - - private Date parseDate(String date, Locale locale) { - if(StringHelper.containsNonWhitespace(date)) { - if(date.indexOf('T') > 0) { - if(date.indexOf('.') > 0) { - try { - return new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.S").parse(date); - } catch (ParseException e) { - //fail silently - } - } else { - try { - return new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss").parse(date); - } catch (ParseException e) { - //fail silently - } - } - } - - //try with the locale - if(date.length() > 10) { - //probably date time - try { - DateFormat format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale); - format.setLenient(true); - return format.parse(date); - } catch (ParseException e) { - //fail silently - } - } else { - try { - DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); - format.setLenient(true); - return format.parse(date); - } catch (ParseException e) { - //fail silently - } - } - } - - Calendar cal = Calendar.getInstance(); - cal.setTime(new Date()); - cal.add(Calendar.MONTH, -1); - return cal.getTime(); - } } diff --git a/src/main/java/org/olat/core/commons/services/notifications/ui/DateChooserController.java b/src/main/java/org/olat/core/commons/services/notifications/ui/DateChooserController.java index c96d5595edcfdd1889f505f6b6fb793ad5e3dad6..97888b317a3c558ff61d212e09e0304473d31f18 100644 --- a/src/main/java/org/olat/core/commons/services/notifications/ui/DateChooserController.java +++ b/src/main/java/org/olat/core/commons/services/notifications/ui/DateChooserController.java @@ -80,8 +80,7 @@ public class DateChooserController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { dateChooser = uifactory.addDateChooser("news.since", null, formLayout); - //FIXME: Can't use time format for now, only date format due to bug OLAT-4736 - // dateChooser.setDateChooserTimeEnabled(true); + dateChooser.setDate(initDate); dateChooser.addActionListener(FormEvent.ONCHANGE); diff --git a/src/main/java/org/olat/core/commons/services/notifications/ui/NotificationNewsController.java b/src/main/java/org/olat/core/commons/services/notifications/ui/NotificationNewsController.java index 05a8e28b1ae2efea20548df3db74e7a64ef72c35..ec661492981e47069ab9e6797d5a60dcb36009bb 100644 --- a/src/main/java/org/olat/core/commons/services/notifications/ui/NotificationNewsController.java +++ b/src/main/java/org/olat/core/commons/services/notifications/ui/NotificationNewsController.java @@ -28,6 +28,7 @@ import java.util.Date; import java.util.List; import java.util.Map; +import org.olat.commons.calendar.CalendarUtils; import org.olat.core.commons.services.notifications.NotificationHelper; import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.commons.services.notifications.Subscriber; @@ -92,13 +93,14 @@ public class NotificationNewsController extends BasicController implements } else { compareDate = newsSinceDate; } + compareDate = CalendarUtils.removeTime(compareDate); + // Main view is a velocity container newsVC = createVelocityContainer("notificationsNews"); // Fetch data from DB and update datamodel and reuse subscribers List<Subscriber> subs = updateNewsDataModel(); // Add date and type chooser - dateChooserCtr = new DateChooserController(ureq, getWindowControl(), - new Date()); + dateChooserCtr = new DateChooserController(ureq, getWindowControl(), compareDate); dateChooserCtr.setSubscribers(subs); listenTo(dateChooserCtr); newsVC.put("dateChooserCtr", dateChooserCtr.getInitialComponent()); @@ -136,6 +138,7 @@ public class NotificationNewsController extends BasicController implements * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, * org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) */ + @Override protected void event(UserRequest ureq, Controller source, Event event) { if (source == dateChooserCtr) { if (event == Event.CHANGED_EVENT) { diff --git a/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml b/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml index d570acedcfb0675694ba3a3404c046456fa08aa6..4b243b1dd46e1a7b113e9fb9f45405de5860c656 100644 --- a/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml +++ b/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml @@ -16,8 +16,8 @@ to the MBeanExporter Bean at the end. How to add a new job: 1. Create you class which extends from QuartzJobBean see ChangePresenceJob as example 2. Create a file called "olatextconfig.xml" with your own beans and place it in the same directory as this file. It will be loaded automatically. -3. Add a bean definition where your job is created like ="<bean id="changePresenceJob" class="org.springframework.scheduling.quartz.JobDetailBean">" -4. Create a scheduler for your definded bean: Either an SimpleTriggerBean or an CronTriggerBean +3. Add a bean definition where your job is created like ="<bean id="changePresenceJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">" +4. Create a scheduler for your definded bean: Either an SimpleTriggerFactoryBean or an CronTriggerFactoryBean 5. Add your trigger bean to the SchedulerFactoryBean list. --> @@ -35,7 +35,6 @@ How to add a new job: <list> <!-- Include every bean here that should be scheduled --> <ref bean="sendNotificationsEmailTrigger" /> - <!-- <ref bean="dumpJMXJobTrigger"/> --> <ref bean="adobeCleanupJob"/> <ref bean="updateStatisticsTrigger"/> <ref bean="searchIndexingTrigger"/> @@ -52,6 +51,7 @@ How to add a new job: <ref bean="reminderTrigger"/> <ref bean="videoTranscodingTrigger"/> <ref bean="automaticLifecycleTrigger"/> + <ref bean="calendarImportTrigger"/> <ref bean="autoCloseLecturesTrigger"/> <ref bean="reminderLecturesTrigger"/> </list> @@ -60,50 +60,19 @@ How to add a new job: <!-- add referenced schedulers here --> -<!-- Only needed in cluster mode, dumps jmx info to disc --> -<bean id="dumpJMXJobTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> - <property name="jobDetail" ref="dumpJMXJob" /> - <!-- 5 minute --> - <property name="startDelay" value="300000" /> - <!-- repeat every 10 seconds (dmps the data to disk) --> - <property name="repeatInterval" value="60000" /> -</bean> - <!-- Example bean for cron style scheduling--> <!-- OLAT-5093 start delay ensures there's no conflict with server startup and db not being ready yet --> <!-- -<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> +<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="exampleJob" /> <property name="cronExpression" value="0 0 6 * * ?" /> <property name="startDelay" value="300000" /> </bean> --> - -<!-- job definition --> -<bean id="dumpJMXJob" class="org.springframework.scheduling.quartz.JobDetailBean"> - <property name="jobClass" value="org.olat.admin.jmx.DumpJMXJob"/> - <property name="jobDataAsMap"> - <map> - <!-- either true or false --> - <!-- TODO:gs make configurable via olat.properties file --> - <entry key="enabled" value="false" /> - <!-- List of dumping beans, key must end with 'Bean' --> - <entry key="ThreadAndControllerInfoBean" value="org.olat.admin.jmx.datasources:name=ThreadAndControllerInfo" /> - <entry key="FilesInfoMBean" value="org.olat.core.commons.modules.bc:name=FilesInfoMBean" /> - </map> - </property> -</bean> - -<!-- - Export your Beans via JMX, to enable start you JVM with "-Dcom.sun.management.jmxremote=true". - This only enables JMX locally and allows you to connect with the same user. To connect via remote read: - http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html ---> - <!-- SEARCH INDEXING CONFIGURATION --> - <bean id="searchIndexingTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="searchIndexingTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="org.olat.search.job.${search.indexing.cronjob}" /> <property name="cronExpression" ref="searchIndexCronGenerator" /> <!-- OLAT-5093 start delay ensures there's no conflict with server startup and db not being ready yet --> @@ -116,12 +85,12 @@ How to add a new job: <property name="cronExpression" value="${search.indexing.cronjob.expression}" /> </bean> - <bean id="org.olat.search.job.enabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="org.olat.search.job.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.search.service.indexer.SearchIndexingJob"/> </bean> <!-- dummy bean --> - <bean id="org.olat.search.job.disabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="org.olat.search.job.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <!-- NOTE: reusing the notifications.DummyJob here --> <property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" /> </bean> diff --git a/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_pl.properties new file mode 100644 index 0000000000000000000000000000000000000000..843e0ce7b368c787de861e2a8115bb1c24438106 --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_pl.properties @@ -0,0 +1,28 @@ +#Thu Jul 27 15:09:10 CEST 2017 +admin.configuration.description=<p>Powiadomienie SMS jest komponentem opcjonalnym.</p><p>Uwaga\: Mog\u0105 zosta\u0107 poniesione dodatkowe koszty za wysy\u0142anie SMS\!</p> +admin.configuration.title=Konfiguracja SMS +admin.enable=Wysy\u0142anie wiadomo\u015Bci SMS +admin.menu.title=SMS +admin.menu.title.alt=Konfiguracja i statystyki SMS +admin.settings=Konfiguracja serwisu SMS +admin.statistics=Wysy\u0142anie wiadomo\u015Bci SMS +confirm.sms.phone=<h3>Uwierzytelnianie SMS</h3><p>System pozwala na uwierzytelnianie poprzez SMS w przypadku resetowania zapomnianego has\u0142a. Wpisz sw\u00F3j numer telefonu kom\u00F3rkowego w celu aktywacji tej us\u0142ugi.</p> +dont.activate=Nie aktywuj +error.invalid.token=Kod jest nieprawid\u0142owy. +error.phone.invalid=Niepoprawny numer telefonu (np. +41 12 345 67 89) +on=w\u0142\u0105czony +on.sms=z kodem SMS +reset.password=Resetuj has\u0142o +service=Us\u0142uga +sms.phone.number=Telefon kom\u00F3rkowy +sms.phone.number.example=Musisz wpisa\u0107 numer telefonu w formacie mi\u0119dzynarodowym (np. +41 12 345 67 89). +sms.phone.number.hint=+41 12 345 67 89 +sms.send=Rozpocznij uwierzytelnianie przez SMS +sms.token=Tw\u00F3j kod to {0} +sms.token.number=Kod +sms.token.number.explain=Wprowad\u017A 6 cyfrowy kod, kt\u00F3ry zosta\u0142 wys\u0142any SMS-em. Je\u015Bli SMS z kodem nie dotar\u0142 do Ciebie w przeci\u0105gu 1 minuty, sprawd\u017A czy numer Twojego telefonu zosta\u0142 wpisany prawid\u0142owo w standardzie mi\u0119dzynarodowym. +start.sms.authentication=Rozpocznij uwierzytelnianie przez SMS +table.header.month=miesi\u0105c +table.header.numOfMessages=SMS +table.header.year=rok +warning.spi.not.configured=Us\u0142uga nie jest skonfigurowana. diff --git a/src/main/java/org/olat/core/commons/services/taskexecutor/_spring/taskExecutorCorecontext.xml b/src/main/java/org/olat/core/commons/services/taskexecutor/_spring/taskExecutorCorecontext.xml index 3dfedfa0560ed36c09f25c77e132013113ff8806..564f9696967c031b755ea1b5affb94ecb83612fe 100644 --- a/src/main/java/org/olat/core/commons/services/taskexecutor/_spring/taskExecutorCorecontext.xml +++ b/src/main/java/org/olat/core/commons/services/taskexecutor/_spring/taskExecutorCorecontext.xml @@ -34,13 +34,13 @@ </bean> <!-- Persistent task executor job --> - <bean id="taskExecutorTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="taskExecutorTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="taskExecutorJob" /> <!-- every day at 1:21 --> <property name="cronExpression" value="10 */5 * * * ?" /> <property name="startDelay" value="60000" /> </bean> - <bean id="taskExecutorJob" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="taskExecutorJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.core.commons.services.taskexecutor.manager.ExecutorJob" /> </bean> diff --git a/src/main/java/org/olat/core/commons/services/taskexecutor/manager/TaskExecutorManagerImpl.java b/src/main/java/org/olat/core/commons/services/taskexecutor/manager/TaskExecutorManagerImpl.java index 777d9f829bb60f8afdcae7aa1b71c37d29de441c..b014f529c679490448d90152cb207989aad0db2c 100644 --- a/src/main/java/org/olat/core/commons/services/taskexecutor/manager/TaskExecutorManagerImpl.java +++ b/src/main/java/org/olat/core/commons/services/taskexecutor/manager/TaskExecutorManagerImpl.java @@ -46,7 +46,7 @@ import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.manager.BasicManager; import org.olat.resource.OLATResource; -import org.quartz.JobDetail; +import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; @@ -150,8 +150,7 @@ public class TaskExecutorManagerImpl extends BasicManager implements TaskExecuto @Override public void executeTaskToDo() { try { - JobDetail detail = scheduler.getJobDetail("taskExecutorJob", Scheduler.DEFAULT_GROUP); - scheduler.triggerJob(detail.getName(), detail.getGroup()); + scheduler.triggerJob(new JobKey("taskExecutorJob", Scheduler.DEFAULT_GROUP)); } catch (SchedulerException e) { log.error("", e); } diff --git a/src/main/java/org/olat/core/commons/services/taskexecutor/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/commons/services/taskexecutor/ui/_i18n/LocalStrings_pl.properties new file mode 100644 index 0000000000000000000000000000000000000000..3a7f61c0d3be65b506b727842b014e572e5d05b5 --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/taskexecutor/ui/_i18n/LocalStrings_pl.properties @@ -0,0 +1,6 @@ +#Thu Jul 27 15:10:48 CEST 2017 +done=Gotowe +edition=Zmieniono +failed=B\u0142\u0105d +inWork=W trakcie +newTask=Oczekuje diff --git a/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVAuthManager.java b/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVAuthManager.java index ec28f37f574d9e7d6a9e681d507e895d39f22691..589bb4e4844249d5d821d759f6265881f473ad53 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVAuthManager.java +++ b/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVAuthManager.java @@ -20,6 +20,9 @@ package org.olat.core.commons.services.webdav.manager; +import java.util.ArrayList; +import java.util.List; + import org.olat.basesecurity.Authentication; import org.olat.basesecurity.BaseSecurity; import org.olat.core.commons.services.webdav.WebDAVModule; @@ -49,7 +52,11 @@ import org.springframework.stereotype.Service; public class WebDAVAuthManager implements AuthenticationSPI { public static final String PROVIDER_WEBDAV = "WEBDAV"; + public static final String PROVIDER_WEBDAV_EMAIL = "WEBDAV-E"; + public static final String PROVIDER_WEBDAV_INSTITUTIONAL_EMAIL = "WEBDAV-I"; public static final String PROVIDER_HA1 = "HA1"; + public static final String PROVIDER_HA1_EMAIL = "HA1-E"; + public static final String PROVIDER_HA1_INSTITUTIONAL_EMAIL = "HA1-I"; private static final OLog log = Tracing.createLoggerFor(WebDAVAuthManager.class); @@ -65,25 +72,31 @@ public class WebDAVAuthManager implements AuthenticationSPI { public Identity digestAuthentication(String httpMethod, DigestAuthentication digestAuth) { String username = digestAuth.getUsername(); - Authentication olatAuth = securityManager.findAuthenticationByAuthusername(username, WebDAVAuthManager.PROVIDER_HA1); - if(olatAuth != null) { - if("auth".equals(digestAuth.getQop())) { - String nonce = digestAuth.getNonce(); - String response = digestAuth.getResponse(); - - String ha1 = olatAuth.getCredential(); - - String a2 = httpMethod + ":" + digestAuth.getUri(); - String ha2 = Encoder.md5hash(a2); - - String ver = ha1 + ":" + nonce + ":" + digestAuth.getNc() + ":" + digestAuth.getCnonce() + ":" + digestAuth.getQop() + ":" + ha2; - String verity = Encoder.md5hash(ver); - if(verity.equals(response)) { - Identity identity = olatAuth.getIdentity(); - return identity; - } else if(log.isDebug()) { - // don't log as error, happens all the time with certain clients, e.g. Microsoft-WebDAV-MiniRedir - log.debug("Verity::" + verity + " doesn't equals response::" + response); + List<String> providers = new ArrayList<>(3); + providers.add(PROVIDER_HA1); + providers.add(PROVIDER_HA1_EMAIL); + providers.add(PROVIDER_HA1_INSTITUTIONAL_EMAIL); + + List<Authentication> authentications = securityManager.findAuthenticationByAuthusername(username, providers); + if(authentications != null && authentications.size() > 0) { + for(Authentication authentication:authentications) { + if("auth".equals(digestAuth.getQop())) { + String nonce = digestAuth.getNonce(); + String response = digestAuth.getResponse(); + + String ha1 = authentication.getCredential(); + + String a2 = httpMethod + ":" + digestAuth.getUri(); + String ha2 = Encoder.md5hash(a2); + + String ver = ha1 + ":" + nonce + ":" + digestAuth.getNc() + ":" + digestAuth.getCnonce() + ":" + digestAuth.getQop() + ":" + ha2; + String verity = Encoder.md5hash(ver); + if(verity.equals(response)) { + return authentication.getIdentity(); + } else if(log.isDebug()) { + // don't log as error, happens all the time with certain clients, e.g. Microsoft-WebDAV-MiniRedir + log.debug("Verity::" + verity + " doesn't equals response::" + response); + } } } } @@ -92,30 +105,37 @@ public class WebDAVAuthManager implements AuthenticationSPI { @Override public Identity authenticate(Identity identity, String login, String password) { - Authentication authentication = null; + List<String> providers = new ArrayList<>(3); + providers.add(PROVIDER_WEBDAV); + providers.add(PROVIDER_WEBDAV_EMAIL); + providers.add(PROVIDER_WEBDAV_INSTITUTIONAL_EMAIL); + + List<Authentication> authentications = null; if (identity != null) { - authentication = securityManager.findAuthentication(identity, PROVIDER_WEBDAV); + authentications = securityManager.findAuthentications(identity, providers); } else { - authentication = securityManager.findAuthenticationByAuthusername(login, PROVIDER_WEBDAV); + authentications = securityManager.findAuthenticationByAuthusername(login, providers); } - if(authentication == null) { + if(authentications == null || authentications.isEmpty()) { //fallback to standard OLAT authentication return olatAuthenticationSpi.authenticate(identity, login, password); } - Identity authenticatedIdentity = authentication.getIdentity(); + Identity authenticatedIdentity = authentications.get(0).getIdentity(); boolean visible = securityManager.isIdentityVisible(authenticatedIdentity); if (!visible) { return null; } - if (securityManager.checkCredentials(authentication, password)) { - Algorithm algorithm = Algorithm.find(authentication.getAlgorithm()); - if(Algorithm.md5.equals(algorithm)) { - authentication = securityManager.updateCredentials(authentication, password, loginModule.getDefaultHashAlgorithm()); + for(Authentication authentication:authentications) { + if (securityManager.checkCredentials(authentication, password)) { + Algorithm algorithm = Algorithm.find(authentication.getAlgorithm()); + if(Algorithm.md5.equals(algorithm)) { + authentication = securityManager.updateCredentials(authentication, password, loginModule.getDefaultHashAlgorithm()); + } + return authentication.getIdentity(); } - return authentication.getIdentity(); } return null; } @@ -123,12 +143,8 @@ public class WebDAVAuthManager implements AuthenticationSPI { @Override public void upgradePassword(Identity identity, String login, String password) { if(webDAVModule.isEnabled() && webDAVModule.isDigestAuthenticationEnabled()) { - Authentication digestAuth = securityManager.findAuthentication(identity, PROVIDER_HA1); - if(digestAuth == null) { - String digestToken = login + ":" + WebDAVManagerImpl.BASIC_AUTH_REALM + ":" + password; - Identity reloadedIdentity = securityManager.loadIdentityByKey(identity.getKey()); - securityManager.createAndPersistAuthentication(reloadedIdentity, PROVIDER_HA1, login, digestToken, Encoder.Algorithm.md5_noSalt); - } + List<Authentication> digestAuths = securityManager.getAuthentications(identity); + updateDigestPasswords(identity, identity, password, digestAuths); } } @@ -140,27 +156,51 @@ public class WebDAVAuthManager implements AuthenticationSPI { * @return True upon success. */ public boolean changePassword(Identity doer, Identity identity, String newPwd) { - if (doer==null) throw new AssertException("password changing identity cannot be undefined!"); - if (identity == null || identity.getKey() == null) + if (doer==null) { + throw new AssertException("password changing identity cannot be undefined!"); + } + if (identity == null || identity.getKey() == null) { throw new AssertException("cannot change password on a nonpersisted identity"); + } //For Basic - Authentication auth = securityManager.findAuthentication(identity, PROVIDER_WEBDAV); - if (auth == null) { // create new authentication for provider OLAT + List<Authentication> auths = securityManager.getAuthentications(identity); + updateWebdavPassword(doer, identity, newPwd, auths); + //For Digest + changeDigestPassword(doer, identity, newPwd); + return true; + } + + private void updateWebdavPassword(Identity doer, Identity identity, String password, List<Authentication> authentications) { + updateWebDAVPassword(doer, identity, identity.getName(), password, PROVIDER_WEBDAV, authentications); + if(identity.getUser().getEmail() != null) { + updateWebDAVPassword(doer, identity, identity.getUser().getEmail(), password, PROVIDER_WEBDAV_EMAIL, authentications); + } + if(identity.getUser().getInstitutionalEmail() != null) { + updateWebDAVPassword(doer, identity, identity.getUser().getEmail(), password, PROVIDER_WEBDAV_INSTITUTIONAL_EMAIL, authentications); + } + + for(Authentication authentication:authentications) { + if(authentication.getProvider().startsWith(PROVIDER_WEBDAV)) { + securityManager.deleteAuthentication(authentication); + } + } + } + + private void updateWebDAVPassword(Identity doer, Identity identity, String authUsername, String password, + String provider, List<Authentication> authentications) { + Authentication authentication = getAndRemoveAuthentication(provider, authentications); + if (authentication == null) { // create new authentication for provider OLAT Identity reloadedIdentity = securityManager.loadIdentityByKey(identity.getKey()); - auth = securityManager.createAndPersistAuthentication(reloadedIdentity, PROVIDER_WEBDAV, identity.getName(), newPwd, loginModule.getDefaultHashAlgorithm()); - log.audit(doer.getName() + " created new WebDAV authentication for identity: " + identity.getName()); + securityManager.createAndPersistAuthentication(reloadedIdentity, provider, authUsername, password, loginModule.getDefaultHashAlgorithm()); + log.audit(doer.getName() + " created new WebDAV authentication for identity: " + identity.getKey() + " (" + authUsername + ")"); } else { - auth = securityManager.updateCredentials(auth, newPwd, loginModule.getDefaultHashAlgorithm()); - log.audit(doer.getName() + " set new WebDAV password for identity: " +identity.getName()); + securityManager.updateCredentials(authentication, password, loginModule.getDefaultHashAlgorithm()); + log.audit(doer.getName() + " set new WebDAV password for identity: " + identity.getKey() + " (" + authUsername + ")"); } - - //For Digest - changeDigestPassword(doer, identity, identity.getName(), newPwd); - return true; } - public boolean changeDigestPassword(Identity doer, Identity identity, String username, String newPwd) { + public boolean changeDigestPassword(Identity doer, Identity identity, String newPwd) { if (doer == null) { throw new AssertException("password changing identity cannot be undefined!"); } @@ -170,22 +210,57 @@ public class WebDAVAuthManager implements AuthenticationSPI { //For Digest if(webDAVModule.isDigestAuthenticationEnabled()) { - Authentication authHa1 = securityManager.findAuthentication(identity, PROVIDER_HA1); - String digestToken = username + ":" + WebDAVManagerImpl.BASIC_AUTH_REALM + ":" + newPwd; + List<Authentication> ha1Authentications = securityManager.getAuthentications(identity); + updateDigestPasswords(doer, identity, newPwd, ha1Authentications); + } + return true; + } + + private void updateDigestPasswords(Identity doer, Identity identity, String newPwd, + List<Authentication> authentications) { + updateDigestPassword(doer, identity, identity.getName(), newPwd, PROVIDER_HA1, authentications); + if(identity.getUser().getEmail() != null) { + updateDigestPassword(doer, identity, identity.getUser().getEmail(), newPwd, PROVIDER_HA1_EMAIL, authentications); + } + if(identity.getUser().getInstitutionalEmail() != null) { + updateDigestPassword(doer, identity, identity.getUser().getEmail(), newPwd, PROVIDER_HA1_INSTITUTIONAL_EMAIL, authentications); + } + + for(Authentication authentication:authentications) { + if(authentication.getProvider().startsWith(PROVIDER_HA1)) { + securityManager.deleteAuthentication(authentication); + } + } + } + + private void updateDigestPassword(Identity doer, Identity identity, String authUsername, String password, + String provider, List<Authentication> authentications) { + String digestToken = authUsername + ":" + WebDAVManagerImpl.BASIC_AUTH_REALM + ":" + password; + Authentication authHa1 = getAndRemoveAuthentication(provider, authentications); + if (authHa1 == null) { // create new authentication for provider OLAT + Identity reloadedIdentity = securityManager.loadIdentityByKey(identity.getKey()); + securityManager.createAndPersistAuthentication(reloadedIdentity, provider, authUsername, digestToken, Encoder.Algorithm.md5_noSalt); + log.audit(doer.getName() + " created new WebDAV (HA1) authentication for identity: " + identity.getKey() + " (" + authUsername + ")"); + } else { String md5DigestToken = Encoder.encrypt(digestToken, null, Encoder.Algorithm.md5_noSalt); - - if (authHa1 == null) { // create new authentication for provider OLAT - Identity reloadedIdentity = securityManager.loadIdentityByKey(identity.getKey()); - authHa1 = securityManager.createAndPersistAuthentication(reloadedIdentity, PROVIDER_HA1, username, digestToken, Encoder.Algorithm.md5_noSalt); - log.audit(doer.getName() + " created new WebDAV (HA1) authenticatin for identity: " + identity.getName()); - } else if (username != null && (!username.equals(authHa1.getAuthusername()) || !md5DigestToken.equals(authHa1.getCredential()))) { + if (!md5DigestToken.equals(authHa1.getCredential()) || !authHa1.getAuthusername().equals(authUsername)) { authHa1.setCredential(md5DigestToken); - authHa1.setAuthusername(username); - authHa1 = securityManager.updateAuthentication(authHa1); - log.audit(doer.getName() + " set new WebDAV (HA1) password for identity: " +identity.getName()); + authHa1.setAuthusername(authUsername); + securityManager.updateAuthentication(authHa1); + log.audit(doer.getName() + " set new WebDAV (HA1) password for identity: " + identity.getKey() + " (" + authUsername + ")"); } } - - return true; + } + + private Authentication getAndRemoveAuthentication(String provider, List<Authentication> authentications) { + if(authentications != null && authentications.size() > 0) { + for(Authentication authentication:authentications) { + if(provider.equals(authentication.getProvider())) { + authentications.remove(authentication); + return authentication; + } + } + } + return null; } } diff --git a/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_pl.properties new file mode 100644 index 0000000000000000000000000000000000000000..7bbde4c15ced470d0deb8ec87e134d73304799e4 --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_pl.properties @@ -0,0 +1,12 @@ +#Thu Jul 27 15:20:19 CEST 2017 +admin.menu.title=WebDAV +admin.menu.title.alt=Dost\u0119p WebDAV +admin.webdav.description=U\u017Cywaj\u0105c WebDAV, mo\u017Cesz montowa\u0107 i u\u017Cywa\u0107 folder\u00F3w OpenOLAT na swoim komputerze, tak jakby to by\u0142y lokalne foldery. W\u0142\u0105cz to rozszerzenie, je\u017Celi chcesz udost\u0119pni\u0107 taka mo\u017Cliwo\u015B\u0107 u\u017Cytkownikom Twojej platformy. Przeczytaj pomoc kontekstow\u0105. +core.webdav=WebDAV +webdav.digest=Szyfrowane uwierzytelnienie dla dost\u0119pu HTTP +webdav.for.learners.bookmarks=W\u0142\u0105cz dost\u0119p do kurs\u00F3w, kt\u00F3re u\u017Cytkownicy zaznaczyli jako ulubione. +webdav.for.learners.participants=W\u0142\u0105cz dost\u0119p do kurs\u00F3w, w kt\u00F3rych u\u017Cytkownik jest uczestnikiem lub opiekunem. +webdav.link=Poka\u017C linki WebDAV +webdav.module=Dost\u0119p WebDAV +webdav.on=w\u0142\u0105czony +webdav.termsfolders=Pogrupuj kursy po terminarzu semestr\u00F3w diff --git a/src/main/java/org/olat/core/configuration/AbstractOLATModule.java b/src/main/java/org/olat/core/configuration/AbstractOLATModule.java deleted file mode 100644 index 34b77371367393552c0cdbc187512fe2026f8985..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/configuration/AbstractOLATModule.java +++ /dev/null @@ -1,347 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ -package org.olat.core.configuration; - -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicInteger; - -import org.olat.core.gui.control.Event; -import org.olat.core.logging.LogDelegator; -import org.olat.core.logging.OLog; -import org.olat.core.logging.StartupException; -import org.olat.core.logging.Tracing; -import org.olat.core.util.StringHelper; -import org.olat.core.util.event.GenericEventListener; - -/** - * Description:<br> - * Default/abstract class with helper methods. <br> - * The abstract olat module features reading and writing of configuration - * properties to config and properties files. The idea is that the system can be - * configured with default values either in the config xml file or by providing - * reasonable default values directly in the module code. - * <p> - * The developer should provide a GUI for each value that can be configured at - * runtime without the need of rebooting the entire system. But this is up to - * the programmer who implements the setter methods for the config values. - * <p> - * The getter methods will load the configuration in the following order: - * <ol> - * <li> - * <code>olatdata/system/configuration/fully.qualified.ClassName.properties</code> - * </li> - * <li>falling back to<code>olat.local.properties</code></li> - * <li>falling back to<code>olat.properties</code></li> - * <li>falling back to default value defined in method call</li> - * </ol> - * The class does also provide save methods. Setting a config parameter will - * store it always in the user space config file - * <code>olatdata/system/configuration/fully.qualified.ClassName.properties</code> - * and not in the olat.properties, those are only the default values in case no - * other configuration. - * <p> - * To work properly in a cluster environment, the module will fire a - * ModuleConfiguratoinChangedEvent at the end of each save cycle. This event is - * catched automatically and the abstract method initFromChangedProperties() is - * called. - * <p> - * For more information on how the storing mechanism of the configuration works - * please have a look at the PersistedProperties class. - * <p> - * If you want to use the properties mechanism in a spring loaded class, use the - * PersistedProperties class directly to read/write your application - * configuration. - * <p> - * Initial Date: 01.10.2007 <br> - * - * @author Felix Jost, http://www.goodsolutions.ch - * @author Florian Gnägi, http://www.frentix.com - */ -public abstract class AbstractOLATModule extends LogDelegator implements GenericEventListener { - protected PersistedProperties moduleConfigProperties; - private Properties moduleDefaultConfig; - - public static final Map<Class<?>,AtomicInteger> starts = new HashMap<Class<?>,AtomicInteger>(); - - public AbstractOLATModule() { - if(!starts.containsKey(this.getClass())) { - starts.put(this.getClass(), new AtomicInteger(1)); - } else { - starts.get(this.getClass()).incrementAndGet(); - } - } - - public static void printStats() { - OLog logger = Tracing.createLoggerFor(AbstractOLATModule.class); - for(Map.Entry<Class<?>, AtomicInteger> entry:starts.entrySet()) { - if(entry.getValue().get() > 1) { - logger.info(entry.getValue().get() + " :: " + entry.getKey()); - } - } - } - - /** - * Initialize the module. Called by the spring framework at startup time - */ - public final void init(Properties moduleConfig) { - // Default module configuration from xml file - this.moduleDefaultConfig = moduleConfig; - // Let the module set the default properties - if (moduleConfigProperties == null) throw new StartupException("PersistedProperties is null. You have to set Persisted properties in spring config when you use abstractOlatModule!"); - initDefaultProperties(); - init(); - } - - public abstract void init(); - - - public abstract void setPersistedProperties(PersistedProperties persistedProperties); - - /** - * Called during module initialization to read the default values from the - * configuration and set them as config properties default. - */ - protected abstract void initDefaultProperties(); - - /** - * Called whenever the properties configuraton changed (e.g. on this or on another - * cluster node). The properties have been reloaded prior to when this method is executed. - */ - protected abstract void initFromChangedProperties(); - - - /** - * Return an int value for certain config-parameter. If the parameter does - * not exist, return the defaultValue. - * - * @param parameterName - * @param defaultValue - * @param - * @return The int value. - */ - protected int getIntConfigParameter(String parameterName, int defaultValue) { - String stringValue = moduleDefaultConfig.getProperty(parameterName); - if (StringHelper.containsNonWhitespace(stringValue)) { - try { - return Integer.parseInt(stringValue.trim()); - } catch (Exception ex) { - logWarn("Cannot parse to integer conf-parameter '" + parameterName + "', value=" + stringValue, null); - } - } - logInfo("Take default value for integer conf-parameter '" + parameterName + "', value=" + defaultValue, null); - return defaultValue; - } - - /** - * Return a string value for certain config-parameter. If the parameter does - * not exist, return the defaultValue. - * - * @param parameterName - * @param defaultValue - * @param - * @return The string value. Can be empty, but never null - */ - protected String getStringConfigParameter(String parameterName, String defaultValue, boolean allowEmptyString) { - String stringValue = moduleDefaultConfig.getProperty(parameterName); - if (stringValue != null) { - if (allowEmptyString || StringHelper.containsNonWhitespace(stringValue)) { - return stringValue.trim(); - } - } - logInfo("Take default value for String conf-parameter '" + parameterName + "', value=" + defaultValue, null); - return defaultValue; - } - - /** - * Return a boolean value for certain config-parameter. If the paramter does - * not exist, return the defaultValue. 'true' and 'enabled' return <code>true</code>, 'false' and 'disabled' return <code>false</code>. - * - * @param parameterName - * @param defaultValue - * @return - */ - protected boolean getBooleanConfigParameter(String parameterName, boolean defaultValue) { - String stringValue = moduleDefaultConfig.getProperty(parameterName); - if ((stringValue != null) && (stringValue.trim().equalsIgnoreCase("TRUE") || stringValue.trim().equalsIgnoreCase("ENABLED"))) { - return true; - } - if ((stringValue != null) && (stringValue.trim().equalsIgnoreCase("FALSE") || stringValue.trim().equalsIgnoreCase("DISABLED"))) { - return false; - } - logInfo("Take default Boolean conf-parameter '" + parameterName + "', value=" + stringValue - + ", only true/false supported => take default value.", null); - return defaultValue; - } - - // - // Delegate methods used to get and set the values and default in the user - // configuration using the persisted properties. - // - - /** - * Return a string value for certain propertyName-parameter. - * - * @param propertyName - * @param allowEmptyString - * true: empty strings are valid values; false: emtpy strings are - * discarded - * @return the value from the configuration or the default value or ""/NULL - * (depending on allowEmptyString flag) - */ - protected String getStringPropertyValue(String propertyName, boolean allowEmptyString) { - // delegate to new property based config style - return moduleConfigProperties.getStringPropertyValue(propertyName, allowEmptyString); - } - /** - * Set a string property - * - * @param propertyName - * The key - * @param value - * The Value - * @param saveConfiguration - * true: will save property and fire event; false: will not save, - * but set a dirty flag - */ - protected void setStringProperty(String propertyName, String value, boolean saveConfiguration) { - // delegate to new property based config style - moduleConfigProperties.setStringProperty(propertyName, value, saveConfiguration); - logAudit("change system property: " + propertyName, value); - } - /** - * Retrun an int value for a certain propertyName - * - * @param propertyName - * @return the value from the configuration or the default value or 0 - */ - protected int getIntPropertyValue(String propertyName) { - // delegate to new property based config style - return moduleConfigProperties.getIntPropertyValue(propertyName); - } - /** - * Set an int property - * - * @param propertyName - * The key - * @param value - * The Value - * @param saveConfiguration - * true: will save property and fire event; false: will not save, - * but set a dirty flag - */ - protected void setIntProperty(String propertyName, int value, boolean saveConfiguration) { - // delegate to new property based config style - moduleConfigProperties.setIntProperty(propertyName, value, saveConfiguration); - logAudit("change system property: " + propertyName, Integer.toString(value)); - } - /** - * Return a boolean value for certain propertyName - * - * @param propertyName - * @return the value from the configuration or the default value or false - */ - protected boolean getBooleanPropertyValue(String propertyName) { - // delegate to new property based config style - return moduleConfigProperties.getBooleanPropertyValue(propertyName); - } - /** - * Set a boolean property - * - * @param propertyName - * The key - * @param value - * The Value - * @param saveConfiguration - * true: will save property and fire event; false: will not save, - * but set a dirty flag - */ - protected void setBooleanProperty(String propertyName, boolean value, boolean saveConfiguration) { - // delegate to new property based config style - moduleConfigProperties.setBooleanProperty(propertyName, value, saveConfiguration); - logAudit("change system property: " + propertyName, Boolean.toString(value)); - } - /** - * Save the properties configuration to disk and notify other nodes about - * change. This is only done when there are dirty changes, otherwhile the - * method call does nothing. - */ - protected void savePropertiesAndFireChangedEvent() { - // delegate to new property based config style - moduleConfigProperties.savePropertiesAndFireChangedEvent(); - } - /** - * Clear the properties and save the empty properties to the file system. - */ - protected void clearAndSaveProperties() { - // delegate to new property based config style - moduleConfigProperties.clearAndSaveProperties(); - } - /** - * Set a default value for a string property - * @param propertyName - * @param value - */ - protected void setStringPropertyDefault(String key, String value){ - // delegate to new property based config style - moduleConfigProperties.setStringPropertyDefault(key, value); - } - /** - * Set a default value for a boolean property - * @param propertyName - * @param value - */ - protected void setBooleanPropertyDefault(String key, boolean value){ - // delegate to new property based config style - moduleConfigProperties.setBooleanPropertyDefault(key, value); - } - /** - * Set a default value for an integer property - * @param propertyName - * @param value - */ - protected void setIntPropertyDefault(String key, int value){ - // delegate to new property based config style - moduleConfigProperties.setIntPropertyDefault(key, value); - } - - /** - * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event) - */ - public void event(Event event) { - if (event instanceof PersistedPropertiesChangedEvent) { - PersistedPropertiesChangedEvent persistedPropertiesEvent = (PersistedPropertiesChangedEvent) event; - if (!persistedPropertiesEvent.isEventOnThisNode()) { - // Reload the module configuration from disk, only when event not fired by this node - moduleConfigProperties.loadPropertiesFromFile(); - } - // Call abstract method to initialize after the property changed, even when changes - // were triggered by this node. - initFromChangedProperties(); - } - } -} diff --git a/src/main/java/org/olat/core/configuration/PersistedProperties.java b/src/main/java/org/olat/core/configuration/PersistedProperties.java index 3164b8c69339200311d74479d50ecd595c31789b..56f976905051f40f5afcab6f7776683aa70bc1c7 100644 --- a/src/main/java/org/olat/core/configuration/PersistedProperties.java +++ b/src/main/java/org/olat/core/configuration/PersistedProperties.java @@ -471,8 +471,8 @@ public class PersistedProperties extends LogDelegator implements Initializable, if(secured) { SecretKey key = generateKey("rk6R9pQy7dg3usJk"); Cipher cipher = Cipher.getInstance("AES/CTR/NOPADDING"); - cipher.init(Cipher.ENCRYPT_MODE, key, generateIV(cipher), random); - fileStream = new CipherOutputStream(fileStream, cipher); + cipher.init(Cipher.ENCRYPT_MODE, key, generateIV(cipher), random); + fileStream = new CipherOutputStream(fileStream, cipher); } configuredProperties.store(fileStream, null); diff --git a/src/main/java/org/olat/core/configuration/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/configuration/_i18n/LocalStrings_pl.properties index edb279e2720ff42e8024e020e9a960b8e1e97aee..0ccb131620119f6122e6afa06e9abacf892a5f8d 100644 --- a/src/main/java/org/olat/core/configuration/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/core/configuration/_i18n/LocalStrings_pl.properties @@ -1,4 +1,4 @@ -#Fri Sep 17 11:39:18 CEST 2010 +#Thu Jul 27 15:20:42 CEST 2017 main.menu.title=Ustawienia -main.menu.title.alt=Ustawienia startowych parametr\u00F3w OLAT +main.menu.title.alt=Ustawienia parametr\u00F3w startowych OLAT overwrite.properties.not.found=Nie odnaleziono pliku olat.local.properties w \u015Bcie\u017Cce z klasami\! diff --git a/src/main/java/org/olat/core/gui/components/download/DisplayOrDownloadComponentRenderer.java b/src/main/java/org/olat/core/gui/components/download/DisplayOrDownloadComponentRenderer.java index 99a4a7328093c03399af7b1890c06933a7d56400..5680ada613829dc3cc9cae85b7b4665615ef4554 100644 --- a/src/main/java/org/olat/core/gui/components/download/DisplayOrDownloadComponentRenderer.java +++ b/src/main/java/org/olat/core/gui/components/download/DisplayOrDownloadComponentRenderer.java @@ -20,10 +20,9 @@ package org.olat.core.gui.components.download; import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.ComponentRenderer; +import org.olat.core.gui.components.DefaultComponentRenderer; import org.olat.core.gui.render.RenderResult; import org.olat.core.gui.render.Renderer; -import org.olat.core.gui.render.RenderingState; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; @@ -38,16 +37,8 @@ import org.olat.core.gui.translator.Translator; * * @author gnaegi */ -class DisplayOrDownloadComponentRenderer implements ComponentRenderer { +class DisplayOrDownloadComponentRenderer extends DefaultComponentRenderer { - /** - * @see org.olat.core.gui.components.ComponentRenderer#render(org.olat.core.gui.render.Renderer, - * org.olat.core.gui.render.StringOutput, - * org.olat.core.gui.components.Component, - * org.olat.core.gui.render.URLBuilder, - * org.olat.core.gui.translator.Translator, - * org.olat.core.gui.render.RenderResult, java.lang.String[]) - */ @Override public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator, RenderResult renderResult, String[] args) { @@ -63,30 +54,4 @@ class DisplayOrDownloadComponentRenderer implements ComponentRenderer { sb.append("</script>"); } } - - /** - * @see org.olat.core.gui.components.ComponentRenderer#renderBodyOnLoadJSFunctionCall(org.olat.core.gui.render.Renderer, - * org.olat.core.gui.render.StringOutput, - * org.olat.core.gui.components.Component, - * org.olat.core.gui.render.RenderingState) - */ - @Override - public void renderBodyOnLoadJSFunctionCall(Renderer renderer, StringOutput sb, Component source, RenderingState rstate) { - // no body on-load methods (must also work in non-ajax mode) - } - - /** - * @see org.olat.core.gui.components.ComponentRenderer#renderHeaderIncludes(org.olat.core.gui.render.Renderer, - * org.olat.core.gui.render.StringOutput, - * org.olat.core.gui.components.Component, - * org.olat.core.gui.render.URLBuilder, - * org.olat.core.gui.translator.Translator, - * org.olat.core.gui.render.RenderingState) - */ - @Override - public void renderHeaderIncludes(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator, - RenderingState rstate) { - // no header includes - } - } diff --git a/src/main/java/org/olat/core/gui/components/dropdown/DropdownItem.java b/src/main/java/org/olat/core/gui/components/dropdown/DropdownItem.java index dc52dc7ea88bf0288365086c0fd67a09d1a06500..b4f548e8ecc965975107207d72a6c944ce56fc18 100644 --- a/src/main/java/org/olat/core/gui/components/dropdown/DropdownItem.java +++ b/src/main/java/org/olat/core/gui/components/dropdown/DropdownItem.java @@ -56,6 +56,20 @@ public class DropdownItem extends FormItemImpl implements FormItemCollection { dropdown.setEmbbeded(embbeded); } + public DropdownOrientation getOrientation() { + return dropdown.getOrientation(); + } + + public void setOrientation(DropdownOrientation orientation) { + dropdown.setOrientation(orientation); + } + + @Override + public void setElementCssClass(String elementCssClass) { + dropdown.setElementCssClass(elementCssClass); + super.setElementCssClass(elementCssClass); + } + public void addElement(FormLink link) { items.add(link); diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/FormUIFactory.java b/src/main/java/org/olat/core/gui/components/form/flexible/FormUIFactory.java index 54a63f3da12d29cd753badafeb999c6e7d672839..c73b6c0d2c46ee59ff0ada99b272f8759f588dc3 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/FormUIFactory.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/FormUIFactory.java @@ -35,6 +35,7 @@ import org.olat.core.commons.controllers.linkchooser.CustomLinkTreeModel; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.ComponentEventListener; +import org.olat.core.gui.components.dropdown.DropdownItem; import org.olat.core.gui.components.form.flexible.elements.AutoCompleter; import org.olat.core.gui.components.form.flexible.elements.DateChooser; import org.olat.core.gui.components.form.flexible.elements.DownloadLink; @@ -811,6 +812,7 @@ public class FormUIFactory { rte.getEditorConfiguration().setExtendedValidElements("script[src|type|defer]"); rte.getEditorConfiguration().disableTinyMedia(); rte.getEditorConfiguration().setFilenameUriValidation(true); + rte.getEditorConfiguration().setFigCaption(false); // Add to form and finish formLayout.add(rte); return rte; @@ -828,6 +830,7 @@ public class FormUIFactory { rte.getEditorConfiguration().setExtendedValidElements("script[src|type|defer]"); rte.getEditorConfiguration().disableTinyMedia(); rte.getEditorConfiguration().setFilenameUriValidation(true); + rte.getEditorConfiguration().setFigCaption(false); // Add to form and finish formLayout.add(rte); return rte; @@ -1235,4 +1238,14 @@ public class FormUIFactory { formLayout.add(slider); return slider; } + + + public DropdownItem addDropdownMenu(String name, String i18nLabel, FormItemContainer formLayout, Translator translator) { + DropdownItem dropdown = new DropdownItem(name, name, translator); + dropdown.setEmbbeded(true); + dropdown.setButton(true); + setLabelIfNotNull(i18nLabel, dropdown); + formLayout.add(dropdown); + return dropdown; + } } diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/BasicFormFragment.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/BasicFormFragment.java deleted file mode 100644 index 1c8936b3137ca94b674ca75ce331ee9acd8f2b5d..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/BasicFormFragment.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.core.gui.components.form.flexible.impl; - -import org.olat.core.CoreSpringFactory; -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.form.flexible.FormItemContainer; -import org.olat.core.gui.components.form.flexible.FormUIFactory; -import org.olat.core.gui.control.Controller; -import org.olat.modules.IModuleConfiguration; - -/** - * Base class for implementing {@link IFormFragment} - * - * <p>Initial date: May 6, 2016 - * @author lmihalkovic, http://www.frentix.com - */ -public abstract class BasicFormFragment implements IFormFragment { - - protected IFormFragmentHost host; - protected IFormFragmentContainer container; - - public BasicFormFragment() { - CoreSpringFactory.autowireObject(this); - } - - @Override - public final void initFormFragment(UserRequest ureq, IFormFragmentContainer container, Controller listener, IModuleConfiguration config) { - FormItemContainer formLayout = container.formItemsContainer(); - - this.container = container; - this.host = container.getFragmentHostInterface(); - - initFormFragment(formLayout, listener, ureq, config); - } - - protected abstract void initFormFragment(FormItemContainer formLayout, Controller listener, UserRequest ureq, IModuleConfiguration config); - - protected FormUIFactory uifactory() { - return container.getFragmentHostInterface().getUIFactory(); - } - - @Override - public void readConfiguration(UserRequest ureq, IModuleConfiguration moduleConfiguration) { - // do nothing by default - } - -} diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java index f12ed9fa050eaffb54e457b8388f20928ed95a99..a5a7223ab0cade0182eb4bf6168b78e69e944120 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java @@ -25,11 +25,6 @@ */ package org.olat.core.gui.components.form.flexible.impl; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.FormItem; @@ -72,7 +67,7 @@ import org.olat.core.logging.activity.ThreadLocalUserActivityLoggerInstaller; * * @author patrickb */ -public abstract class FormBasicController extends BasicController implements IFormFragmentContainer { +public abstract class FormBasicController extends BasicController { public static final int LAYOUT_DEFAULT = 0; @@ -91,8 +86,6 @@ public abstract class FormBasicController extends BasicController implements IFo protected StackedPanel initialPanel; - private List<FragmentRef> fragments; - protected final FormUIFactory uifactory = FormUIFactory.getInstance(); public FormBasicController(UserRequest ureq, WindowControl wControl) { @@ -367,7 +360,6 @@ public abstract class FormBasicController extends BasicController implements IFo @Override protected void event(UserRequest ureq,Controller source, Event event) { - routeEventToFragments(ureq, source, event); super.event(ureq, source, event); } @@ -378,7 +370,6 @@ public abstract class FormBasicController extends BasicController implements IFo */ @Override public void event(UserRequest ureq, Component source, Event event) { - routeEventToFragments(ureq, source, event); if (source == mainForm.getInitialComponent()) { // general form events if (event == org.olat.core.gui.components.form.Form.EVNT_VALIDATION_OK) { @@ -649,126 +640,11 @@ public abstract class FormBasicController extends BasicController implements IFo disposableFormItem.dispose(); } } - - forEachFragment(fragment -> { - // do nothing for now - }); } }, getUserActivityLogger()); } - // ------------------------------------------------------------------------ - // IFormFragmentContainer implementation - - /** - * A lifecycle method used to signal the controller that it should read the contents - * of its configuration and apply it to its view. The idea is that the structure of a - * form can be created separately from assigning contents to its fields. - * <p>This is particularly useful when dealing with fragments which know how to - * load/store data from a given configuration themselves. - * @param ureq - */ - public void readFormData(UserRequest ureq) { - // do nothing by default - } - - /** - * A lifecycle used to signal the form controller that it should visit the view's - * content and save all relevant data into its current configuration. - * <p>This is particularly useful when dealing with fragments which know how to - * load/store data from a given configuration themselves. - * @param ureq - */ - public void storeFormData(UserRequest ureq) { - // do nothing by default - } - - @Override - public IFormFragmentHost getFragmentHostInterface() { - // this is to document the missing method implementation in a subclass - throw new IllegalStateException("In order to host from fragments the controller must override getFragmentHostInterface(): " + this.getClass().getSimpleName() ); - } - - private static class FragmentRef extends WeakReference<IFormFragment>{ - public FragmentRef(IFormFragment referent) { - super(referent); - } - } - - @Override public void setNeedsLayout() { flc.setDirty(true); } - - @Override - public void registerFormFragment(IFormFragment fragment) { - if(fragments == null) { - fragments = new ArrayList<>(5); - } - fragments.add(new FragmentRef(fragment)); - } - - @Override - public FormItemContainer formItemsContainer() { - return flc; - } - - // Helpers - @Override - protected void fireEvent(UserRequest ureq, Event event) { - super.fireEvent(ureq, event); - } - - // Redefinition of a the super method to provide access with the same - // package (this is required for the Form Fragments) - @Override - protected Controller listenTo(Controller controller) { - return super.listenTo(controller); - } - - @Override - public void forEachFragment(Consumer<IFormFragment> handler) { - if(fragments == null) return; - - fragments.stream() - .filter(ref -> ref.get() != null) - .forEach(ref -> { - IFormFragment frag = ref.get(); - if (frag != null) { - handler.accept(frag); - } - }); - } - - protected boolean routeEventToFragments(UserRequest ureq, Component source, Event event) { - if(fragments == null) return false; - - // implement shortcut?! - Boolean processed = - fragments.stream() - .reduce(Boolean.FALSE - , (t, u) -> { - IFormFragment frag = u.get(); - return frag == null ? Boolean.FALSE : frag.processEvent(ureq, source, event); - }, (t, u) -> t & u) - ; - return processed; - } - - - protected boolean routeEventToFragments(UserRequest ureq, Controller source, Event event) { - if(fragments == null) return false; - - // implement shortcut?! - Boolean processed = - fragments.stream() - .reduce(Boolean.FALSE - , (t, u) -> { - IFormFragment frag = u.get(); - return frag == null ? Boolean.FALSE : frag.processEvent(ureq, source, event); - }, (t, u) -> t & u) - ; - return processed; - } - } \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragment.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragment.java deleted file mode 100644 index 647b54c717051cd95fe6f4b60f2b8e9fd562e029..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragment.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.core.gui.components.form.flexible.impl; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.form.flexible.FormItem; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.Disposable; -import org.olat.core.gui.control.Event; -import org.olat.modules.IModuleConfiguration; - -/** - * A form fragment is a simple abstraction that allows composing {@code Form} instances from - * reusable groups of fields. This is a lighter weight level of reuse than to embed entire - * forms inside containing forms. In the case of fragments, there is a single controller - * managing multiple fragments. - * - * <p>Fragments are hosted by a {@link IFormFragmentContainer}. - * - * <p>Initial date: May 6, 2016<br> - * @author lmihalkovic, http://www.frentix.com - */ -public interface IFormFragment extends Disposable { - - // this is here for compatibility to help migrate chunks of existing code into fragments - default void initForm(IFormFragmentContainer container, Controller _listener, UserRequest ureq, IModuleConfiguration config) { - this.initFormFragment(ureq, container, _listener, config); - this.validateFormLogic(ureq); - } - - /** - * This method must be implemented by fragments however it is not recommended that form - * fragment hosts call it directly. Instead fragment hosts should directly call {@code initForm} - * which will ensure that all initialization is performed in a single step - * - * @param ureq - * @param formLayout - * @param listener - */ - void initFormFragment(UserRequest ureq, IFormFragmentContainer container, Controller listener, IModuleConfiguration config); - - /** - * @see FormBasicController#validateFormLogic(UserRequest) - * @return - */ - boolean validateFormLogic(UserRequest ureq); - - void readConfiguration(UserRequest ureq, IModuleConfiguration moduleConfiguration); - void storeConfiguration(UserRequest ureq, IModuleConfiguration moduleConfiguration); - - default void refreshContents() { - // do nothing by default - } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.control.Controller, - * org.olat.core.gui.control.Event) - * @return true if the event was processed, false otherwise - */ - default boolean processEvent(UserRequest ureq, Controller source, Event event) { - return false; - } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.components.Component, - * org.olat.core.gui.control.Event) - * @return true if the event was processed, false otherwise - */ - default boolean processEvent(UserRequest ureq, Component source, Event event) { - return false; - } - - /** - * called if an element inside of form triggered an event - * - * @param source - * @param event - * @return true if the event was processed, false otherwise - */ - default boolean processFormEvent(UserRequest ureq, FormItem source, FormEvent event) { - return false; - } - -} diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragmentContainer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragmentContainer.java deleted file mode 100644 index e66d1507071a6b0bd1982ceb06f0e06ed419877b..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragmentContainer.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.core.gui.components.form.flexible.impl; - -import java.util.function.Consumer; - -import org.olat.core.gui.components.form.flexible.FormItemContainer; - -/** - * Interface implemented by a visual element (usually a Form controller) that can contain - * one or more {@link IFormFragment} instances - * - * <p>Initial date: May 6, 2016<br> - * @author lmihalkovic, http://www.frentix.com - */ -public interface IFormFragmentContainer { - - /** - * Return an instance of the interface used - * @return - */ - default IFormFragmentHost getFragmentHostInterface() { - return null; - } - - /** - * Called by a hosted fragment to tell its container that the current presentation - * no longer accurately reflects the current internal state of the fragment. The - * container would generally use this information to trigger a re-evaluation of its - * layout - */ - void setNeedsLayout(); - - /** - * Used by the fragment in order to add contents to the visual presentation of the - * container - * - * @return - */ - FormItemContainer formItemsContainer(); - - /** - * Used for registering the existance of a fragment with the underlying form controller - * - * @param fragment - */ - void registerFormFragment(IFormFragment fragment); - - /** - * This method can be used to perform an operation on all the fragments currently hosted - * by this container - * - * @param handler - */ - void forEachFragment(Consumer<IFormFragment> handler); - -} diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragmentController.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragmentController.java deleted file mode 100644 index b0fa7d7b88e19d45f8c032389fa2840b8110f1a1..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragmentController.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.core.gui.components.form.flexible.impl; - -import java.util.function.Consumer; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.Event; -import org.olat.core.gui.control.WindowControl; - -/** - * A {@link IFormFragment} requires access to a controller. This interface represents the very - * minimal set of features it expects from its controller. This subset corresponds strictly with - * the features offered by a {@link FormBasicController} and in most cases the fragment controller - * will be the form controller itself. Nonetheless this interface is here to guaranty that a - * fragment will be truly reusable by isolating it from the internal details of more powerful - * form controller. - * - * <p>Initial date: May 6, 2016<br> - * @author lmihalkovic, http://www.frentix.com - */ -public interface IFormFragmentController { - void removeAsListenerAndDispose(Controller controller); - WindowControl getWindowControl(); - void listenTo(Controller controller); - void setFormCanSubmit(boolean canSubmit); - void fireEvent(UserRequest ureq, Event event); - - - /** - * A helper method to help adapt an existing {@link FormBasicController} instance to - * the subset of features exposed by a {@link IFormFragmentController}. - * - * @param delegate the form controller to be adapted - * @param canSubmitHandler a handler to be invoked when the fragment wants to change the overall readiness state of the form - * @return - */ - public static IFormFragmentController fragmentControllerAdapter(final FormBasicController delegate, final Consumer<Boolean> canSubmitHandler) { - return new IFormFragmentController() { - @Override - public void setFormCanSubmit(boolean canSubmit) { - canSubmitHandler.accept(canSubmit); - } - - @Override - public void removeAsListenerAndDispose(Controller controller) { - delegate.removeAsListenerAndDispose(controller); - } - - @Override - public void listenTo(Controller controller) { - delegate.listenTo(controller); - } - - @Override - public WindowControl getWindowControl() { - return delegate.getWindowControlForDebug(); - } - - @Override - public void fireEvent(UserRequest ureq, Event event) { - delegate.fireEvent(ureq, event); - } - }; - } -} diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragmentHost.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragmentHost.java deleted file mode 100644 index e678e22130f6273bd26fb34e4056b71f6a93bc88..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/IFormFragmentHost.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.core.gui.components.form.flexible.impl; - -import org.olat.core.gui.components.form.flexible.FormUIFactory; -import org.olat.core.gui.translator.Translator; - -/** - * The interface implemented by a {@link IFormFragmentContainer} to provide the {@link IFormFragment} - * with controller over its runtime behavior. - * - * <p>Initial date: May 6, 2016<br> - * @author lmihalkovic, http://www.frentix.com - */ -public interface IFormFragmentHost { - - /** - * Return a {@link Translator} instance that can provide a translation specific to where the - * fragment is used, or a default translation associated with the fragment itself. - * - * @return - */ - Translator getFragmentTranslator(); - - /** - * Return a {@link FormUIFactory} instance that may have been tweaked to enforce certain - * behavior specific to where the fragment is being embedded - * @return - */ - default FormUIFactory getUIFactory() { - return FormUIFactory.getInstance(); - } - - /** - * Return the controller instance to be used by the fragment for event handling - * - * @return - */ - IFormFragmentController getFragmentController(); - -} diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementImpl.java index a74801a12275be33b6f1b954a1a76f6e1e4621dd..4a3cbbffd6f10e555600e1e03a4350125b894fc4 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementImpl.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementImpl.java @@ -54,6 +54,7 @@ import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.CodeHelper; import org.olat.core.util.FileUtils; +import org.olat.core.util.StringHelper; import org.olat.core.util.UserSession; import org.olat.core.util.Util; import org.olat.core.util.ValidationStatus; @@ -122,6 +123,7 @@ public class FileElementImpl extends FormItemImpl super(name); this.wControl = wControl; component = new FileElementComponent(this); + setElementCssClass(null); // trigger default css } /** @@ -197,7 +199,8 @@ public class FileElementImpl extends FormItemImpl } private void doConfirmDelete(UserRequest ureq) { - Translator fileTranslator = Util.createPackageTranslator(FileElementImpl.class, ureq.getLocale(), getTranslator()); + Translator fileTranslator = Util.createPackageTranslator(FileElementImpl.class, ureq.getLocale(), + getTranslator()); String title = fileTranslator.translate("confirm.delete.file.title"); String text = fileTranslator.translate("confirm.delete.file"); dialogCtr = DialogBoxUIFactory.createOkCancelDialog(ureq, wControl, title, text); @@ -208,7 +211,7 @@ public class FileElementImpl extends FormItemImpl @Override public Iterable<FormItem> getFormItems() { if (previewEl != null) { - return Collections.<FormItem> singletonList(previewEl); + return Collections.<FormItem>singletonList(previewEl); } return Collections.emptyList(); } @@ -339,15 +342,15 @@ public class FileElementImpl extends FormItemImpl @Override public String getExampleText() { - if(fileExampleKey != null) { - if(fileExampleParams != null) { + if (fileExampleKey != null) { + if (fileExampleParams != null) { return translator.translate(fileExampleKey, fileExampleParams); } return translator.translate(fileExampleKey); } return null; } - + @Override public void setExampleKey(String exampleKey, String[] params) { this.fileExampleKey = exampleKey; @@ -464,7 +467,7 @@ public class FileElementImpl extends FormItemImpl public String getUploadFileName() { return uploadFilename; } - + @Override public void setUploadFileName(String uploadFileName) { this.uploadFilename = uploadFileName; @@ -601,6 +604,17 @@ public class FileElementImpl extends FormItemImpl } + @Override + public void setElementCssClass(String elementCssClass) { + // make sure the o_fileElement class is always set to trigger special + // rendering for all file elements (error handling) + if (StringHelper.containsNonWhitespace(elementCssClass)) { + super.setElementCssClass(elementCssClass + " o_fileElement"); + } else { + super.setElementCssClass("o_fileElement"); + } + } + /** * @see org.olat.core.gui.control.Disposable#dispose() */ diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/TextBoxListElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/TextBoxListElementImpl.java index e87e730e2c49c4457e4aba0f857da415fc3c83d9..e04c05cecd0e56ca117cf7171c936fc6ed910c9b 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/TextBoxListElementImpl.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/TextBoxListElementImpl.java @@ -76,9 +76,7 @@ public class TextBoxListElementImpl extends AbstractTextElement implements TextB } else { //this one handle multipart/form too String submitValue = getRootForm().getRequestParameter(inputId); - if(StringHelper.containsNonWhitespace(submitValue)) { - component.setCmd(ureq, submitValue); - } + component.setCmd(ureq, submitValue); } } diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextConfiguration.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextConfiguration.java index acf788c2dbb104230a33733ce49ee467271bd9bc..8dc4d69c7c84dc0d0a00beea50429408b4132bf6 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextConfiguration.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextConfiguration.java @@ -99,7 +99,7 @@ public class RichTextConfiguration implements Disposable { private static final String TABFOCUS_SETTINGS_PREV_NEXT = ":prev,:next"; // Valid elements private static final String EXTENDED_VALID_ELEMENTS = "extended_valid_elements"; - private static final String EXTENDED_VALID_ELEMENTS_VALUE_FULL = "script[src|type|defer],form[*],input[*],a[*],p[*],#comment[*],img[*],iframe[*],map[*],area[*],textentryinteraction[*]"; + private static final String EXTENDED_VALID_ELEMENTS_VALUE_FULL = "script[src|type|defer],form[*],input[*],a[*],p[*],#comment[*],figure[*],figcaption,img[*],iframe[*],map[*],area[*],textentryinteraction[*]"; private static final String MATHML_VALID_ELEMENTS = "math[*],mi[*],mn[*],mo[*],mtext[*],mspace[*],ms[*],mrow[*],mfrac[*],msqrt[*],mroot[*],merror[*],mpadded[*],mphantom[*],mfenced[*],mstyle[*],menclose[*],msub[*],msup[*],msubsup[*],munder[*],mover[*],munderover[*],mmultiscripts[*],mtable[*],mtr[*],mtd[*],maction[*]"; private static final String INVALID_ELEMENTS = "invalid_elements"; private static final String INVALID_ELEMENTS_FORM_MINIMALISTIC_VALUE_UNSAVE = "iframe,script,@[on*],object,embed"; @@ -150,10 +150,9 @@ public class RichTextConfiguration implements Disposable { private String linkBrowserAbsolutFilePath; private boolean relativeUrls = true; private boolean removeScriptHost = true; - private boolean statusBar = true; private boolean pathInStatusBar = true; + private boolean figCaption = true; private boolean allowCustomMediaFactory = true; - private boolean inline = false; private boolean sendOnBlur; private boolean readOnly; private boolean filenameUriValidation = false; @@ -166,6 +165,7 @@ public class RichTextConfiguration implements Disposable { private final Locale locale; private TinyConfig tinyConfig; + private List<TextMode> textModes = Collections.singletonList(TextMode.formatted); private RichTextConfigurationDelegate additionalConfiguration; public RichTextConfiguration(Locale locale) { @@ -414,14 +414,6 @@ public class RichTextConfiguration implements Disposable { this.allowCustomMediaFactory = allowCustomMediaFactory; } - public boolean isInline() { - return inline; - } - - public void setInline(boolean inline) { - this.inline = inline; - } - public boolean isSendOnBlur() { return sendOnBlur; } @@ -434,21 +426,6 @@ public class RichTextConfiguration implements Disposable { this.sendOnBlur = sendOnBlur; } - public boolean isStatusBar() { - return statusBar; - } - - /** - * Allow to remove the status bar - * - * @see https://www.tinymce.com/docs/configure/editor-appearance/#statusbar - * - * @param statusBar - */ - public void setStatusBar2(boolean statusBar) { - this.statusBar = statusBar; - } - public boolean isPathInStatusBar() { return pathInStatusBar; } @@ -466,6 +443,22 @@ public class RichTextConfiguration implements Disposable { this.readOnly = readOnly; } + public List<TextMode> getTextModes() { + return new ArrayList<>(textModes); + } + + public void setSimplestTextModeAllowed(TextMode textMode) { + if(textMode != null) { + List<TextMode> newModes = new ArrayList<>(3); + for(int i=textMode.ordinal(); i<=TextMode.formatted.ordinal(); i++) { + newModes.add(TextMode.values()[i]); + } + textModes = newModes; + } else { + textModes = Collections.singletonList(TextMode.formatted); + } + } + public RichTextConfigurationDelegate getAdditionalConfiguration() { return additionalConfiguration; } @@ -858,6 +851,10 @@ public class RichTextConfiguration implements Disposable { tinyConfig = tinyConfig.enableCode(); } + public void enableCharCount() { + tinyConfig = tinyConfig.enableCharcount(); + } + public void enableQTITools(boolean textEntry, boolean numericalInput, boolean hottext) { tinyConfig = tinyConfig.enableQTITools(textEntry, numericalInput, hottext); setQuotedConfigValue("custom_elements", "~textentryinteraction,~hottext"); @@ -884,6 +881,21 @@ public class RichTextConfiguration implements Disposable { setNonQuotedConfigValue(RichTextConfiguration.HEIGHT, "b_initialEditorHeight()"); } + /** + * @return True if the fig caption for image is enabled. + */ + public boolean isFigCaption() { + return figCaption; + } + + /** + * Enable or disable fig caption for image. + * @param figCaption + */ + public void setFigCaption(boolean figCaption) { + this.figCaption = figCaption; + } + public boolean isFilenameUriValidation() { return filenameUriValidation; } @@ -1005,9 +1017,10 @@ public class RichTextConfiguration implements Disposable { StringOutput tinyMenuSb = new StringOutput(); tinyMenuSb.append("plugins: '").append(tinyConfig.getPlugins()).append("',\n") .append("image_advtab:true,\n") + .append("image_caption:").append(figCaption).append(",\n") + .append("image_title:true,\n") .append("relative_urls:").append(isRelativeUrls()).append(",\n") .append("remove_script_host:").append(isRemoveScriptHost()).append(",\n") - .append("inline:").append(isInline()).append(",\n") .append("statusbar:").append(true).append(",\n") .append("resize:").append(true).append(",\n") .append("menubar:").append(tinyConfig.hasMenu()).append(",\n"); diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementComponent.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementComponent.java index 4836447aac707d76702236b5737514a324ff323d..e76a7fcb60e1d8c07436e04e6a0e616d30375b94 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementComponent.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementComponent.java @@ -53,11 +53,12 @@ class RichTextElementComponent extends FormBaseComponentImpl { private static final String CMD_IMAGEBROWSER = "image"; private static final String CMD_FLASHPLAYERBROWSER = "flashplayer"; private static final String CMD_FILEBROWSER = "file"; + private static final String CMD_MEDIABROWSER = "media"; private static final ComponentRenderer RENDERER = new RichTextElementRenderer(); private final RichTextElementImpl element; - private int cols; - private int rows; + private int cols, rows; + private TextMode currentTextMode; /** * Constructor for a text area element @@ -105,6 +106,14 @@ class RichTextElementComponent extends FormBaseComponentImpl { this.rows = rows; } + protected TextMode getCurrentTextMode() { + return currentTextMode; + } + + protected void setCurrentTextMode(TextMode currentTextMode) { + this.currentTextMode = currentTextMode; + } + @Override public void validate(UserRequest ureq, ValidationResult vr) { super.validate(ureq, vr); @@ -118,7 +127,8 @@ class RichTextElementComponent extends FormBaseComponentImpl { // element we make an exception since we have the media and link chooser // events that must be dispatched by this code. String moduleUri = ureq.getModuleURI(); - if (CMD_FILEBROWSER.equals(moduleUri) || CMD_IMAGEBROWSER.equals(moduleUri) || CMD_FLASHPLAYERBROWSER.equals(moduleUri)) { + if (CMD_FILEBROWSER.equals(moduleUri) || CMD_IMAGEBROWSER.equals(moduleUri) + || CMD_FLASHPLAYERBROWSER.equals(moduleUri) || CMD_MEDIABROWSER.equals(moduleUri)) { // Get currently edited relative file path String fileName = getRichTextElementImpl().getEditorConfiguration().getLinkBrowserRelativeFilePath(); createFileSelectorPopupWindow(ureq, moduleUri, fileName); diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementImpl.java index 7babc13075fe26d68f3ab20674bd33a6ec84be6f..8e7640d3ec0e774149e60344f6e8925cb168205f 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementImpl.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementImpl.java @@ -20,6 +20,8 @@ package org.olat.core.gui.components.form.flexible.impl.elements.richText; +import java.util.Iterator; +import java.util.List; import java.util.Locale; import org.olat.core.gui.UserRequest; @@ -32,6 +34,8 @@ import org.olat.core.gui.control.Disposable; import org.olat.core.helpers.Settings; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; import org.olat.core.util.filter.Filter; import org.olat.core.util.filter.FilterFactory; @@ -52,6 +56,7 @@ public class RichTextElementImpl extends AbstractTextElement implements private static final OLog log = Tracing.createLoggerFor(RichTextElementImpl.class); private final RichTextElementComponent component; private RichTextConfiguration configuration; + private TextMode renderingMode; /** * Constructor for specialized TextElements, i.e. IntegerElementImpl. @@ -88,6 +93,7 @@ public class RichTextElementImpl extends AbstractTextElement implements super(name); // initialize the component component = new RichTextElementComponent(this, rows, cols); + component.setTranslator(Util.createPackageTranslator(RichTextElementImpl.class, locale)); // configure tiny (must be after component initialization) // init editor on our form element configuration = new RichTextConfiguration(getFormDispatchId(), rootForm.getDispatchFieldId(), locale); @@ -121,6 +127,51 @@ public class RichTextElementImpl extends AbstractTextElement implements public void setDomReplacementWrapperRequired(boolean required) { component.setDomReplacementWrapperRequired(required); } + + protected void setRenderingMode(TextMode mode) { + renderingMode = mode; + } + + /** + * @return The list of text modes available based on the configuration and + * the content of the editor. + */ + public TextModeState getAvailableTextModes() { + List<TextMode> textModes = configuration.getTextModes(); + if(textModes.size() == 1) { + return new TextModeState(TextMode.formatted, textModes); + } + + TextMode minimalMode = TextMode.guess(getRawValue()); + for(Iterator<TextMode> it=textModes.iterator(); it.hasNext(); ) { + if(it.next().ordinal() < minimalMode.ordinal()) { + it.remove(); + } + } + + if(minimalMode.ordinal() < textModes.get(0).ordinal()) { + minimalMode = textModes.get(0); + } + + TextMode currentMode = minimalMode; + if(component.getCurrentTextMode() != null + && component.getCurrentTextMode().ordinal() > currentMode.ordinal()) { + currentMode = component.getCurrentTextMode(); + } else if(component.getCurrentTextMode() == null) { + component.setCurrentTextMode(currentMode); + } + return new TextModeState(currentMode, textModes); + } + + protected String getRawValue(TextMode mode) { + String raw = getRawValue(); + if(mode == TextMode.oneLine) { + raw = TextMode.toOneLine(raw); + } else if(mode == TextMode.multiLine) { + raw = TextMode.toMultiLine(raw); + } + return raw; + } /** * This apply a filter to remove some buggy conditional comment @@ -144,6 +195,15 @@ public class RichTextElementImpl extends AbstractTextElement implements String paramId = component.getFormDispatchId(); String cmd = getRootForm().getRequestParameter("cmd"); String submitValue = getRootForm().getRequestParameter(paramId); + if(StringHelper.containsNonWhitespace(submitValue)) { + if(renderingMode == TextMode.oneLine) { + submitValue = TextMode.fromOneLine(submitValue); + } else if(renderingMode == TextMode.multiLine) { + submitValue = TextMode.fromMultiLine(submitValue); + } + } + + String dispatchUri = getRootForm().getRequestParameter("dispatchuri"); if("saveinlinedtiny".equals(cmd)) { if(submitValue != null) { setValue(submitValue); @@ -153,10 +213,20 @@ public class RichTextElementImpl extends AbstractTextElement implements setValue(submitValue); // don't re-render component, value in GUI already correct component.setDirty(false); - } else if(cmd != null) { + } else if(cmd != null && !cmd.equals("multiline") && !cmd.equals("formatted")) { getRootForm().fireFormEvent(ureq, new FormEvent(cmd, this, FormEvent.ONCLICK)); component.setDirty(false); } + + if(paramId.equals(dispatchUri)) { + if(TextMode.formatted.name().equals(cmd)) { + component.setCurrentTextMode(TextMode.formatted); + } else if(TextMode.multiLine.name().equals(cmd)) { + component.setCurrentTextMode(TextMode.multiLine); + } else if(TextMode.oneLine.name().equals(cmd)) { + component.setCurrentTextMode(TextMode.oneLine); + } + } } /** @@ -212,4 +282,23 @@ public class RichTextElementImpl extends AbstractTextElement implements "the submit button first the onchange event will be triggered and you have to click twice to submit the data. "); } } + + public static class TextModeState { + + private final TextMode currentMode; + private final List<TextMode> availableTextModes; + + public TextModeState(TextMode currentMode, List<TextMode> availableTextModes) { + this.currentMode = currentMode; + this.availableTextModes = availableTextModes; + } + + public TextMode getCurrentMode() { + return currentMode; + } + + public List<TextMode> getAvailableTextModes() { + return availableTextModes; + } + } } \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementRenderer.java index 259aa505ed2bd21c613f23b529b990e2d77c04b5..b3666d14ea165a761b6d1caa04b396a04f619bf5 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementRenderer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementRenderer.java @@ -28,12 +28,15 @@ import org.olat.core.gui.components.Component; import org.olat.core.gui.components.DefaultComponentRenderer; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormJSHelper; +import org.olat.core.gui.components.form.flexible.impl.NameValuePair; +import org.olat.core.gui.components.form.flexible.impl.elements.richText.RichTextElementImpl.TextModeState; import org.olat.core.gui.render.RenderResult; import org.olat.core.gui.render.Renderer; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; /** * @@ -91,13 +94,100 @@ class RichTextElementRenderer extends DefaultComponentRenderer { sb.append(" o_richtext_mce_without_path"); } sb.append("'>"); - renderTinyMCE_4(sb, domID, teC, ubu, source.getTranslator()); + //switches + TextMode currentTextMode; + if(te.getEditorConfiguration().getTextModes().size() > 1) { + TextModeState textModeState = te.getAvailableTextModes(); + currentTextMode = textModeState.getCurrentMode(); + List<TextMode> modes = textModeState.getAvailableTextModes(); + if(modes.size() > 0) { + Form form = te.getRootForm(); + sb.append("<div class='o_richtext_mce_modes'><div class='btn-group'>"); + for(TextMode mode:modes) { + sb.append("<a href='javascript:;' class='btn btn-default btn-xs") + .append(" active", currentTextMode == mode).append("'") + .append(" onclick=\"").append(FormJSHelper.getXHRFnCallFor(form, teC.getFormDispatchId(), 1, false, false, true, + new NameValuePair("cmd", mode.name()))).append("\">") + .append(source.getTranslator().translate(mode.name())) + .append("</a>"); + } + sb.append("</div></div>"); + } + } else { + currentTextMode = TextMode.formatted; + } + + switch(currentTextMode) { + case formatted: + renderTinyMCE_4(sb, domID, teC, ubu, source.getTranslator()); + break; + case multiLine: + renderMultiLine(sb, domID, teC); + break; + case oneLine: + renderOneLine(sb, domID, teC); + break; + } sb.append("</div>"); } } + + private void renderOneLine(StringOutput sb, String domID, RichTextElementComponent teC) { + RichTextElementImpl te = teC.getRichTextElementImpl(); + te.setRenderingMode(TextMode.oneLine); + String htmlVal = StringHelper.escapeHtml(te.getRawValue(TextMode.oneLine)); + + sb.append("<input id=\"").append(domID).append("\" name=\"").append(domID).append("\" ") + .append(" type='text' class='form-control'") + .append(" value=\"").append(htmlVal).append("\" ") + .append(FormJSHelper.getRawJSFor(te.getRootForm(), domID, te.getAction())); + if (te.hasPlaceholder()) { + sb.append(" placeholder=\"").append(te.getPlaceholder()).append("\""); + } + if (te.hasFocus()) { + sb.append(" autofocus"); + } + + sb.append(" />"); + //add set dirty form only if enabled + FormJSHelper.appendFlexiFormDirty(sb, te.getRootForm(), teC.getFormDispatchId()); + } + + private void renderMultiLine(StringOutput sb, String domID, RichTextElementComponent teC) { + RichTextElementImpl te = teC.getRichTextElementImpl(); + te.setRenderingMode(TextMode.multiLine); + int cols = teC.getCols(); + int rows = teC.getRows(); + String value = te.getRawValue(TextMode.multiLine); + + // Read write view + sb.append("<textarea id=\"").append(domID).append("\" name=\"").append(domID).append("\" "); + StringBuilder rawData = FormJSHelper.getRawJSFor(te.getRootForm(), domID, te.getAction()); + sb.append(rawData.toString()); + sb.append(" class='form-control' style=\"width:"); + if (cols == -1) { + sb.append("100%;"); + } else { + sb.append(cols).append("em;"); + } + sb.append("height:"); + if (rows == -1) { + sb.append("100%;"); + } else { + sb.append(rows).append("em;"); + } + sb.append("\" class=\"BGlossarIgnore\">") + .append(value) + .append("</textarea>") + .append(FormJSHelper.getJSStartWithVarDeclaration(domID)) + //plain textAreas should not propagate the keypress "enter" (keynum = 13) as this would submit the form + .append(domID).append(".on('keypress', function(event, target){if (13 == event.keyCode) {event.stopPropagation()} })") + .append(FormJSHelper.getJSEnd()); + } private void renderTinyMCE_4(StringOutput sb, String domID, RichTextElementComponent teC, URLBuilder ubu, Translator translator) { RichTextElementImpl te = teC.getRichTextElementImpl(); + te.setRenderingMode(TextMode.formatted); RichTextConfiguration config = te.getEditorConfiguration(); List<String> onInit = config.getOnInit(); @@ -111,15 +201,14 @@ class RichTextElementRenderer extends DefaultComponentRenderer { StaticMediaDispatcher.renderStaticURI(baseUrl, "js/tinymce4/tinymce/tinymce.min.js", true); // Read write view - if(config.isInline()) { - renderInlineEditor(sb, domID, teC); - } else { - renderTextarea(sb, domID, teC); - } + renderTinyMCETextarea(sb, domID, teC); Form form = te.getRootForm(); configurations.append("ffxhrevent: { formNam:\"").append(form.getFormName()).append("\", dispIdField:\"").append(form.getDispatchFieldId()).append("\",") - .append(" dispId:\"").append(teC.getFormDispatchId()).append("\", eventIdField:\"").append(form.getEventFieldId()).append("\"}\n"); + .append(" dispId:\"").append(teC.getFormDispatchId()).append("\", eventIdField:\"").append(form.getEventFieldId()).append("\"},\n"); + if(te.getMaxLength() > 0) { + configurations.append("maxSize:").append(te.getMaxLength()).append("\n"); + } sb.append("<script type='text/javascript'>/* <![CDATA[ */\n"); //file browser url @@ -136,7 +225,7 @@ class RichTextElementRenderer extends DefaultComponentRenderer { .append(" ed.on('change', function(e) {\n") .append(" BTinyHelper.triggerOnChange('").append(domID).append("');\n") .append(" });\n"); - if(config.isInline() || config.isSendOnBlur()) { + if(config.isSendOnBlur()) { sb.append(" ed.on('blur', function(e) {\n") .append(" o_ffXHREvent('").append(form.getFormName()).append("','").append(form.getDispatchFieldId()).append("','").append(teC.getFormDispatchId()).append("','").append(form.getEventFieldId()).append("', 2, false, false, false, 'cmd','saveinlinedtiny','").append(domID).append("',ed.getContent());\n") .append(" });\n"); @@ -147,45 +236,11 @@ class RichTextElementRenderer extends DefaultComponentRenderer { .append("/* ]]> */</script>\n"); } - private void renderInlineEditor(StringOutput sb, String domID, RichTextElementComponent teC) { + private void renderTinyMCETextarea(StringOutput sb, String domID, RichTextElementComponent teC) { RichTextElementImpl te = teC.getRichTextElementImpl(); int cols = teC.getCols(); int rows = teC.getRows(); - String value = te.getRawValue(); - - // Read write view - sb.append("<div id=\""); - sb.append(domID); - sb.append("\" name=\""); - sb.append(domID); - sb.append("\" "); - StringBuilder rawData = FormJSHelper.getRawJSFor(te.getRootForm(), domID, te.getAction()); - sb.append(rawData.toString()); - sb.append(" style=\""); - sb.append(" width:"); - if (cols == -1) { - sb.append("100%;"); - } else { - sb.append(cols); - sb.append("em;"); - } - sb.append("height:"); - if (rows == -1) { - sb.append("100%;"); - } else { - sb.append(rows); - sb.append("em;"); - } - sb.append("\" class=\"BGlossarIgnore\">"); - sb.append(value); - sb.append("</div>"); - } - - private void renderTextarea(StringOutput sb, String domID, RichTextElementComponent teC) { - RichTextElementImpl te = teC.getRichTextElementImpl(); - int cols = teC.getCols(); - int rows = teC.getRows(); - String value = te.getRawValue(); + String value = te.getRawValue(TextMode.formatted); // Read write view sb.append("<textarea id=\""); diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TextMode.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TextMode.java new file mode 100644 index 0000000000000000000000000000000000000000..e79f0cf8770fe37c6484a995cdf32156a4c17ac6 --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TextMode.java @@ -0,0 +1,207 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.gui.components.form.flexible.impl.elements.richText; + +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.List; + +import org.cyberneko.html.parsers.SAXParser; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * + * Initial date: 19 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public enum TextMode { + //order is important, from the simplest to the sophisticated + oneLine, + multiLine, + formatted; + + private static final OLog log = Tracing.createLoggerFor(TextMode.class); + + public static TextMode guess(String text) { + if(StringHelper.containsNonWhitespace(text)) { + try { + TextAnalyser analyser = new TextAnalyser(); + parse(text, analyser); + if(analyser.isOtherTags()) { + return formatted; + } else if(analyser.isBr()) { + return multiLine; + } else if(analyser.getP() > 1) { + return multiLine; + } + return oneLine; + } catch (Exception e) { + log.error("", e); + return formatted; + } + } + return oneLine; + } + + public static String toMultiLine(String text) { + if(StringHelper.containsNonWhitespace(text)) { + try { + LineExtractor handler = new LineExtractor("\n"); + parse(text, handler); + return handler.getText(); + } catch (Exception e) { + log.error("", e); + return text; + } + } + return text; + } + + public static String fromMultiLine(String text) { + String formattedTex; + if(StringHelper.containsNonWhitespace(text)) { + StringBuilder sb = new StringBuilder(text.length() * 2); + String[] lines = text.split("\r?\n"); + for(String line:lines) { + sb.append("<p>").append(line).append("</p>"); + } + formattedTex = sb.toString(); + } else { + formattedTex = ""; + } + return formattedTex; + } + + public static String toOneLine(String text) { + if(StringHelper.containsNonWhitespace(text)) { + try { + LineExtractor handler = new LineExtractor(" "); + parse(text, handler); + return handler.getText(); + } catch (Exception e) { + log.error("", e); + return text; + } + } + return text; + } + + public static String fromOneLine(String text) { + if(StringHelper.containsNonWhitespace(text)) { + return "<p>" + text.trim() + "</p>"; + } + return ""; + } + + private static void parse(String text, DefaultHandler handler) throws Exception { + SAXParser parser = new SAXParser(); + parser.setProperty("http://cyberneko.org/html/properties/names/elems", "lower"); + parser.setFeature("http://cyberneko.org/html/features/balance-tags/document-fragment", true); + parser.setProperty("http://cyberneko.org/html/properties/default-encoding", "UTF-8"); + parser.setContentHandler(handler); + parser.parse(new InputSource(new ByteArrayInputStream(text.getBytes()))); + } + + private static final class TextAnalyser extends DefaultHandler { + + private int p = 0; + private boolean br = false; + private boolean otherTags = false; + + public int getP() { + return p; + } + + public boolean isBr() { + return br; + } + + public boolean isOtherTags() { + return otherTags; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if("p".equalsIgnoreCase(qName)) { + p++; + } else if("br".equalsIgnoreCase(qName)) { + br = true; + } else { + otherTags = true; + } + } + } + + + private static final class LineExtractor extends DefaultHandler { + + private final String separator; + private StringBuilder sb = new StringBuilder(); + private List<String> lines = new ArrayList<>(); + + public LineExtractor(String separator) { + this.separator = separator; + } + + public String getText() { + StringBuilder content = new StringBuilder(1024); + for(String line:lines) { + line = line.trim(); + if(StringHelper.containsNonWhitespace(line)) { + if(content.length() > 0) content.append(separator); + content.append(line); + } + } + return content.toString(); + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if("p".equalsIgnoreCase(qName) || "br".equalsIgnoreCase(qName)) { + lines.add(sb.toString()); + sb = new StringBuilder(128); + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if(start >= 0 && length > 0) { + sb.append(ch, start, length); + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if("p".equalsIgnoreCase(qName)) { + lines.add(sb.toString()); + sb = new StringBuilder(128); + } + } + } +} diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TinyConfig.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TinyConfig.java index a2ffa666104767739e50e717cc3bd6765e367bf7..5d1d863b2c14e175f8073e238316b1b91033fa98 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TinyConfig.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TinyConfig.java @@ -130,6 +130,10 @@ public class TinyConfig { return plugins != null && plugins.indexOf("olatmatheditor") >= 0; } + public TinyConfig enableCharcount() { + return enableFeature("olatcharcount"); + } + public TinyConfig enableCode() { return enableFeature("code"); } diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_de.properties index 6cff616d0c5f43e8151035cf00f72ce57f855f38..cd3f414f0ae4a28fce7bee4da78aeb13cd308690 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_de.properties @@ -3,3 +3,6 @@ richText.element.target.window.alwayssame = Link immer im selben neuen Fenster \ left.clear=Linksb\u00fcndig und allein right.clear=Rechtsb\u00fcndig und allein left.clear.nomargin=Linksb\u00fcndig mit Bildunterschrift +oneLine=Eine Zeile +multiLine=Mehrere Zeile +formatted=Formatiert diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_en.properties index b237ef02f3f051052a48d734bfcc4eca9e64d63a..918cc001c28daec8a59c42600cd3e613c3291665 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_en.properties @@ -2,4 +2,7 @@ richText.element.target.window.alwayssame=Open link always in the same new window left.clear=Left and clear right.clear=Right and clear -left.clear.nomargin=Left with caption \ No newline at end of file +left.clear.nomargin=Left with caption +oneLine=One line +multiLine=Multi-line +formatted=Formatted \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_fr.properties index 4b08e4d206a418410d7f5cc73ca416087076bb17..13e28eea99de946d319de9d6e3e2296ff3d01235 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_fr.properties @@ -1,5 +1,8 @@ -#Wed Mar 08 11:24:38 CET 2017 +#Tue Aug 15 17:17:34 CEST 2017 +formatted=Format\u00E9 left.clear=Align\u00E9 \u00E0 gauche et rien \u00E0 droite left.clear.nomargin=Align\u00E9 \u00E0 gauche avec l\u00E9gende +multiLine=Multi-lignes +oneLine=Ligne unique richText.element.target.window.alwayssame=Ouvrir le lien dans une nouvelle fen\u00EAtre right.clear=Aligner \u00E0 droite et rien \u00E0 gauche diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_pt_BR.properties index 629e97023960970b8290da267e812004503f176f..7fdc955a15bead4595eff7977c6858d8d6350074 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/_i18n/LocalStrings_pt_BR.properties @@ -1,5 +1,8 @@ -#Tue Feb 14 21:16:28 CET 2017 +#Tue Sep 05 22:46:09 CEST 2017 +formatted=Formatado left.clear=Justificado \u00E0 esquerda e sozinho left.clear.nomargin=Alinhado \u00E0 esquerda com subt\u00EDtulo +multiLine=Multi-linha +oneLine=Uma linha richText.element.target.window.alwayssame=Abrir link sempre na mesma nova janela right.clear=Justificado \u00E0 direita e sozinho diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..6e0fb4f76b391f462ebb6e374063d8003ba01d9e --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_de.properties @@ -0,0 +1,10 @@ +olatcharcount.size = Zeichen: {0} +olatcharcount.tooltip=Die Anzahl Zeichen ist mit HTML Markup gezählt. + + + + + + + + diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_en.properties new file mode 100644 index 0000000000000000000000000000000000000000..fb3f4ce0920be774208f0fab3a313a848ef3b21d --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_en.properties @@ -0,0 +1,3 @@ +#Thu Jan 20 20:04:11 CET 2011 +olatcharcount.size = Characters: {0} +olatcharcount.tooltip=Der number of characters is counted with the HTML Markup. diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_fr.properties new file mode 100644 index 0000000000000000000000000000000000000000..50a037ca4fcedb4a870a23f222e8aee044779e07 --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_fr.properties @@ -0,0 +1,3 @@ +#Tue Aug 15 17:16:55 CEST 2017 +olatcharcount.size=Caract\u00E8res\: {0} +olatcharcount.tooltip=Le nombre de caract\u00E8res est calcul\u00E9 avec le markup HTML. diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_pt_BR.properties new file mode 100644 index 0000000000000000000000000000000000000000..efa554b943fa280eeb8ec9ac0ac465413e145469 --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/plugins/olatcharcount/_i18n/LocalStrings_pt_BR.properties @@ -0,0 +1,3 @@ +#Tue Sep 05 22:47:31 CEST 2017 +olatcharcount.size=Caract\u00E9res\: {0} +olatcharcount.tooltip=O n\u00FAmero de caracteres \u00E9 contado com o HTML Markup. diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java index 8a8997be3553dcc4f5b7dc2da506ce2c1bbdc0e7..9d52bfc7b38159bdd15edddedc64200a7bd7b1ca 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java @@ -430,15 +430,15 @@ public abstract class AbstractFlexiTableRenderer extends DefaultComponentRendere renderPageSize(sb, ftC, translator); } - sb.append("<ul class='pagination'>"); if(pageSize > 0 && rows > pageSize) { + sb.append("<ul class='pagination'>"); int page = ftE.getPage(); int maxPage = (int)Math.ceil(((double) rows / (double) pageSize)); renderPageBackLink(sb, ftC, page); renderPageNumberLinks(sb, ftC, page, maxPage); renderPageNextLink(sb, ftC, page, maxPage); + sb.append("</ul>"); } - sb.append("</ul>"); } private void renderPageSize(StringOutput sb, FlexiTableComponent ftC, Translator translator) { diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java index ef1be3a2be80b3e0d987dab898d2f743e3c77d57..518dd8cea3d6585a420022ec2e01a126227fc158 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java @@ -26,7 +26,6 @@ package org.olat.core.gui.components.form.flexible.impl.elements.table; - /** * * @author Christian Guretzki @@ -243,7 +242,7 @@ public class DefaultFlexiColumnModel implements FlexiColumnModel { public void setExportable(boolean exportable) { this.exportable = exportable; } - + @Override public boolean isDefaultVisible() { return defaultVisible; diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiColumnModel.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiColumnModel.java index c7bf48963a44632d4a2a071476b5292cd1803d42..8476d9b5520db7996f8c83e6177b1d4763022d64 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiColumnModel.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiColumnModel.java @@ -26,7 +26,6 @@ package org.olat.core.gui.components.form.flexible.impl.elements.table; - /** * * @author Christian Guretzki diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableClassicRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableClassicRenderer.java index 337b5b945fe56af221366d4801912984a535e7e2..7796cbf8816d963aa8127af7595825cdf1d8a6be 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableClassicRenderer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableClassicRenderer.java @@ -80,7 +80,12 @@ class FlexiTableClassicRenderer extends AbstractFlexiTableRenderer implements Co private void renderHeader(StringOutput sb, FlexiTableComponent ftC, FlexiColumnModel fcm, Translator translator) { String header = getHeader(fcm, translator); - sb.append("<th>"); + sb.append("<th"); + // append sort key to make column width set via css + if (fcm.getSortKey() != null) { + sb.append(" class='o_col_").append(fcm.getSortKey()).append("'"); + } + sb.append(">"); // sort is not defined if (!fcm.isSortable() || fcm.getSortKey() == null) { sb.append(header); diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/XlsFlexiTableExporter.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/XlsFlexiTableExporter.java index 25b363df716b2a1765cc65dc02b93acf180b9e84..f9b9506dc019fe71828ea37fd321b4c83e9c4c6c 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/XlsFlexiTableExporter.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/XlsFlexiTableExporter.java @@ -73,19 +73,20 @@ public class XlsFlexiTableExporter implements FlexiTableExporter { }; } - private void createHeader(List<FlexiColumnModel> columns, Translator translator, + protected void createHeader(List<FlexiColumnModel> columns, Translator translator, OpenXMLWorksheet sheet, OpenXMLWorkbook workbook) { sheet.setHeaderRows(1); Row headerRow = sheet.newRow(); for (int c=0; c<columns.size(); c++) { FlexiColumnModel cd = columns.get(c); + String headerVal = cd.getHeaderLabel() == null ? translator.translate(cd.getHeaderKey()) : cd.getHeaderLabel(); headerRow.addCell(c, headerVal, workbook.getStyles().getHeaderStyle()); } } - private void createData(FlexiTableComponent ftC, List<FlexiColumnModel> columns, Translator translator, + protected void createData(FlexiTableComponent ftC, List<FlexiColumnModel> columns, Translator translator, OpenXMLWorksheet sheet, OpenXMLWorkbook workbook) { FlexiTableDataModel<?> dataModel = ftC.getFlexiTableElement().getTableDataModel(); @@ -95,28 +96,38 @@ public class XlsFlexiTableExporter implements FlexiTableExporter { Row dataRow = sheet.newRow(); for (int c = 0; c<numOfColumns; c++) { FlexiColumnModel cd = columns.get(c); - - int colIndex = cd.getColumnIndex(); - if(colIndex >= 0) { - Object value = dataModel.getValueAt(r, colIndex); - if(value instanceof Date) { - dataRow.addCell(c, (Date)value, workbook.getStyles().getDateStyle()); - } else if(value instanceof Number) { - dataRow.addCell(c, (Number)value, null); - } else { - StringOutput so = StringOutputPool.allocStringBuilder(1000); - cd.getCellRenderer().render(null, so, value, r, ftC, ubu, translator); - String cellValue = StringOutputPool.freePop(so); - - cellValue = StringHelper.stripLineBreaks(cellValue); - cellValue = FilterFactory.getHtmlTagsFilter().filter(cellValue); - if(StringHelper.containsNonWhitespace(cellValue)) { - cellValue = StringEscapeUtils.unescapeHtml(cellValue); - } - dataRow.addCell(c, cellValue, null); + createCell(ftC, cd, dataRow, r, c, translator, workbook); + } + } + } + + protected void createCell(FlexiTableComponent ftC, FlexiColumnModel cd, Row dataRow, int row, int col, Translator translator, + OpenXMLWorkbook workbook) { + FlexiTableDataModel<?> dataModel = ftC.getFlexiTableElement().getTableDataModel(); + + try { + int colIndex = cd.getColumnIndex(); + if(colIndex >= 0) { + Object value = dataModel.getValueAt(row, colIndex); + if(value instanceof Date) { + dataRow.addCell(col, (Date)value, workbook.getStyles().getDateStyle()); + } else if(value instanceof Number) { + dataRow.addCell(col, (Number)value, null); + } else { + StringOutput so = StringOutputPool.allocStringBuilder(1000); + cd.getCellRenderer().render(null, so, value, row, ftC, ubu, translator); + String cellValue = StringOutputPool.freePop(so); + + cellValue = StringHelper.stripLineBreaks(cellValue); + cellValue = FilterFactory.getHtmlTagsFilter().filter(cellValue); + if(StringHelper.containsNonWhitespace(cellValue)) { + cellValue = StringEscapeUtils.unescapeHtml(cellValue); } + dataRow.addCell(col, cellValue, null); } } + } catch (Exception e) { + log.error("", e); } } } diff --git a/src/main/java/org/olat/core/gui/components/image/ImageComponent.java b/src/main/java/org/olat/core/gui/components/image/ImageComponent.java index afb0c79a8383446a48b2beb5aba1b1200ae72b71..970735bfde1b16c951591430081e02e97eb8f0b5 100644 --- a/src/main/java/org/olat/core/gui/components/image/ImageComponent.java +++ b/src/main/java/org/olat/core/gui/components/image/ImageComponent.java @@ -78,6 +78,7 @@ public class ImageComponent extends AbstractComponent implements Disposable { private Size realSize; private Size scaledSize; private float scalingFactor; + private boolean divImageWrapper = true; private boolean cropSelectionEnabled = false; /** @@ -104,6 +105,14 @@ public class ImageComponent extends AbstractComponent implements Disposable { this.alt = alt; } + public boolean isDivImageWrapper() { + return divImageWrapper; + } + + public void setDivImageWrapper(boolean divImageWrapper) { + this.divImageWrapper = divImageWrapper; + } + /** * @see org.olat.core.gui.components.Component#dispatchRequest(org.olat.core.gui.UserRequest) */ diff --git a/src/main/java/org/olat/core/gui/components/image/ImageRenderer.java b/src/main/java/org/olat/core/gui/components/image/ImageRenderer.java index 928c95a8ae910547e32ebe36c25029922abf4c94..4e5ebd5f02b14f0cffcf075e8d17b4638d1a6fe6 100644 --- a/src/main/java/org/olat/core/gui/components/image/ImageRenderer.java +++ b/src/main/java/org/olat/core/gui/components/image/ImageRenderer.java @@ -119,9 +119,14 @@ public class ImageRenderer extends DefaultComponentRenderer { } sb.append("'>"); } - sb.append("<div id='").append(compId).append("' class='o_image'>"); // START component + + boolean divWrapper = ic.isDivImageWrapper(); + if(divWrapper) { + sb.append("<div id='").append(compId).append("' class='o_image'>"); // START component + } + // The inner component - String imgId = "o_img" + ic.getDispatchID(); + String imgId = divWrapper ? "o_img" + ic.getDispatchID() : compId; sb.append("<img").append(" id='").append(imgId).append("'"); if (scaledSize != null) { sb.append(" width=\"").append(scaledSize.getWidth()).append("\""); @@ -165,8 +170,7 @@ public class ImageRenderer extends DefaultComponentRenderer { .append("/* ]]> */\n") .append("</script>"); } - sb.append("</div>"); // ENDcomponent + sb.append("</div>", divWrapper); // ENDcomponent sb.append("</div>", cropEnabled); - } } \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/components/progressbar/ProgressBar.java b/src/main/java/org/olat/core/gui/components/progressbar/ProgressBar.java index bec350d7dd185ad18654851392251e3318b88d2b..fdc441a8f7563f528f73ed472cbe150cca06ad62 100644 --- a/src/main/java/org/olat/core/gui/components/progressbar/ProgressBar.java +++ b/src/main/java/org/olat/core/gui/components/progressbar/ProgressBar.java @@ -133,11 +133,13 @@ public class ProgressBar extends AbstractComponent { } public boolean isWidthInPercent() { - width = 100; return widthInPercent; } public void setWidthInPercent(boolean widthInPercent) { + if(widthInPercent) { + width = 100; + } this.widthInPercent = widthInPercent; } diff --git a/src/main/java/org/olat/core/gui/components/text/TextComponentRenderer.java b/src/main/java/org/olat/core/gui/components/text/TextComponentRenderer.java index 8905c5cc3089ce72d79892eb8edf8f61f6ba4f22..8fbd06a5b114749c5b34501c589d5711324c5b43 100644 --- a/src/main/java/org/olat/core/gui/components/text/TextComponentRenderer.java +++ b/src/main/java/org/olat/core/gui/components/text/TextComponentRenderer.java @@ -26,6 +26,7 @@ import org.olat.core.gui.render.Renderer; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; +import org.olat.core.util.StringHelper; /** * Description:<br> @@ -58,13 +59,21 @@ class TextComponentRenderer extends DefaultComponentRenderer { if (text != null) { // Add a wrapper with a CSS class if necessary String cssClass = comp.getCssClass(); + String elementCssClasss = comp.getElementCssClass(); String tag = comp.getSpanAsDomReplaceable() ? "span" : "div"; // In any case render a span or div. If in ajax mode, another span/div // will be wrapped around this to identify the component. sb.append("<").append(tag); // Add optional css class - if (cssClass != null) { - sb.append(" class='").append(cssClass).append("'"); + if (cssClass != null || elementCssClasss != null) { + sb.append(" class='"); + if(StringHelper.containsNonWhitespace(cssClass)) { + sb.append(cssClass); + } + if(StringHelper.containsNonWhitespace(elementCssClasss)) { + sb.append(" ").append(elementCssClasss); + } + sb.append("'"); } if(!comp.isDomReplacementWrapperRequired()) { sb.append(" id='").append(comp.getDispatchID()).append("'"); diff --git a/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListComponent.java b/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListComponent.java index 9b47bca26fb34f96e8a42ee14a3b48fce84b9b84..cc7919b14d3471040279983014701ea0ad24b487 100644 --- a/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListComponent.java +++ b/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListComponent.java @@ -153,9 +153,10 @@ public abstract class TextBoxListComponent extends FormBaseComponentImpl { } public void setCmd(UserRequest ureq, String cmd) { - if(!StringHelper.containsNonWhitespace(cmd)) { + if(cmd == null) { return; } + // empty string is ok = empty text box String[] splitted = cmd.split(","); List<String> cleanedItemValues = new ArrayList<String>(); @@ -434,12 +435,13 @@ public abstract class TextBoxListComponent extends FormBaseComponentImpl { } /** - * returns a the initialItems as comma-separated list.<br /> + * returns a the current items as comma-separated list.<br /> * * @return An HTML escaped list of item */ - protected String getInitialItemsAsString() { - Map<String, String> content = getInitialItems(); + protected String getItemsAsString() { + Map<String, String> content = getCurrentItems(); + if (content != null && content.size() != 0) { //antisamy + escaping to prevent issue with the javascript code OWASPAntiSamyXSSFilter filter = new OWASPAntiSamyXSSFilter(); diff --git a/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListRenderer.java b/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListRenderer.java index 97cc01b4979791c8418fa3867143106ddf2acf07..f98e9376255362517c363c62736d4b9e59c035fa 100644 --- a/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListRenderer.java +++ b/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListRenderer.java @@ -30,6 +30,8 @@ import org.olat.core.gui.render.Renderer; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; +import org.olat.core.util.Formatter; +import org.olat.core.util.Util; /** * Description:<br> @@ -57,7 +59,7 @@ public class TextBoxListRenderer extends DefaultComponentRenderer { TextBoxListComponent tblComponent = (TextBoxListElementComponent) source; if (tblComponent.isEnabled()) { - renderEnabledMode(tblComponent, sb); + renderEnabledMode(tblComponent, sb, translator); } else { renderDisabledMode(tblComponent, sb); } @@ -72,18 +74,20 @@ public class TextBoxListRenderer extends DefaultComponentRenderer { * the StringOutput * @param translator */ - private void renderEnabledMode(TextBoxListComponent tblComponent, StringOutput sb) { + private void renderEnabledMode(TextBoxListComponent tblComponent, StringOutput sb, Translator translator) { TextBoxListElementImpl te = ((TextBoxListElementComponent)tblComponent).getTextElementImpl(); Form rootForm = te.getRootForm(); String dispatchId = tblComponent.getFormDispatchId(); - String initialValue = tblComponent.getInitialItemsAsString(); + String initialValue = tblComponent.getItemsAsString(); sb.append("<input type='text' id='textboxlistinput").append(dispatchId).append("'") .append(" name='textboxlistinput").append(dispatchId).append("'"); if (te.hasFocus()) { sb.append(" autofocus"); } - sb.append(" value='").append(initialValue).append("' />\n"); + sb.append(" value='").append(initialValue).append("'"); + Translator myTrans = Util.createPackageTranslator(this.getClass(), translator.getLocale()); + sb.append(" placeholder='").append(Formatter.escapeDoubleQuotes(myTrans.translate("add.enter"))).append("' class='o_textbox'/>\n"); String o_ffEvent = FormJSHelper.getJSFnCallFor(rootForm, dispatchId, 2); // generate the JS-code for the bootstrap tagsinput @@ -116,11 +120,13 @@ public class TextBoxListRenderer extends DefaultComponentRenderer { private void renderDisabledMode(TextBoxListComponent tblComponent, StringOutput output) { // read only view, we just display the initialItems as // comma-separated string - String readOnlyContent = tblComponent.getInitialItemsAsString(); + String readOnlyContent = tblComponent.getItemsAsString(); if (readOnlyContent.length() > 0) { - output.append("<div><i class='o_icon o_icon_tags'> </i> ") - .append(readOnlyContent) - .append("</div>"); + output.append("<span class='o_textbox_disabled'><i class='o_icon o_icon_tags'> </i> "); + for (String item : readOnlyContent.split(",")) { + output.append("<span class='tag label label-info'>").append(item.trim()).append("</span>"); + } + output.append("</span>"); } else { output.append("-"); } diff --git a/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_de.properties index 26a2de17429b57e840ada3623aeaae03bd2d403f..46a6d684d4ce87e1443a1857da1c80eb33b08396 100644 --- a/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_de.properties @@ -2,3 +2,4 @@ add.new.element.prefix=Hinzuf\u00fcgen please.wait.searching=Bitte warten. Suche nach: more.results.found.specify.search=Es wurden noch weitere Resultate gefunden, bitte Suche verfeinern. default.input.hint=Klicken Sie hier, um ein Element hinzuzuf\u00fcgen. Mehrere Elemente k\u00f6nnen mit Komma getrennt werden. +add.enter=Eingabe mit \u23CE abschliessen \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_en.properties index 6b01f8f346cef0f37b83a197308d53aad679375a..fb0744da518fb873cd240d703ce86f5dadda33df 100644 --- a/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_en.properties @@ -3,3 +3,4 @@ add.new.element.prefix=Add default.input.hint=Click here to add an element. Several elements can be separated by commas. more.results.found.specify.search=More search results found. Please refine your search. please.wait.searching=Please be patient. Searching for\: +add.enter=Terminate input with \u23CE \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_fr.properties index 83b8f1319903a9743bc2dfc7e8702234a964d298..1b8481a23982c1237b6457f8c3fc7596cbea5e73 100644 --- a/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_fr.properties @@ -1,5 +1,6 @@ -#Tue Feb 01 12:20:21 CET 2011 +#Tue Aug 15 17:15:12 CEST 2017 +add.enter=Computer l'entr\u00E9e avec \u23CE add.new.element.prefix=Ajouter default.input.hint=Cliquez ici pour ajouter un \u00E9l\u00E9ment. Plusieurs \u00E9l\u00E9ments doivent \u00EAtre s\u00E9par\u00E9s par des virgules. -more.results.found.specify.search=D'autres r\u00E9sultats ont \u00E9t\u00E9 trouv\u00E9s\: affinez la recherche, svp. +more.results.found.specify.search=D&\#39;autres r\u00E9sultats ont \u00E9t\u00E9 trouv\u00E9s\: affinez la recherche, svp. please.wait.searching=Attendre svp. recherche pour\: diff --git a/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_pt_BR.properties index 1b61b70d44fa9318e7695ec152baa418ff8110c9..77bd5d881fb18c0620c9e8c9d67036e6623607f6 100644 --- a/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/core/gui/components/textboxlist/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,5 @@ -#Thu Sep 08 16:42:37 CEST 2011 +#Tue Sep 05 22:51:18 CEST 2017 +add.enter=Terminada inser\u00E7\u00E3o com \u23CE add.new.element.prefix=Adicionar default.input.hint=Clique aqui para adicionar um elemento. V\u00E1rios elementos podem ser separados por v\u00EDrgulas. more.results.found.specify.search=Mais resultados encontrados. Por favor, refine a sua pesquisa. diff --git a/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java b/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java index a42a3f2122689302c7e9a7b96b2a210479c14241..e0f23760766447abc0aae111545d6126d2503e1c 100644 --- a/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java +++ b/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java @@ -80,6 +80,13 @@ public interface DTabs { */ public boolean addDTab(UserRequest ureq, DTab dt); + /** + * Update the title of an already instantiated tab. Use rarely + * @param ores + * @param newTitle + */ + public void updateDTabTitle(OLATResourceable ores, String newTitle); + /** * Remove a tab from tabs-list. * @param dt Remove this tab diff --git a/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java b/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java index 57ab19ecb5c27d99ff30e1aeb796bb9a5be4adaa..c181daa9d0029f628ca058bff9ea2151f32651ad 100644 --- a/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java +++ b/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java @@ -597,33 +597,9 @@ public class IFrameDeliveryMapper implements Mapper { appendStaticJs("js/prototype/prototype.js"); } - /* - MathJax.Hub.Config({ - extensions: ["jsMath2jax.js"], - messageStyle: 'none', - showProcessingMessages: false, - showMathMenu: false, - menuSettings: { }, - jsMath2jax: { - preview: "none" - }, - tex2jax: { - ignoreClass: "math" - }, - "HTML-CSS": { - EqnChunk: 5, EqnChunkFactor: 1, EqnChunkDelay: 100 - }, - "fast-preview": { - disabled: true - } - }); - */ public void appendJsMath() { - append("<script type=\"text/javascript\" src=\""); - append(WebappHelper.getMathJaxCdn()); - append("MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n"); append("<script type=\"text/javascript\">\n"); - append("MathJax.Hub.Config({\n"); + append("window.MathJax = {\n"); append(" extensions: [\"jsMath2jax.js\"],\n"); append(" messageStyle: 'none',\n"); append(" showProcessingMessages: false,\n"); @@ -641,8 +617,13 @@ public class IFrameDeliveryMapper implements Mapper { append(" \"fast-preview\": {\n"); append(" disabled: true\n"); append(" }\n"); - append("});"); + append("};"); append("</script>"); + append("<script type=\"text/javascript\" src=\""); + append(WebappHelper.getMathJaxCdn()); + append("MathJax.js?config="); + append(WebappHelper.getMathJaxConfig()); + append("\"></script>\n"); } public void appendGlossary() { diff --git a/src/main/java/org/olat/core/gui/control/navigation/NavElement.java b/src/main/java/org/olat/core/gui/control/navigation/NavElement.java index b6a67720dcf64a4a57e59edb2b20a55c9c4b61ca..c96ab52053fe9d646be4f3fb9d64efe22d72ba5a 100644 --- a/src/main/java/org/olat/core/gui/control/navigation/NavElement.java +++ b/src/main/java/org/olat/core/gui/control/navigation/NavElement.java @@ -43,7 +43,14 @@ public interface NavElement { * @return */ public String getTitle(); - + + /** + * Set a new title for the navigation, e.g. when a resource has been renamed + * + * @param title + */ + public void setTitle(String title); + /**[used by velocity] * @return */ diff --git a/src/main/java/org/olat/core/gui/media/FileMediaResource.java b/src/main/java/org/olat/core/gui/media/FileMediaResource.java index 54ba5d9640bb1be87b614b4f625a37505bfe0f69..fcfbba8f53892adfdc5bc09fe29bb9ecf6eb3254 100644 --- a/src/main/java/org/olat/core/gui/media/FileMediaResource.java +++ b/src/main/java/org/olat/core/gui/media/FileMediaResource.java @@ -34,8 +34,6 @@ import java.io.InputStream; import javax.servlet.http.HttpServletResponse; -import org.olat.core.CoreSpringFactory; -import org.olat.core.commons.modules.bc.FilesInfoMBean; import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; @@ -59,7 +57,6 @@ import org.olat.core.util.WebappHelper; public class FileMediaResource implements MediaResource { //TODO:fj:a clean up on all filemediaresources subclasses protected File file; - private FilesInfoMBean filesInfoMBean; private boolean unknownMimeType = false; private boolean deliverAsAttachment = false; @@ -87,7 +84,6 @@ public class FileMediaResource implements MediaResource { public FileMediaResource(File file, boolean deliverAsAttachment) { this.file = file; this.deliverAsAttachment = deliverAsAttachment; - this.filesInfoMBean = (FilesInfoMBean) CoreSpringFactory.getBean(FilesInfoMBean.class.getCanonicalName()); } @Override @@ -131,7 +127,6 @@ public class FileMediaResource implements MediaResource { BufferedInputStream bis = null; try { bis = new BufferedInputStream( new FileInputStream(file) ); - filesInfoMBean.logDownload(getSize()); } catch (FileNotFoundException e) { // } diff --git a/src/main/java/org/olat/core/gui/media/StringMediaResource.java b/src/main/java/org/olat/core/gui/media/StringMediaResource.java index 67f6f3eab5dae3106e236834f4c889ccdee44e95..47682f506158514490617339f9b05eb6bb662ad3 100644 --- a/src/main/java/org/olat/core/gui/media/StringMediaResource.java +++ b/src/main/java/org/olat/core/gui/media/StringMediaResource.java @@ -43,6 +43,8 @@ public class StringMediaResource extends DefaultMediaResource { //default - if no encoding is specified we assume iso latin private String encoding = "iso-8859-1"; private String data; + private boolean downloadable = false; + private String downloadFileName = null; @Override public boolean acceptRanges() { @@ -87,10 +89,30 @@ public class StringMediaResource extends DefaultMediaResource { hres.setHeader("Pragma", "no-cache"); hres.setDateHeader("Expires", 0); // + if (downloadable && downloadFileName != null) { + String filename = StringHelper.urlEncodeUTF8(downloadFileName); + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + filename); + } } @Override public String toString() { return data; } + + /** + * Set to true to force the browser to download the resource. This is done + * by set the content-disposition to attachment + * + * NOTE: make sure when writing the link to properly set the target or + * download attribute depending on the mime-type or the downloadable nature + * of the file! + * + * @param downloadable true: set to download; false: let browser decide + * @param downloadFileName name of the attachment if downloadable set to true + */ + public void setDownloadable(boolean downloadable, String downloadFileName) { + this.downloadable = downloadable; + this.downloadFileName = downloadFileName; + } } \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java b/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java index 28948bd0cc5b07ac3c796f85a49409984ca33140..f9f420dd5503060c278c1a26d281c4c7b78b9a73 100644 --- a/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java +++ b/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java @@ -196,6 +196,14 @@ public class VelocityRenderDecorator implements Closeable { return ""; } + public String javaScriptCommand(String command, boolean dirtyCheck, boolean pushState, String key1, String value1, String key2, String value2) { + renderer.getUrlBuilder().buildXHREvent(target, null, dirtyCheck, pushState, + new NameValuePair(VelocityContainer.COMMAND_ID, command), + new NameValuePair(key1, value1), + new NameValuePair(key2, value2)); + return ""; + } + /** * Creates the start of a java script fragment to execute a background request. It's * up to you to close the javascript call. @@ -209,6 +217,12 @@ public class VelocityRenderDecorator implements Closeable { return ""; } + public String openJavaScriptCommand(String command, boolean dirtyCheck, boolean pushState) { + renderer.getUrlBuilder().openXHREvent(target, null, dirtyCheck, pushState, + new NameValuePair(VelocityContainer.COMMAND_ID, command)); + return ""; + } + public String openNoResponseJavaScriptCommand(String command) { renderer.getUrlBuilder().openXHRNoResponseEvent(target, null, new NameValuePair(VelocityContainer.COMMAND_ID, command)); @@ -352,6 +366,12 @@ public class VelocityRenderDecorator implements Closeable { } return sb; } + + public StringOutput mathJaxConfig() { + StringOutput sb = new StringOutput(100); + sb.append(WebappHelper.getMathJaxConfig()); + return sb; + } public StringOutput contextPath() { StringOutput sb = new StringOutput(100); @@ -721,6 +741,16 @@ public class VelocityRenderDecorator implements Closeable { return false; } + public boolean isFalse(Object obj) { + if("falsse".equals(obj)) { + return true; + } + if(obj instanceof Boolean) { + return !((Boolean)obj).booleanValue(); + } + return false; + } + public boolean isNull(Object obj) { return obj == null; } @@ -811,6 +841,15 @@ public class VelocityRenderDecorator implements Closeable { return (source != null && source.isVisible() && source.isEnabled()); } + public boolean enabled(Component component) { + return component != null && component.isVisible() && component.isEnabled(); + } + + public boolean enabled(FormItem item) { + if(item == null) return false; + return enabled(item.getComponent()); + } + /** * Return the component * @param componentName @@ -972,15 +1011,17 @@ public class VelocityRenderDecorator implements Closeable { } public Languages getLanguages() { - I18nManager i18nMgr = I18nManager.getInstance(); - Collection<String> enabledKeysSet = I18nModule.getEnabledLanguageKeys(); + I18nManager i18nMgr = CoreSpringFactory.getImpl(I18nManager.class); + I18nModule i18nModule = CoreSpringFactory.getImpl(I18nModule.class); + + Collection<String> enabledKeysSet = i18nModule.getEnabledLanguageKeys(); Map<String, String> langNames = new HashMap<String, String>(); Map<String, String> langTranslators = new HashMap<String, String>(); String[] enabledKeys = ArrayHelper.toArray(enabledKeysSet); String[] names = new String[enabledKeys.length]; for (int i = 0; i < enabledKeys.length; i++) { String key = enabledKeys[i]; - String langName = i18nMgr.getLanguageInEnglish(key, I18nModule.isOverlayEnabled()); + String langName = i18nMgr.getLanguageInEnglish(key, i18nModule.isOverlayEnabled()); langNames.put(key, langName); names[i] = langName; String author = i18nMgr.getLanguageAuthor(key); diff --git a/src/main/java/org/olat/core/gui/translator/PackageTranslator.java b/src/main/java/org/olat/core/gui/translator/PackageTranslator.java index 2558f5c6fd58e4f550f8c16546967c98eec8fa45..563b388ad4e5f1e789aff7297a59acb5b706caf1 100644 --- a/src/main/java/org/olat/core/gui/translator/PackageTranslator.java +++ b/src/main/java/org/olat/core/gui/translator/PackageTranslator.java @@ -32,6 +32,7 @@ import java.io.Writer; import java.util.Locale; import org.apache.log4j.Level; +import org.olat.core.CoreSpringFactory; import org.olat.core.helpers.Settings; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.logging.OLog; @@ -51,12 +52,24 @@ public class PackageTranslator implements Translator { private final String packageName; private Locale locale; private int fallBackLevel = 0; + + private transient I18nModule i18nModule; + private transient I18nManager i18nManager; + private PackageTranslator(String packageName, Locale locale, boolean fallBack, Translator fallBackTranslator) { this.locale = locale; this.packageName = packageName; this.fallBackTranslator = fallBackTranslator; this.fallBack = fallBack; + i18nManager = CoreSpringFactory.getImpl(I18nManager.class); + i18nModule = CoreSpringFactory.getImpl(I18nModule.class); + } + + private Object readResolve() { + i18nManager = CoreSpringFactory.getImpl(I18nManager.class); + i18nModule = CoreSpringFactory.getImpl(I18nModule.class); + return this; } public void setFallBack(PackageTranslator fallback){ @@ -198,9 +211,8 @@ public class PackageTranslator implements Translator { */ @Override public String translate(String key, String[] args, boolean fallBackToDefaultLocale) { - I18nManager i18n = I18nManager.getInstance(); - boolean overlayEnabled = I18nModule.isOverlayEnabled(); - String val = i18n.getLocalizedString(packageName, key, args, locale, overlayEnabled, fallBackToDefaultLocale); + boolean overlayEnabled = i18nModule.isOverlayEnabled(); + String val = i18nManager.getLocalizedString(packageName, key, args, locale, overlayEnabled, fallBackToDefaultLocale); if (val == null) { // if not found, try the fallBackTranslator if (fallBackTranslator != null && fallBackLevel < 10) { @@ -209,10 +221,10 @@ public class PackageTranslator implements Translator { } else if (fallBack) { // both fallback and fallbacktranslator does not // make sense; latest translator in chain should // fallback to application fallback. - val = i18n.getLocalizedString(I18nModule.getApplicationFallbackBundle(), key, args, locale, overlayEnabled, fallBackToDefaultLocale); + val = i18nManager.getLocalizedString(i18nModule.getApplicationFallbackBundle(), key, args, locale, overlayEnabled, fallBackToDefaultLocale); if (val == null) { // lastly fall back to brasato framework fallback - val = i18n.getLocalizedString(I18nModule.getCoreFallbackBundle(), key, args, locale, overlayEnabled, fallBackToDefaultLocale); + val = i18nManager.getLocalizedString(i18nModule.getCoreFallbackBundle(), key, args, locale, overlayEnabled, fallBackToDefaultLocale); } } } diff --git a/src/main/java/org/olat/core/gui/util/WindowControlMocker.java b/src/main/java/org/olat/core/gui/util/WindowControlMocker.java index 1c93d3f510b450ec0ae19de0b0076be358f7efc6..8a5e35ddd9df02889f56bd76a285cf4a3408846d 100644 --- a/src/main/java/org/olat/core/gui/util/WindowControlMocker.java +++ b/src/main/java/org/olat/core/gui/util/WindowControlMocker.java @@ -22,13 +22,24 @@ package org.olat.core.gui.util; import java.util.Collections; import java.util.List; +import org.olat.core.gui.GlobalSettings; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.WindowManager; +import org.olat.core.gui.WindowSettings; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.Window; +import org.olat.core.gui.control.ChiefController; +import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowBackOffice; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; +import org.olat.core.gui.control.guistack.GuiStack; import org.olat.core.gui.control.info.WindowControlInfo; +import org.olat.core.gui.control.util.ZIndexWrapper; +import org.olat.core.gui.control.winmgr.Command; import org.olat.core.id.context.BusinessControl; import org.olat.core.id.context.ContextEntry; +import org.olat.core.util.event.GenericEventListener; public class WindowControlMocker implements WindowControl{ @@ -136,5 +147,98 @@ public class WindowControlMocker implements WindowControl{ return null; } + public class WindowBackOfficeMocker implements WindowBackOffice { + @Override + public void dispose() { + // TODO Auto-generated method stub + + } + + @Override + public WindowManager getWindowManager() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Window getWindow() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ChiefController getChiefController() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Controller createDevelopmentController(UserRequest ureq, WindowControl windowControl) { + // TODO Auto-generated method stub + return null; + } + + @Override + public GlobalSettings getGlobalSettings() { + // TODO Auto-generated method stub + return null; + } + + @Override + public WindowSettings getWindowSettings() { + return null; + } + + @Override + public void setWindowSettings(WindowSettings settings) { + // + + } + + @Override + public Controller createDebugDispatcherController(UserRequest ureq, WindowControl windowControl) { + return null; + } + + @Override + public Controller createInlineTranslationDispatcherController(UserRequest ureq, WindowControl windowControl) { + return null; + } + + @Override + public Controller createAJAXController(UserRequest ureq) { + return null; + } + + @Override + public boolean isDebuging() { + return false; + } + + @Override + public GuiStack createGuiStack(Component initialComponent) { + return null; + } + + @Override + public void sendCommandTo(Command wco) { + // + } + + @Override + public List<ZIndexWrapper> getGuiMessages() { + return null; + } + + @Override + public void addCycleListener(GenericEventListener gel) { + // + } + + @Override + public void removeCycleListener(GenericEventListener gel) { + // + } + } } diff --git a/src/main/java/org/olat/core/id/User.java b/src/main/java/org/olat/core/id/User.java index 6ae56a24694d3fbc7edfa22882513d8078ea58e5..a91134f158d68e8990660318adecaa288b8f3ae6 100644 --- a/src/main/java/org/olat/core/id/User.java +++ b/src/main/java/org/olat/core/id/User.java @@ -49,6 +49,8 @@ public interface User extends CreateInfo, Persistable { public String getLastName(); public String getEmail(); + + public String getInstitutionalEmail(); /** * Get the users prefereces object diff --git a/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java b/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java index 86e134302464386f0e9f516ea52fdef457551c02..75f3c56297bbc9c680b35c969af53cf0d75b3700 100644 --- a/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java +++ b/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java @@ -19,9 +19,13 @@ */ package org.olat.core.logging; +import static org.quartz.CronScheduleBuilder.cronSchedule; +import static org.quartz.JobBuilder.newJob; +import static org.quartz.TriggerBuilder.newTrigger; +import static org.quartz.impl.matchers.KeyMatcher.keyEquals; + import java.io.IOException; import java.io.StringWriter; -import java.text.ParseException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -31,6 +35,7 @@ import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.log4j.WriterAppender; import org.olat.core.CoreSpringFactory; +import org.olat.core.commons.services.scheduler.DummyJob; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.htmlheader.jscss.JSAndCSSComponent; @@ -41,14 +46,16 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.util.Formatter; -import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; +import org.quartz.JobKey; import org.quartz.JobListener; import org.quartz.Scheduler; import org.quartz.SchedulerException; -import org.quartz.jobs.NoOpJob; +import org.quartz.Trigger; +import org.quartz.TriggerKey; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -68,10 +75,13 @@ public class LogRealTimeViewerController extends BasicController implements JobL private Logger log4JLogger; private WriterAppender writerAppender; private StringWriter writer; - private JobDetail jobDetail; - private String jobName; + private JobKey jobKey; + private TriggerKey triggerKey; private Link updateLink, startLink, stopLink; private boolean removeLogNoise; + + @Autowired + private Scheduler scheduler; /** * Constructor for creating a real time log viewer controller @@ -106,21 +116,23 @@ public class LogRealTimeViewerController extends BasicController implements JobL updateLogViewFromWriter(); // Add job to read from the string writer every second try { - jobName = "Log_Displayer_Job_" + this.hashCode(); - jobDetail = new JobDetail(jobName, LOG_DISPLAYER_GROUP, NoOpJob.class); - jobDetail.addJobListener(jobName); - CronTrigger trigger = new CronTrigger(); - trigger.setName(jobName); - trigger.setGroup(LOG_DISPLAYER_GROUP); - trigger.setCronExpression("* * * * * ?"); + jobKey = new JobKey("Log_Displayer_Job_" + this.hashCode(), LOG_DISPLAYER_GROUP); + triggerKey = new TriggerKey("Log_Displayer_Trigger_" + this.hashCode(), LOG_DISPLAYER_GROUP); + + JobDetail jobDetail = newJob(DummyJob.class) + .withIdentity(jobKey) + .build(); + + Trigger trigger = newTrigger() + .withIdentity(triggerKey) + .withSchedule(cronSchedule("* * * * * ?")) + .build(); + // Schedule job now - Scheduler scheduler = (Scheduler) CoreSpringFactory.getBean("schedulerFactoryBean"); - scheduler.addJobListener(this); + scheduler.getListenerManager().addJobListener(this, keyEquals(jobKey)); scheduler.scheduleJob(jobDetail, trigger); - } catch (ParseException e) { + } catch (Exception e) { logError("Can not parse log viewer cron expression", e); - } catch (SchedulerException e) { - logError("Problem when creating log viewer scheduler", e); } // Add one second interval to update the log view every second JSAndCSSComponent jsc = new JSAndCSSComponent("intervall", this.getClass(), 3000); @@ -138,13 +150,12 @@ public class LogRealTimeViewerController extends BasicController implements JobL */ @Override protected void doDispose() { - if (logViewerVC != null) { // don't clean up twice Scheduler scheduler = (Scheduler) CoreSpringFactory.getBean("schedulerFactoryBean"); // remove scheduler job first try { - scheduler.deleteJob(jobName, LOG_DISPLAYER_GROUP); - scheduler.removeJobListener(jobName); + scheduler.deleteJob(jobKey); + scheduler.getListenerManager().removeJobListener(jobKey.getName()); } catch (SchedulerException e) { logError("Can not delete log viewer job", e); } @@ -193,44 +204,51 @@ public class LogRealTimeViewerController extends BasicController implements JobL protected void event(UserRequest ureq, Component source, Event event) { if (source == updateLink) { updateLogViewFromWriter(); + } else if (source == stopLink) { + doStop(); + } else if (source == startLink) { + doStart(); + } + } + + private void doStart() { + // update viewable links + logViewerVC.remove(startLink); + updateLink = LinkFactory.createButtonSmall("logviewer.link.update", logViewerVC, this); + stopLink = LinkFactory.createButtonSmall("logviewer.link.stop", logViewerVC, this); + // re-add appender to logger + log4JLogger.addAppender(writerAppender); + // resume trigger job + try { + Scheduler scheduler = (Scheduler) CoreSpringFactory.getBean("schedulerFactoryBean"); + scheduler.resumeJob(jobKey); + } catch (SchedulerException e) { + logError("Can not resume log viewer job", e); } - if (source == stopLink) { - // update viewable links - logViewerVC.remove(stopLink); - logViewerVC.remove(updateLink); - startLink = LinkFactory.createButtonSmall("logviewer.link.start", logViewerVC, this); - // remove logger appender - log4JLogger.removeAppender(writerAppender); - // pause log update trigger job - try { - Scheduler scheduler = (Scheduler) CoreSpringFactory.getBean("schedulerFactoryBean"); - scheduler.pauseJob(jobName, LOG_DISPLAYER_GROUP); - } catch (SchedulerException e) { - logError("Can not pause log viewer job", e); - } + } + + private void doStop() { + // update viewable links + logViewerVC.remove(stopLink); + logViewerVC.remove(updateLink); + startLink = LinkFactory.createButtonSmall("logviewer.link.start", logViewerVC, this); + // remove logger appender + log4JLogger.removeAppender(writerAppender); + // pause log update trigger job + try { + Scheduler scheduler = (Scheduler) CoreSpringFactory.getBean("schedulerFactoryBean"); + scheduler.pauseJob(jobKey); + } catch (SchedulerException e) { + logError("Can not pause log viewer job", e); } - if (source == startLink) { - // update viewable links - logViewerVC.remove(startLink); - updateLink = LinkFactory.createButtonSmall("logviewer.link.update", logViewerVC, this); - stopLink = LinkFactory.createButtonSmall("logviewer.link.stop", logViewerVC, this); - // re-add appender to logger - log4JLogger.addAppender(writerAppender); - // resume trigger job - try { - Scheduler scheduler = (Scheduler) CoreSpringFactory.getBean("schedulerFactoryBean"); - scheduler.resumeJob(jobName, LOG_DISPLAYER_GROUP); - } catch (SchedulerException e) { - logError("Can not resume log viewer job", e); - } - } } /** * @see org.quartz.JobListener#getName() */ + @Override public String getName() { - return jobName; + return jobKey.getName(); } /** diff --git a/src/main/java/org/olat/core/servlets/OpenOLATServlet.java b/src/main/java/org/olat/core/servlets/OpenOLATServlet.java index 5ead513dede58dba21151e5e832a4db0368ecd5a..b78d55c54b0dd309ab48bad9ea474f7868a46db5 100644 --- a/src/main/java/org/olat/core/servlets/OpenOLATServlet.java +++ b/src/main/java/org/olat/core/servlets/OpenOLATServlet.java @@ -36,7 +36,6 @@ import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.commons.services.taskexecutor.TaskExecutorManager; import org.olat.core.commons.services.webdav.WebDAVDispatcher; -import org.olat.core.configuration.AbstractOLATModule; import org.olat.core.configuration.AbstractSpringModule; import org.olat.core.configuration.PreWarm; import org.olat.core.dispatcher.Dispatcher; @@ -127,8 +126,6 @@ public class OpenOLATServlet extends HttpServlet { //preload extensions ExtManager.getInstance().getExtensions(); - - AbstractOLATModule.printStats(); AbstractSpringModule.printStats(); preWarm(); } diff --git a/src/main/java/org/olat/core/util/Formatter.java b/src/main/java/org/olat/core/util/Formatter.java index c3bef62e04dd71b62e272781b5dd7e180cc1751a..4b6ba05a9c6c6d17ff63d3cf39ccfeefb099924b 100644 --- a/src/main/java/org/olat/core/util/Formatter.java +++ b/src/main/java/org/olat/core/util/Formatter.java @@ -638,7 +638,7 @@ public class Formatter { if (htmlFragment.contains("<math") || htmlFragment.contains("class='math'") || htmlFragment.contains("class=\"math\"")) { // add math wrapper String domid = "mw_" + CodeHelper.getRAMUniqueID(); - String elem = htmlFragment.contains("<div") ? "div" : "span"; + String elem = htmlFragment.contains("<div") || htmlFragment.contains("<p") ? "div" : "span"; StringBuilder sb = new StringBuilder(htmlFragment.length() + 200); sb.append("<").append(elem).append(" id=\"").append(domid).append("\">"); sb.append(htmlFragment); @@ -661,6 +661,7 @@ public class Formatter { * @return text with clickable links */ public static String formatURLsAsLinks(String textFragment) { + if(textFragment == null) return ""; Matcher matcher = urlPattern.matcher(textFragment); StringBuilder sb = new StringBuilder(128); diff --git a/src/main/java/org/olat/core/util/WebappHelper.java b/src/main/java/org/olat/core/util/WebappHelper.java index 7fe810e3be566c02b04549d68785d0286cecc7b1..9b9431688e968da772d580a15e8ac3b1ab8ff70a 100644 --- a/src/main/java/org/olat/core/util/WebappHelper.java +++ b/src/main/java/org/olat/core/util/WebappHelper.java @@ -76,6 +76,7 @@ public class WebappHelper implements Initializable, Destroyable, ServletContextA private static long timeOfServerStartup = System.currentTimeMillis(); private static String mathJaxCdn; + private static String mathJaxConfig; private static String mobileContext; /** need to set this at least once before the actual request, since we cannot extract it from the servletContext, @@ -304,6 +305,14 @@ public class WebappHelper implements Initializable, Destroyable, ServletContextA WebappHelper.mathJaxCdn = mathJaxCdn; } + public static String getMathJaxConfig() { + return mathJaxConfig; + } + + public void setMathJaxConfig(String mathJaxConfig) { + WebappHelper.mathJaxConfig = mathJaxConfig; + } + public void setFullPathToSrc(String fullPathToSrc) { File path = new File(fullPathToSrc); if (path.exists()) { diff --git a/src/main/java/org/olat/core/util/ZipUtil.java b/src/main/java/org/olat/core/util/ZipUtil.java index 2d8d1fef843c742eb59b7077e94efa402ceb05b7..8c5b22b640cfa3686bf3995e1b0dd7f30a2a4baf 100644 --- a/src/main/java/org/olat/core/util/ZipUtil.java +++ b/src/main/java/org/olat/core/util/ZipUtil.java @@ -761,6 +761,39 @@ public class ZipUtil { } } + /** + * Add a directory to a zip stream. The files path are relative to the + * specified directory. The name of the directory is not part of + * the path of its files. + * + * @param path The directory to zip + * @param exportStream The stream + */ + public static void addPathToZip(final Path path, final ZipOutputStream exportStream) { + try { + Files.walkFileTree(path, new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if(!attrs.isDirectory()) { + Path relativeFile = path.relativize(file); + String names = relativeFile.toString(); + exportStream.putNextEntry(new ZipEntry(names)); + + try(InputStream in=Files.newInputStream(file)) { + FileUtils.copy(in, exportStream); + } catch (Exception e) { + log.error("", e); + } + + exportStream.closeEntry(); + } + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + log.error("", e); + } + } /** * Zip all files under a certain root directory. (with compression) diff --git a/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml b/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml index e48bab4999532f3ce0e2ca94b0b5a42dd3f2af5d..42bb91e467cf2ecdbf158b4e23929c6f4a1f10b0 100644 --- a/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml +++ b/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml @@ -8,7 +8,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - <context:component-scan base-package="org.olat.core.util.session,org.olat.core.util.vfs.version,org.olat.core.helpers" /> + <context:component-scan base-package="org.olat.core.util.session,org.olat.core.util.vfs.version,org.olat.core.util.i18n" /> <bean id="codeHelper" class="org.olat.core.util.CodeHelper" > <constructor-arg value="${node.id}" /> @@ -48,6 +48,7 @@ <property name="applicationName" value="${application.name}" /> <property name="mobileContext" value="${mobile.context}" /> <property name="mathJaxCdn" value="${mathjax.cdn}"/> + <property name="mathJaxConfig" value="${mathjax.config}"/> </bean> <bean id="org.olat.core.helpers.Settings" class="org.olat.core.helpers.Settings" depends-on="org.olat.core.util.WebappHelper"> diff --git a/src/main/java/org/olat/core/util/filter/impl/_resources/antisamy-tinymce.xml b/src/main/java/org/olat/core/util/filter/impl/_resources/antisamy-tinymce.xml index ccb76534a1751e9418b23427ab1b5dc27e3f8744..eeedb0d7b07e31a21ab00c8856a24d82046a6945 100644 --- a/src/main/java/org/olat/core/util/filter/impl/_resources/antisamy-tinymce.xml +++ b/src/main/java/org/olat/core/util/filter/impl/_resources/antisamy-tinymce.xml @@ -491,7 +491,13 @@ <tag name="dd" action="validate" /> <!-- Image & image related tags --> - + <tag name="figure" action="validate" > + <attribute name="class" /> + </tag> + <tag name="figcaption" action="validate" > + <attribute name="class" /> + </tag> + <tag name="img" action="validate"> <attribute name="src" onInvalid="removeTag"> <regexp-list> diff --git a/src/main/java/org/olat/core/util/i18n/I18nDirectoriesVisitor.java b/src/main/java/org/olat/core/util/i18n/I18nDirectoriesVisitor.java index bf1233447f337800632a052dd06b107aadbbff86..54bea141813157aaffb890e8a86fd5eec75956f1 100644 --- a/src/main/java/org/olat/core/util/i18n/I18nDirectoriesVisitor.java +++ b/src/main/java/org/olat/core/util/i18n/I18nDirectoriesVisitor.java @@ -36,9 +36,10 @@ import org.olat.core.util.FileVisitor; * @author gnaegi */ class I18nDirectoriesVisitor implements FileVisitor { - private OLog log = Tracing.createLoggerFor(I18nDirectoriesVisitor.class); + private static final OLog log = Tracing.createLoggerFor(I18nDirectoriesVisitor.class); private String basePath; private List<String> bundles = new LinkedList<String>(); + private final List<String> referenceLangKeys; /** * Packag scope constructor @@ -46,8 +47,9 @@ class I18nDirectoriesVisitor implements FileVisitor { * @param basePathConfig The base path to be subtracted from the file name to * get the classname */ - I18nDirectoriesVisitor(String basePathConfig) { + I18nDirectoriesVisitor(String basePathConfig, List<String> referenceLangKeys) { basePath = basePathConfig; + this.referenceLangKeys = referenceLangKeys; } /** @@ -58,7 +60,6 @@ class I18nDirectoriesVisitor implements FileVisitor { if (file.isFile()) { // regular file String toBeChechedkFilName = file.getName(); // match? - List<String> referenceLangKeys = I18nModule.getTransToolReferenceLanguages(); for (String langKey : referenceLangKeys) { String computedFileName = I18nModule.LOCAL_STRINGS_FILE_PREFIX + langKey + I18nModule.LOCAL_STRINGS_FILE_POSTFIX; if (toBeChechedkFilName.equals(computedFileName)) { diff --git a/src/main/java/org/olat/core/util/i18n/I18nManager.java b/src/main/java/org/olat/core/util/i18n/I18nManager.java index 1d96939ef143a72fc4913d1128b2522defb14315..2af4f1d209b79c0d1daaf87d2591f2f5ade0d61a 100644 --- a/src/main/java/org/olat/core/util/i18n/I18nManager.java +++ b/src/main/java/org/olat/core/util/i18n/I18nManager.java @@ -30,7 +30,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -71,9 +70,7 @@ import org.olat.core.helpers.Settings; import org.olat.core.logging.AssertException; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.logging.OLog; -import org.olat.core.logging.StartupException; import org.olat.core.logging.Tracing; -import org.olat.core.manager.BasicManager; import org.olat.core.util.AlwaysEmptyMap; import org.olat.core.util.CodeHelper; import org.olat.core.util.FileUtils; @@ -83,8 +80,8 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.UserSession; import org.olat.core.util.WebappHelper; import org.olat.core.util.session.UserSessionManager; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** @@ -96,12 +93,14 @@ import org.springframework.core.io.Resource; * * @author Felix Jost */ +@Service("I18nManager") +public class I18nManager { -public class I18nManager extends BasicManager { + private static final OLog log = Tracing.createLoggerFor(I18nManager.class); + private static final String BUNDLE_INLINE_TRANSLATION_INTERCEPTOR = "org.olat.core.util.i18n.ui"; private static final String BUNDLE_EXCEPTION = "org.olat.core.gui.exception"; private static I18nManager INSTANCE; - private static final OLog log = Tracing.createLoggerFor(I18nManager.class); public static final String FILE_NOT_FOUND_ERROR_PREFIX = ":::file not found"; public static final String USESS_KEY_I18N_MARK_LOCALIZED_STRINGS = "I18N_MARK_LOCALIZED_STRINGS"; @@ -139,17 +138,16 @@ public class I18nManager extends BasicManager { private ConcurrentMap<String, Properties> cachedBundles = new ConcurrentHashMap<String, Properties>(); private ConcurrentMap<String, String> cachedJSTranslatorData = new ConcurrentHashMap<String, String>(); private ConcurrentMap<String, Deque<String>> referencingBundlesIndex = new ConcurrentHashMap<String, Deque<String>>(); - private static final ConcurrentMap<Locale,String> localeToLocaleKey = new ConcurrentHashMap<>(); private boolean cachingEnabled = true; + + private final I18nModule i18nModule; - private static FilenameFilter i18nFileFilter = new FilenameFilter() { - public boolean accept(File dir, String name) { - // don't add overlayLocales as selectable availableLanguages - // (LocaleStrings_de__VENDOR.properties) - if (name.startsWith(I18nModule.LOCAL_STRINGS_FILE_PREFIX) && name.indexOf("_") != 0 && name.endsWith(I18nModule.LOCAL_STRINGS_FILE_POSTFIX)) { return true; } - return false; - } - }; + @Autowired + public I18nManager(I18nModule i18nModule) { + this.i18nModule = i18nModule; + setCachingEnabled(i18nModule.isCachingEnabled()); + INSTANCE = this; + } /** * @return the manager @@ -217,7 +215,7 @@ public class I18nManager extends BasicManager { // file if (overlayEnabled) { - Locale overlayLocale = I18nModule.getOverlayLocales().get(locale); + Locale overlayLocale = i18nModule.getOverlayLocales().get(locale); if (overlayLocale != null) { properties = getProperties(overlayLocale, bundleName, resolveRecursively, recursionLevel); if (properties != null) { @@ -257,7 +255,7 @@ public class I18nManager extends BasicManager { // 1. Check on variant String variant = locale.getVariant(); if (!variant.equals("")) { - Locale newLoc = I18nModule.getAllLocales().get(locale.getLanguage() + "_" + locale.getCountry()); + Locale newLoc = i18nModule.getAllLocales().get(locale.getLanguage() + "_" + locale.getCountry()); if (newLoc != null) msg = getLocalizedString(bundleName, key, args, newLoc, overlayEnabled, false, fallBackToFallbackLocale, resolveRecursively, recursionLevel); } @@ -265,7 +263,7 @@ public class I18nManager extends BasicManager { // 2. Check on country String country = locale.getCountry(); if (!country.equals("")) { - Locale newLoc = I18nModule.getAllLocales().get(locale.getLanguage()); + Locale newLoc = i18nModule.getAllLocales().get(locale.getLanguage()); if (newLoc != null) msg = getLocalizedString(bundleName, key, args, newLoc, overlayEnabled, false, fallBackToFallbackLocale, resolveRecursively, recursionLevel); } @@ -280,16 +278,16 @@ public class I18nManager extends BasicManager { // no: return null to indicate nothing was found so that callers may // use fallbacks if (fallBackToDefaultLocale) { - return getLocalizedString(bundleName, key, args, I18nModule.getDefaultLocale(), overlayEnabled, false, fallBackToFallbackLocale, + return getLocalizedString(bundleName, key, args, i18nModule.getDefaultLocale(), overlayEnabled, false, fallBackToFallbackLocale, resolveRecursively, recursionLevel); } else { if (fallBackToFallbackLocale) { // fallback to fallback locale - Locale fallbackLocale = I18nModule.getFallbackLocale(); + Locale fallbackLocale = i18nModule.getFallbackLocale(); if (fallbackLocale.equals(locale)) { // finish when when already in fallback locale - if (isLogDebugEnabled()) { - logWarn("Could not find translation for bundle::" + bundleName + " and key::" + key + if (log.isDebug()) { + log.warn("Could not find translation for bundle::" + bundleName + " and key::" + key + " ; not even in default or fallback packages", null); } return null; @@ -374,7 +372,7 @@ public class I18nManager extends BasicManager { * @return List of i18n items */ public List<I18nItem> findExistingI18nItems(Locale targetLocale, String limitToBundleName, boolean includeBundlesChildren) { - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); List<I18nItem> foundTranslationItems = new LinkedList<I18nItem>(); for (String bundleName : allBundles) { if (limitToBundleName == null || limitToBundleName.equals(bundleName) @@ -411,7 +409,7 @@ public class I18nManager extends BasicManager { */ public List<I18nItem> findMissingI18nItems(Locale referenceLocale, Locale targetLocale, String limitToBundleName, boolean includeBundlesChildren) { - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); List<I18nItem> foundTranslationItems = new LinkedList<I18nItem>(); for (String bundleName : allBundles) { if (limitToBundleName == null || limitToBundleName.equals(bundleName) @@ -450,7 +448,7 @@ public class I18nManager extends BasicManager { */ public List<I18nItem> findExistingAndMissingI18nItems(Locale referenceLocale, Locale targetLocale, String limitToBundleName, boolean includeBundlesChildren) { - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); List<I18nItem> foundTranslationItems = new LinkedList<I18nItem>(); for (String bundleName : allBundles) { if (limitToBundleName == null || limitToBundleName.equals(bundleName) @@ -504,7 +502,7 @@ public class I18nManager extends BasicManager { */ public List<I18nItem> findI18nItemsByValueSearch(String searchString, Locale searchLocale, Locale targetLocale, String limitToBundleName, boolean includeBundlesChildren) { - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); List<I18nItem> foundTranslationItems = new LinkedList<I18nItem>(); searchString = searchString.toLowerCase(); String[] parts = searchString.split("\\*"); @@ -553,7 +551,7 @@ public class I18nManager extends BasicManager { */ public List<I18nItem> findI18nItemsByKeySearch(String searchString, Locale searchLocale, Locale targetLocale, String limitToBundleName, boolean includeBundlesChildren) { - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); List<I18nItem> foundTranslationItems = new LinkedList<I18nItem>(); searchString = searchString.toLowerCase(); for (String bundleName : allBundles) { @@ -674,17 +672,17 @@ public class I18nManager extends BasicManager { public void saveOrUpdateI18nItem(I18nItem i18nItem, String value) { Properties properties = getPropertiesWithoutResolvingRecursively(i18nItem.getLocale(), i18nItem.getBundleName()); // Add logging block to find bogus save issues - if (isLogDebugEnabled()) { + if (log.isDebug()) { String itemIdent = i18nItem.getLocale() + ":" + buildI18nItemIdentifyer(i18nItem.getBundleName(), i18nItem.getKey()); if (properties.containsKey(i18nItem.getKey())) { if (StringHelper.containsNonWhitespace(value)) { - logDebug("Updating i18n item::" + itemIdent + " with new value::" + value, null); + log.debug("Updating i18n item::" + itemIdent + " with new value::" + value, null); } else { - logDebug("Deleting i18n item::" + itemIdent + " because new value is emty", null); + log.debug("Deleting i18n item::" + itemIdent + " because new value is emty", null); } } else { if (StringHelper.containsNonWhitespace(value)) { - logDebug("Creating i18n item::" + itemIdent + " with new value::" + value, null); + log.debug("Creating i18n item::" + itemIdent + " with new value::" + value, null); } } } @@ -731,7 +729,7 @@ public class I18nManager extends BasicManager { * @return */ public int countI18nItems(Locale locale, String limitToBundleName, boolean includeBundlesChildren) { - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); int counter = 0; for (String bundleName : allBundles) { if (limitToBundleName == null || limitToBundleName.equals(bundleName) @@ -755,7 +753,7 @@ public class I18nManager extends BasicManager { * @return */ public int countBundles(String limitToBundleName, boolean includeBundlesChildren) { - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); if (limitToBundleName == null) { return allBundles.size(); } else if (!includeBundlesChildren) { return (allBundles.contains(limitToBundleName) ? 1 : 0); } @@ -799,7 +797,7 @@ public class I18nManager extends BasicManager { // Try to resolve all keys within this properties and add to // cache if (resolveRecursively) { - resolvePropertiesInternalKeys(locale, bundleName, props, I18nModule.isOverlayEnabled(), recursionLevel); + resolvePropertiesInternalKeys(locale, bundleName, props, i18nModule.isOverlayEnabled(), recursionLevel); cachedBundles.put(key, props); } if (locale == null) { @@ -819,14 +817,14 @@ public class I18nManager extends BasicManager { // // 1) Try to load the bundle from a configured source path // This is also used to load the overlay properties - File baseDir = I18nModule.getPropertyFilesBaseDir(locale, bundleName); + File baseDir = i18nModule.getPropertyFilesBaseDir(locale, bundleName); if (baseDir != null) { File f = getPropertiesFile(locale, bundleName, baseDir); // if file exists load properties from file, otherwise // proceed with 2) if (f.exists()) { is = new FileInputStream(f); - if (logDebug) logDebug("loading LocalStrings from file::" + f.getAbsolutePath(), null); + if (logDebug) log.debug("loading LocalStrings from file::" + f.getAbsolutePath(), null); } } // @@ -838,7 +836,7 @@ public class I18nManager extends BasicManager { String relPath = bundleName.replace('.', '/') + "/" + I18N_DIRNAME + "/" + fileName; ClassLoader classLoader = this.getClass().getClassLoader(); is = classLoader.getResourceAsStream(relPath); - if (logDebug && is != null) logDebug("loading LocalStrings from classpath relpath::" + relPath, null); + if (logDebug && is != null) log.debug("loading LocalStrings from classpath relpath::" + relPath, null); } // Now load the properties from resource (file, classpath or // langpacks) @@ -974,10 +972,10 @@ public class I18nManager extends BasicManager { */ public void saveOrUpdateProperties(Properties properties, Locale locale, String bundleName) { String key = calcPropertiesFileKey(locale, bundleName); - if (isLogDebugEnabled()) logDebug("saveOrUpdateProperties for key::" + key, null); + if (log.isDebug()) log.debug("saveOrUpdateProperties for key::" + key, null); // 1) Save file to disk - File baseDir = I18nModule.getPropertyFilesBaseDir(locale, bundleName); + File baseDir = i18nModule.getPropertyFilesBaseDir(locale, bundleName); if (baseDir == null) { throw new AssertException("Can not save or update properties file for bundle::" + bundleName + " and language::" + locale.toString() + " - no base directory found, probably loaded from jar!"); } File propertiesFile = getPropertiesFile(locale, bundleName, baseDir); @@ -999,11 +997,11 @@ public class I18nManager extends BasicManager { try { if (fileStream != null) fileStream.close(); } catch (IOException e) { - logError("Could not close stream after save or update to file::" + propertiesFile.getAbsolutePath(), e); + log.error("Could not close stream after save or update to file::" + propertiesFile.getAbsolutePath(), e); } } // 2) Check if bundle was already in list of known bundles, add it - List<String> knownBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> knownBundles = i18nModule.getBundleNamesContainingI18nFiles(); if (!knownBundles.contains(bundleName)) { knownBundles.add(bundleName); Collections.sort(knownBundles); @@ -1038,7 +1036,7 @@ public class I18nManager extends BasicManager { */ public void deleteProperties(Locale locale, String bundleName) { String key = calcPropertiesFileKey(locale, bundleName); - if (isLogDebugEnabled()) logDebug("deleteProperties for key::" + key, null); + if (log.isDebug()) log.debug("deleteProperties for key::" + key, null); if (locale != null) { // metadata files are not in cache // 1) Remove from cache first @@ -1050,7 +1048,7 @@ public class I18nManager extends BasicManager { } } // 2) Remove from filesystem - File baseDir = I18nModule.getPropertyFilesBaseDir(locale, bundleName); + File baseDir = i18nModule.getPropertyFilesBaseDir(locale, bundleName); if (baseDir == null) { if (baseDir == null) { throw new AssertException("Can not delete properties file for bundle::" + bundleName + " and language::" + locale.toString() + " - no base directory found, probably loaded from jar!"); } @@ -1060,8 +1058,8 @@ public class I18nManager extends BasicManager { // 3) Check if for this bundle any other language file exists, if // not remove // the bundle from the list of translatable bundles - List<String> knownBundles = I18nModule.getBundleNamesContainingI18nFiles(); - Set<String> knownLangs = I18nModule.getAvailableLanguageKeys(); + List<String> knownBundles = i18nModule.getBundleNamesContainingI18nFiles(); + Set<String> knownLangs = i18nModule.getAvailableLanguageKeys(); boolean foundOther = false; for (String lang : knownLangs) { f = getPropertiesFile(getLocaleOrDefault(lang), bundleName, baseDir); @@ -1102,13 +1100,13 @@ public class I18nManager extends BasicManager { StringBuilder data = new StringBuilder(); // we build an js object with key-value pairs data.append("var transData = {"); - Locale referenceLocale = I18nModule.getFallbackLocale(); + Locale referenceLocale = i18nModule.getFallbackLocale(); Properties properties = getPropertiesWithoutResolvingRecursively(referenceLocale, bundleName); Set<Object> keys = properties.keySet(); boolean addComma = false; for (Object keyObject : keys) { String key = (String) keyObject; - String value = getLocalizedString(bundleName, key, null, locale, I18nModule.isOverlayEnabled(), true); + String value = getLocalizedString(bundleName, key, null, locale, i18nModule.isOverlayEnabled(), true); if (value == null) { // use bundlename:key as value in case the key can't be // translated @@ -1133,12 +1131,12 @@ public class I18nManager extends BasicManager { public JSONObject getJSONTranslatorData(Locale locale, String bundleName) { JSONObject array = new JSONObject(); - Locale referenceLocale = I18nModule.getFallbackLocale(); + Locale referenceLocale = i18nModule.getFallbackLocale(); Properties properties = getPropertiesWithoutResolvingRecursively(referenceLocale, bundleName); Set<Object> keys = properties.keySet(); for (Object keyObject : keys) { String key = (String) keyObject; - String value = getLocalizedString(bundleName, key, null, locale, I18nModule.isOverlayEnabled(), true); + String value = getLocalizedString(bundleName, key, null, locale, i18nModule.isOverlayEnabled(), true); if (value == null) { // use bundlename:key as value in case the key can't be // translated @@ -1151,7 +1149,7 @@ public class I18nManager extends BasicManager { try { array.put(key, value); } catch (JSONException e) { - logError("", e); + log.error("", e); } } return array; @@ -1165,7 +1163,7 @@ public class I18nManager extends BasicManager { * @return */ public Long getLastModifiedDate(Locale locale, String bundleName) { - File baseDir = I18nModule.getPropertyFilesBaseDir(locale, bundleName); + File baseDir = i18nModule.getPropertyFilesBaseDir(locale, bundleName); if (baseDir != null) { File propertyFile = getPropertiesFile(locale, bundleName, baseDir); return (propertyFile.lastModified()); @@ -1188,9 +1186,11 @@ public class I18nManager extends BasicManager { * method, or the default locale if the language was not found */ public Locale getLocaleOrDefault(String localeKey) { - if (localeKey == null || !I18nModule.getAvailableLanguageKeys().contains(localeKey)) { return I18nModule.getDefaultLocale(); } - Locale loc = I18nModule.getAllLocales().get(localeKey); - if (loc == null) loc = I18nModule.getDefaultLocale(); + if (localeKey == null || !i18nModule.getAvailableLanguageKeys().contains(localeKey)) { + return i18nModule.getDefaultLocale(); + } + Locale loc = i18nModule.getAllLocales().get(localeKey); + if (loc == null) loc = i18nModule.getDefaultLocale(); return loc; } @@ -1206,8 +1206,10 @@ public class I18nManager extends BasicManager { * method, or if no language was found */ public Locale getLocaleOrNull(String localeKey) { - if (localeKey == null || (!I18nModule.getAvailableLanguageKeys().contains(localeKey) && !I18nModule.getOverlayLanguageKeys().contains(localeKey))) { return null; } - Locale loc = I18nModule.getAllLocales().get(localeKey); + if (localeKey == null || (!i18nModule.getAvailableLanguageKeys().contains(localeKey) && !i18nModule.getOverlayLanguageKeys().contains(localeKey))) { + return null; + } + Locale loc = i18nModule.getAllLocales().get(localeKey); return loc; } @@ -1223,9 +1225,9 @@ public class I18nManager extends BasicManager { public String getLanguageTranslated(String languageKey, boolean overlayEnabled) { // Load it from package without fallback String translated = null; - Locale locale = I18nModule.getAllLocales().get(languageKey); + Locale locale = i18nModule.getAllLocales().get(languageKey); if(locale != null) { - translated = getLocalizedString(I18nModule.getCoreFallbackBundle(), "this.language.translated", null, locale, overlayEnabled, false, false, false, 0); + translated = getLocalizedString(i18nModule.getCoreFallbackBundle(), "this.language.translated", null, locale, overlayEnabled, false, false, false, 0); } if (translated == null) { // Use the english version as callback @@ -1242,12 +1244,12 @@ public class I18nManager extends BasicManager { * @return */ public Map<String, String> getEnabledLanguagesTranslated() { - Collection<String> enabledLangs = I18nModule.getEnabledLanguageKeys(); + Collection<String> enabledLangs = i18nModule.getEnabledLanguageKeys(); Map<String, String> translatedLangs = new HashMap<String, String>(11); for (String langKey : enabledLangs) { String translated = cachedLangTranslated.get(langKey); if(translated == null) { - String newTranslated = getLanguageTranslated(langKey, I18nModule.isOverlayEnabled()); + String newTranslated = getLanguageTranslated(langKey, i18nModule.isOverlayEnabled()); translated = cachedLangTranslated.putIfAbsent(langKey, newTranslated); if(translated == null) { translated = newTranslated; @@ -1268,7 +1270,7 @@ public class I18nManager extends BasicManager { */ public String getLanguageInEnglish(String languageKey, boolean overlayEnabled) { // Load it from package without fallback - String inEnglish = getLocalizedString(I18nModule.getCoreFallbackBundle(), "this.language.in.english", null, I18nModule + String inEnglish = getLocalizedString(i18nModule.getCoreFallbackBundle(), "this.language.in.english", null, i18nModule .getAllLocales().get(languageKey), overlayEnabled, false, false, false, 0); if (inEnglish == null) { // use key as fallback @@ -1287,7 +1289,7 @@ public class I18nManager extends BasicManager { */ public String getLanguageAuthor(String languageKey) { // Load it from package without fallback - String authors = getLocalizedString(I18nModule.getCoreFallbackBundle(), "this.language.translator.names", null, I18nModule + String authors = getLocalizedString(i18nModule.getCoreFallbackBundle(), "this.language.translator.names", null, i18nModule .getAllLocales().get(languageKey), false, false, false, false, 0); if (authors == null) { return "-"; } return authors; @@ -1322,21 +1324,18 @@ public class I18nManager extends BasicManager { public static void attachI18nInfoToThread(HttpServletRequest hreq) { UserSession usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(hreq); if (threadLocalLocale == null) { - I18nManager.getInstance().logError("can't attach i18n info to thread: threadLocalLocale is null", null); + log.error("can't attach i18n info to thread: threadLocalLocale is null", null); } else { if (threadLocalLocale.getThreadLocale() != null) { - I18nManager.getInstance().logWarn( - "try to attach i18n info to thread, but threadLocalLocale is not null - a thread forgot to remove it!", new Exception("attachI18nInfoToThread")); + log.warn("try to attach i18n info to thread, but threadLocalLocale is not null - a thread forgot to remove it!", new Exception("attachI18nInfoToThread")); } threadLocalLocale.setThredLocale(usess.getLocale()); } if (threadLocalIsMarkLocalizedStringsEnabled == null) { - I18nManager.getInstance().logError("can't attach i18n info to thread: threadLocalIsMarkLocalizedStringsEnabled is null", null); + log.error("can't attach i18n info to thread: threadLocalIsMarkLocalizedStringsEnabled is null", null); } else { if (threadLocalIsMarkLocalizedStringsEnabled.isMarkLocalizedStringsEnabled() != null) { - I18nManager.getInstance().logWarn( - "try to attach i18n info to thread, but threadLocalIsMarkLocalizedStringsEnabled is not null - a thread forgot to remove it!", - null); + log.warn("try to attach i18n info to thread, but threadLocalIsMarkLocalizedStringsEnabled is not null - a thread forgot to remove it!", null); } Boolean isMarkLocalizedStringsEnabled = (Boolean) usess.getEntry(USESS_KEY_I18N_MARK_LOCALIZED_STRINGS); if (isMarkLocalizedStringsEnabled != null) { @@ -1347,7 +1346,7 @@ public class I18nManager extends BasicManager { public static void updateLocaleInfoToThread(UserSession usess) { if (threadLocalLocale == null) { - I18nManager.getInstance().logError("can't attach i18n info to thread: threadLocalLocale is null", null); + log.error("can't attach i18n info to thread: threadLocalLocale is null", null); } else { threadLocalLocale.setThredLocale(usess.getLocale()); } @@ -1377,7 +1376,7 @@ public class I18nManager extends BasicManager { Locale locale = threadLocalLocale.getThreadLocale(); if (locale != null) return threadLocalLocale.getThreadLocale(); } - return I18nModule.getDefaultLocale(); + return i18nModule.getDefaultLocale(); } /** @@ -1431,7 +1430,7 @@ public class I18nManager extends BasicManager { try { return (Integer.parseInt(bundlePrioValue.trim())); } catch (NumberFormatException e) { - logWarn("Can not parse metadata priority for bundle::" + bundleName, e); + log.warn("Can not parse metadata priority for bundle::" + bundleName, e); } } // 2) Not found, try with parent bundle @@ -1459,7 +1458,7 @@ public class I18nManager extends BasicManager { try { keyPriority = Integer.parseInt(keyPriorityValue.trim()); } catch (NumberFormatException e) { - logWarn("Can not parse metadata priority for key::" + bundleName + ":" + key, e); + log.warn("Can not parse metadata priority for key::" + bundleName + ":" + key, e); } } return keyPriority; @@ -1596,7 +1595,7 @@ public class I18nManager extends BasicManager { cachedJSTranslatorData = new AlwaysEmptyMap<String, String>(); referencingBundlesIndex = new AlwaysEmptyMap<String, Deque<String>>(); } - this.cachingEnabled = useCache; + cachingEnabled = useCache; } /** @@ -1604,74 +1603,7 @@ public class I18nManager extends BasicManager { * filesystem */ public boolean isCachingEnabled() { - return this.cachingEnabled; - } - - /** - * Helper method to create a locale from a given locale key ('de', 'de_CH', - * 'de_CH_ZH') - * - * @param localeKey - * @return the locale or NULL if no locale could be generated from this string - */ - Locale createLocale(String localeKey) { - Locale aloc = null; - // de - // de_CH - // de_CH_zueri - String[] parts = localeKey.split("_"); - switch (parts.length) { - case 1: - aloc = new Locale(parts[0]); - break; - case 2: - aloc = new Locale(parts[0], parts[1]); - break; - case 3: - String lastPart = parts[2]; - // Add all remaining parts to variant, variant can contain - // underscores according to Locale spec - for (int i = 3; i < parts.length; i++) { - String part = parts[i]; - lastPart = lastPart + "_" + part; - } - aloc = new Locale(parts[0], parts[1], lastPart); - break; - default: - return null; - } - // Test if the locale has been constructed correctly. E.g. when the - // language part is not existing in the ISO chart, the locale can - // convert to something else. - // E.g. he_HE_HE will convert automatically to iw_HE_HE - if (aloc.toString().equals(localeKey)) { - return aloc; - } else { - return null; - } - } - - /** - * Create a local that represents the overlay locale for the given locale - * - * @param locale The original locale - * @return The overlay locale - */ - Locale createOverlay(Locale locale) { - String lang = locale.getLanguage(); - String country = (locale.getCountry() == null ? "" : locale.getCountry()); - String variant = createOverlayKeyForLanguage(locale.getVariant() == null ? "" : locale.getVariant()); - Locale overlay = new Locale(lang, country, variant); - return overlay; - } - - /** - * Add the overlay postfix to the given language key - * @param langKey - * @return - */ - String createOverlayKeyForLanguage(String langKey) { - return langKey + "__" + I18nModule.getOverlayName(); + return cachingEnabled; } /** @@ -1686,49 +1618,10 @@ public class I18nManager extends BasicManager { * @return */ public String buildI18nFilename(Locale locale) { - String langKey = getLocaleKey(locale); + String langKey = i18nModule.getLocaleKey(locale); return I18nModule.LOCAL_STRINGS_FILE_PREFIX + langKey + I18nModule.LOCAL_STRINGS_FILE_POSTFIX; } - /** - * Calculate the locale key that identifies the given locale. Adds support for - * the overlay mechanism. - * - * @param locale - * @return - */ - public String getLocaleKey(Locale locale) { - String key = localeToLocaleKey.get(locale); - if(key == null) { - String langKey = locale.getLanguage(); - String country = locale.getCountry(); - // Only add country when available - in case of an overlay country is - // set to - // an empty value - if (StringHelper.containsNonWhitespace(country)) { - langKey = langKey + "_" + country; - } - String variant = locale.getVariant(); - // Only add the _ separator if the variant contains something in - // addition to - // the overlay, otherways use the __ only - if (StringHelper.containsNonWhitespace(variant)) { - if (variant.startsWith("__" + I18nModule.getOverlayName())) { - langKey += variant; - } else { - langKey = langKey + "_" + variant; - } - } - - key = localeToLocaleKey.putIfAbsent(locale, langKey); - if(key == null) { - key = langKey; - } - - } - return key; - } - /** * Calculate the language key from the given overlay locale without the locale * (the original language before adding the overlay postfix) @@ -1737,11 +1630,11 @@ public class I18nManager extends BasicManager { * @return The original language key or NULL if not found */ public String createOrigianlLocaleKeyForOverlay(Locale overlay) { - Map<Locale,Locale> overlaysLooup = I18nModule.getOverlayLocales(); + Map<Locale,Locale> overlaysLooup = i18nModule.getOverlayLocales(); Set<Map.Entry<Locale, Locale>> entries = overlaysLooup.entrySet(); for (Map.Entry<Locale, Locale> entry : entries) { - if (getLocaleKey(entry.getValue()).equals(getLocaleKey(overlay))) { - return getLocaleKey(entry.getKey()); + if (i18nModule.getLocaleKey(entry.getValue()).equals(i18nModule.getLocaleKey(overlay))) { + return i18nModule.getLocaleKey(entry.getKey()); } } return null; @@ -1758,79 +1651,6 @@ public class I18nManager extends BasicManager { return bundleName + ":" + key; } - /** - * Search in all packages on the source patch for packages that contain an - * _i18n directory that can be used to store olatcore localization files - * - * @return set of bundles that contain olatcore i18n compatible localization - * files - */ - List<String> searchForBundleNamesContainingI18nFiles() { - List<String> foundBundles; - // 1) First search on normal source path of application - String srcPath = null; - File applicationDir = I18nModule.getTransToolApplicationLanguagesSrcDir(); - if (applicationDir != null) { - srcPath = applicationDir.getAbsolutePath(); - } else { - // Fall back to compiled classes - srcPath = WebappHelper.getBuildOutputFolderRoot(); - } - if(StringHelper.containsNonWhitespace(srcPath)) { - I18nDirectoriesVisitor srcVisitor = new I18nDirectoriesVisitor(srcPath); - FileUtils.visitRecursively(new File(srcPath), srcVisitor); - foundBundles = srcVisitor.getBundlesContainingI18nFiles(); - // 3) For jUnit tests, add also the I18n test dir - if (Settings.isJUnitTest()) { - Resource testres = new ClassPathResource("olat.local.properties"); - String jUnitSrcPath = null; - try { - jUnitSrcPath = testres.getFile().getAbsolutePath(); - } catch (IOException e) { - throw new StartupException("Could not find classpath resource for: test-classes/olat.local.property ", e); - } - - - I18nDirectoriesVisitor juniSrcVisitor = new I18nDirectoriesVisitor(jUnitSrcPath); - FileUtils.visitRecursively(new File(jUnitSrcPath), juniSrcVisitor); - foundBundles.addAll(juniSrcVisitor.getBundlesContainingI18nFiles()); - } - // Sort alphabetically - Collections.sort(foundBundles); - } else { - foundBundles = new ArrayList<String>(); - } - return foundBundles; - } - - /** - * Search for available languages in the given directory. The translation - * files must start with 'LocalStrings_' and end with '.properties'. - * Everything in between is considered a language key. - * <p> - * If the directory contains jar files, those files are opened and searched - * for languages files as well. In this case, the algorythm only looks for - * translation files that are in the org/olat/core/_i18n package - * - * @param i18nDir - * @return set of language keys the system will find translations for - */ - Set<String> searchForAvailableLanguages(File i18nDir) { - Set<String> foundLanguages = new TreeSet<String>(); - i18nDir = new File(i18nDir.getAbsolutePath()+"/org/olat/_i18n"); - if (i18nDir.exists()) { - // First check for locale files - String[] langFiles = i18nDir.list(i18nFileFilter); - for (String langFileName : langFiles) { - String lang = langFileName.substring(I18nModule.LOCAL_STRINGS_FILE_PREFIX.length(), langFileName.lastIndexOf(".")); - foundLanguages.add(lang); - if (isLogDebugEnabled()) logDebug("Adding lang::" + lang + " from filename::" + langFileName + " from dir::" - + i18nDir.getAbsolutePath(), null); - } - } - return foundLanguages; - } - /** * Searches within a jar file for available languages. * @@ -1852,15 +1672,14 @@ public class I18nManager extends BasicManager { // check for executables if (checkForExecutables && (jarEntryName.endsWith("java") || jarEntryName.endsWith("class"))) { return new TreeSet<String>(); } // search for core util in jar - if (jarEntryName.indexOf(I18nModule.getCoreFallbackBundle().replace(".", "/") + "/" + I18N_DIRNAME) != -1) { + if (jarEntryName.indexOf(i18nModule.getCoreFallbackBundle().replace(".", "/") + "/" + I18N_DIRNAME) != -1) { // don't add overlayLocales as selectable // availableLanguages if (jarEntryName.indexOf("__") == -1 && jarEntryName.indexOf(I18nModule.LOCAL_STRINGS_FILE_PREFIX) != -1) { String lang = jarEntryName.substring(jarEntryName.indexOf(I18nModule.LOCAL_STRINGS_FILE_PREFIX) + I18nModule.LOCAL_STRINGS_FILE_PREFIX.length(), jarEntryName.lastIndexOf(".")); foundLanguages.add(lang); - if (isLogDebugEnabled()) logDebug("Adding lang::" + lang + " from filename::" + jarEntryName + " in jar::" + jar.getName(), - null); + if (log.isDebug()) log.debug("Adding lang::" + lang + " from filename::" + jarEntryName + " in jar::" + jar.getName(), null); } } } @@ -1881,7 +1700,7 @@ public class I18nManager extends BasicManager { * @param toCopyI18nKeys */ public void copyLanguagesFromJar(File jarFile, Collection<String> toCopyI18nKeys) { - if (!I18nModule.isTransToolEnabled()) { + if (!i18nModule.isTransToolEnabled()) { throw new AssertException("Programming error - can only copy i18n files from a language pack to the source when in translation mode"); } JarFile jar = null; @@ -1896,9 +1715,9 @@ public class I18nManager extends BasicManager { if (jarEntryName.endsWith(I18N_DIRNAME + "/" + I18nModule.LOCAL_STRINGS_FILE_PREFIX + i18nKey + I18nModule.LOCAL_STRINGS_FILE_POSTFIX)) { File targetBaseDir; if (i18nKey.equals("de") || i18nKey.equals("en")) { - targetBaseDir = I18nModule.getTransToolApplicationLanguagesSrcDir(); + targetBaseDir = i18nModule.getTransToolApplicationLanguagesSrcDir(); } else { - targetBaseDir = I18nModule.getTransToolApplicationOptLanguagesSrcDir(); + targetBaseDir = i18nModule.getTransToolApplicationOptLanguagesSrcDir(); } // Copy file File targetFile = new File(targetBaseDir, jarEntryName); @@ -1948,18 +1767,18 @@ public class I18nManager extends BasicManager { String relPath = "/" + bundleName + "/" + I18N_DIRNAME + "/" + fileName; // Load file from path File f = new File(sourceDir, relPath); - if (f.exists() || I18nModule.isTransToolEnabled()) { return f; } + if (f.exists() || i18nModule.isTransToolEnabled()) { return f; } return f; } public boolean createNewLanguage(String localeKey, String languageInEnglish, String languageTranslated, String authors) { - if (!I18nModule.isTransToolEnabled()) { throw new AssertException( + if (!i18nModule.isTransToolEnabled()) { throw new AssertException( "Can not create a new language when the translation tool is not enabled and the transtool source pathes are not configured! Check your olat.properties files"); } - if (I18nModule.getAvailableLanguageKeys().contains(localeKey)) { return false; } + if (i18nModule.getAvailableLanguageKeys().contains(localeKey)) { return false; } // Create new property file in the brasato bundle and re-initialize // everything - String coreFallbackBundle = I18nModule.getApplicationFallbackBundle(); - File transToolCoreLanguagesDir = I18nModule.getTransToolApplicationOptLanguagesSrcDir(); + String coreFallbackBundle = i18nModule.getApplicationFallbackBundle(); + File transToolCoreLanguagesDir = i18nModule.getTransToolApplicationOptLanguagesSrcDir(); String i18nDirRelPath = "/" + coreFallbackBundle.replace(".", "/") + "/" + I18nManager.I18N_DIRNAME; File transToolCoreLanguagesDir_I18n = new File(transToolCoreLanguagesDir, i18nDirRelPath); File newPropertiesFile = new File(transToolCoreLanguagesDir_I18n, I18nModule.LOCAL_STRINGS_FILE_PREFIX + localeKey @@ -1987,12 +1806,12 @@ public class I18nManager extends BasicManager { newProperties.store(fileStream, null); fileStream.flush(); // Now set new language as enabled to allow user to translate the language. - Collection<String> enabledLangKeys = I18nModule.getEnabledLanguageKeys(); + Collection<String> enabledLangKeys = i18nModule.getEnabledLanguageKeys(); enabledLangKeys.add(localeKey); // Reinitialize languages with new language - I18nModule.reInitializeAndFlushCache(); + i18nModule.reInitializeAndFlushCache(); // Now add new language as new language (will re-initialize everything a second time) - I18nModule.setEnabledLanguageKeys(enabledLangKeys); + i18nModule.setEnabledLanguageKeys(enabledLangKeys); return true; } catch (FileNotFoundException e) { @@ -2004,7 +1823,7 @@ public class I18nManager extends BasicManager { try { if (fileStream != null) fileStream.close(); } catch (IOException e) { - logError("Could not close stream after creating new language file::" + newPropertiesFile.getAbsolutePath(), e); + log.error("Could not close stream after creating new language file::" + newPropertiesFile.getAbsolutePath(), e); } } } @@ -2017,22 +1836,22 @@ public class I18nManager extends BasicManager { * logging */ public void deleteLanguage(String deleteLangKey, boolean reallyDeleteIt) { - Locale deleteLoclae = I18nModule.getAllLocales().get(deleteLangKey); + Locale deleteLoclae = i18nModule.getAllLocales().get(deleteLangKey); // copy bundles list to prevent concurrent modification exception List<String> bundlesCopy = new ArrayList<String>(); - bundlesCopy.addAll(I18nModule.getBundleNamesContainingI18nFiles()); + bundlesCopy.addAll(i18nModule.getBundleNamesContainingI18nFiles()); for (String bundleName : bundlesCopy) { if (reallyDeleteIt) { deleteProperties(deleteLoclae, bundleName); - logDebug("Deleted bundle::" + bundleName + " and lang::" + deleteLangKey, null); + log.debug("Deleted bundle::" + bundleName + " and lang::" + deleteLangKey, null); } else { // just log - logInfo("Dry-run-delete of bundle::" + bundleName + " and lang::" + deleteLangKey, null); + log.info("Dry-run-delete of bundle::" + bundleName + " and lang::" + deleteLangKey, null); } } // Now reinitialize everything if (reallyDeleteIt) { - I18nModule.reInitializeAndFlushCache(); + i18nModule.reInitializeAndFlushCache(); } } @@ -2065,7 +1884,7 @@ public class I18nManager extends BasicManager { for (String langKey : languageKeys) { Locale locale = getLocaleOrNull(langKey); // Add all bundles in the current language - for (String bundleName : I18nModule.getBundleNamesContainingI18nFiles()) { + for (String bundleName : i18nModule.getBundleNamesContainingI18nFiles()) { Properties propertyFile = getPropertiesWithoutResolvingRecursively(locale, bundleName); String entryFileName = bundleName.replace(".", "/") + "/" + I18N_DIRNAME + "/" + buildI18nFilename(locale); // Create jar entry for this path, name and last modified @@ -2074,21 +1893,21 @@ public class I18nManager extends BasicManager { // Write properties to jar file out.putNextEntry(jarEntry); propertyFile.store(out, null); - if (isLogDebugEnabled()) { - logDebug("Adding file::" + entryFileName + " + to jar", null); + if (log.isDebug()) { + log.debug("Adding file::" + entryFileName + " + to jar", null); } } } - logDebug("Finished writing jar file::" + file.getAbsolutePath(), null); + log.debug("Finished writing jar file::" + file.getAbsolutePath(), null); } catch (Exception e) { - logError("Could not write jar file", e); + log.error("Could not write jar file", e); return null; } finally { try { out.close(); stream.close(); } catch (IOException e) { - logError("Could not close stream of jar file", e); + log.error("Could not close stream of jar file", e); return null; } } @@ -2099,12 +1918,6 @@ public class I18nManager extends BasicManager { * Private helper methods *************************/ - /** - * [used by spring] - */ - private I18nManager() { - INSTANCE = this; - } /** * Helper method to create a key that uniquely identifies a property file @@ -2119,7 +1932,7 @@ public class I18nManager extends BasicManager { if (locale == null) { return bundleName + ":" + METADATA_KEY; } else { - return bundleName + ":" + getLocaleKey(locale); + return bundleName + ":" + i18nModule.getLocaleKey(locale); } } diff --git a/src/main/java/org/olat/core/util/i18n/I18nModule.java b/src/main/java/org/olat/core/util/i18n/I18nModule.java index e893d0520696b67e2f5e30222148c1eab1ffc8dc..3957c24f119a078dd35513f96c9547ea4f91fe32 100644 --- a/src/main/java/org/olat/core/util/i18n/I18nModule.java +++ b/src/main/java/org/olat/core/util/i18n/I18nModule.java @@ -21,29 +21,40 @@ package org.olat.core.util.i18n; import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; -import org.olat.core.configuration.AbstractOLATModule; -import org.olat.core.configuration.Destroyable; -import org.olat.core.configuration.PersistedProperties; +import org.olat.core.configuration.AbstractSpringModule; import org.olat.core.gui.control.Event; import org.olat.core.helpers.Settings; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.logging.OLog; +import org.olat.core.logging.StartupException; import org.olat.core.logging.Tracing; import org.olat.core.util.ArrayHelper; +import org.olat.core.util.FileUtils; import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.resource.OresHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Service; /** * <h3>Description:</h3> The I18nModule initializes the localization @@ -54,8 +65,8 @@ import org.olat.core.util.resource.OresHelper; * * @author Florian Gnaegi, frentix GmbH, http://www.frentix.com */ - -public class I18nModule extends AbstractOLATModule implements Destroyable { +@Service("i18nModule") +public class I18nModule extends AbstractSpringModule { private static final OLog log = Tracing.createLoggerFor(I18nModule.class); @@ -81,71 +92,75 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { private static final String CONFIG_LANGUAGES_ENABLED = "enabledLanguages"; private static final String CONFIG_LANGUAGES_ENABLED_ALL = "all"; private static final String CONFIG_DEFAULT_LANG = "defaultLanguage"; - private static final String CONFIG_FALLBACK_LANG = "fallbackLanguage"; - private static final String CONFIG_LANGUAGES_REFERENCES = "transToolReferenceLanguages"; - private static final String CONFIG_OVERLAY = "overlayName"; - private static final String CONFIG_OVERLAY_ENABLED = "overlayEnabled"; - private static final String CONFIG_CACHING_ENABLED = "cachingEnabled"; - private static final String CONFIG_LANGUAGE_LIST_ENABLED = "dropDownListEnabled"; - private static final String CONFIG_APPLICATION_FALLBACK_BUNDLE = "applicationFallbackBundle"; - private static final String CONFIG_CORE_FALLBACK_BUNDLE = "coreFallbackBundle"; - private static final String CONFIG_TRANS_TOOL_ENABLED = "transToolEnabled"; - private static final String CONFIG_TRANS_TOOL_APPLICATION_SRC_PATH = "transToolApplicationSrcPath"; - private static final String CONFIG_TRANS_TOOL_APPLICATION_OPT_SRC_PATH = "transToolApplicationOptSrcPath"; + + @Value("${enabledLanguages}") + private String enabledLanguages; + @Value("${defaultlang:en}") + private String defaultLanguage; + @Value("${fallbacklang:en}") + private String fallbackLanguage; // General configuration - private static String overlayName; - private static boolean overlayEnabled; - private static boolean cachingEnabled; - private static boolean languageDropDownListEnabled; + private final String overlayName = "customizing"; + private final boolean overlayEnabled = true; + + @Value("${localization.cache:true}") + private boolean cachingEnabled; + private boolean languageDropDownListEnabled = true; // Lists of the available and enabled languages and locales - private static final Set<String> availableLanguages = new HashSet<String>(); - private static final Set<String> translatableLanguages = new HashSet<String>(); - private static final Map<String, File> translatableLangAppBaseDirLookup = new HashMap<String, File>(); + private final Set<String> availableLanguages = new HashSet<>(); + private final Set<String> translatableLanguages = new HashSet<>(); + private final Map<String, File> translatableLangAppBaseDirLookup = new HashMap<>(); // keys: lang string, values: locale - private static final Map<String, Locale> allLocales = new HashMap<String, Locale>(); + private static final Map<String, Locale> allLocales = new HashMap<>(); // keys: orig Locale, values: overlay Locale - private static final Map<Locale, Locale> overlayLocales = new HashMap<Locale, Locale>(); - private static final Set<String> overlayLanguagesKeys = new HashSet<String>(); - private static final Set<String> enabledLanguagesKeys = new HashSet<String>(); + private final Map<Locale, Locale> overlayLocales = new HashMap<>(); + private final Set<String> overlayLanguagesKeys = new HashSet<>(); + private final Set<String> enabledLanguagesKeys = new HashSet<>(); // The default locale (used on loginscreen and as first fallback) and the // fallback (used as second fallback) private static Locale defaultLocale; - private static Locale fallbackLocale; + private Locale fallbackLocale; // The available bundles - private static List<String> bundleNames = null; // sorted alphabetically - private static String coreFallbackBundle = null; - private static String applicationFallbackBundle = null; + private List<String> bundleNames; // sorted alphabetically + + private final String coreFallbackBundle = "org.olat.core"; + private final String applicationFallbackBundle = "org.olat"; + // Translation tool related configuration - private static final List<String> transToolReferenceLanguages = new ArrayList<String>(); - private static File transToolApplicationLanguagesDir = null; - private static File transToolApplicationOptLanguagesSrcDir = null; - private static boolean transToolEnabled = false; + private final List<String> transToolReferenceLanguages = new ArrayList<>(); + + @Value("${i18n.application.src.dir}") + private String transToolApplicationSrcPath; + private File transToolApplicationLanguagesDir; + @Value("${i18n.application.opt.src.dir}") + private String transToolApplicationOptSrcPath; + private File transToolApplicationOptLanguagesSrcDir; + @Value("${is.translation.server:disabled}") + private String transToolEnabled; + private final String referenceLanguages = "en,de"; + + private final ConcurrentMap<Locale,String> localeToLocaleKey = new ConcurrentHashMap<>(); + // When running on a cluster, we need an event when flushing the i18n cache to do this on all machines private static OLATResourceable I18N_CACHE_FLUSHED_EVENT_CHANNEL; // Reference to instance for static methods - private static I18nModule INSTANCE; - private CoordinatorManager coordinatorManager; + private final CoordinatorManager coordinatorManager; - /** - * [spring] - */ - private I18nModule(CoordinatorManager coordinatorManager) { - super(); + @Autowired + public I18nModule(CoordinatorManager coordinatorManager, WebappHelper webappHelper) { + super(coordinatorManager); + assert webappHelper != null; this.coordinatorManager = coordinatorManager; - //if (INSTANCE != null && !Settings.isJUnitTest()) { throw new OLATRuntimeException("Tried to construct I18nModule, but module was already loaded!", null); } - INSTANCE = this; } @Override protected void initDefaultProperties() { // First read default configuration from the module config and then set // is as default in the properties - String defaultLanguageKey = getStringConfigParameter(CONFIG_DEFAULT_LANG, "en", false); - setStringPropertyDefault(CONFIG_DEFAULT_LANG, defaultLanguageKey); - String enabledLanguagesConfig = getStringConfigParameter(CONFIG_LANGUAGES_ENABLED, CONFIG_LANGUAGES_ENABLED_ALL, false); - setStringPropertyDefault(CONFIG_LANGUAGES_ENABLED, enabledLanguagesConfig); + setStringPropertyDefault(CONFIG_DEFAULT_LANG, defaultLanguage); + setStringPropertyDefault(CONFIG_LANGUAGES_ENABLED, enabledLanguages); } @Override @@ -185,8 +200,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { // can't be changed at runtime and are project specific // Set configured reference languages - String referenceLanguagesConfig = getStringConfigParameter(CONFIG_LANGUAGES_REFERENCES, "en", false); - String[] referenceAndFallbackKeys = referenceLanguagesConfig.split(","); + String[] referenceAndFallbackKeys = referenceLanguages.split(","); // remove whitespace and check for douplicates for (int i = 0; i < referenceAndFallbackKeys.length; i++) { String langKey = referenceAndFallbackKeys[i]; @@ -194,61 +208,39 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { transToolReferenceLanguages.add(langKey); } - // Language overlay: used to override a language with some custom wording - overlayName = getStringConfigParameter(CONFIG_OVERLAY, "customizing", false); - overlayEnabled = getBooleanConfigParameter(CONFIG_OVERLAY_ENABLED, true); - // Set caching configuration of local strings - cachingEnabled = getBooleanConfigParameter(CONFIG_CACHING_ENABLED, true); - logInfo("Localization caching set to: " + cachingEnabled, null); + log.info("Localization caching set to: " + cachingEnabled, null); // Set how the list of available availableLanguages will be shown // (drop-down[true] or in one line[false]) - languageDropDownListEnabled = getBooleanConfigParameter(CONFIG_LANGUAGE_LIST_ENABLED, true); - logInfo("Configuring 'dropDownListEnabled = " + languageDropDownListEnabled + "'", null); + log.info("Configuring 'dropDownListEnabled = " + languageDropDownListEnabled + "'", null); // Set additional source path to load languages from and to store // languages when using the translation tool. Init the values even when transtool is not configured for development mode - String appSrc = getStringConfigParameter(CONFIG_TRANS_TOOL_APPLICATION_SRC_PATH, "", false); - if (StringHelper.containsNonWhitespace(appSrc)) { - appSrc = appSrc.trim(); - transToolApplicationLanguagesDir = new File(appSrc); + if (StringHelper.containsNonWhitespace(transToolApplicationSrcPath)) { + transToolApplicationSrcPath = transToolApplicationSrcPath.trim(); + transToolApplicationLanguagesDir = new File(transToolApplicationSrcPath); } - String optAppSrc = getStringConfigParameter(CONFIG_TRANS_TOOL_APPLICATION_OPT_SRC_PATH, "", false); - if (StringHelper.containsNonWhitespace(optAppSrc)) { - optAppSrc = optAppSrc.trim(); - transToolApplicationOptLanguagesSrcDir = new File(optAppSrc); + if (StringHelper.containsNonWhitespace(transToolApplicationOptSrcPath)) { + transToolApplicationOptSrcPath = transToolApplicationOptSrcPath.trim(); + transToolApplicationOptLanguagesSrcDir = new File(transToolApplicationOptSrcPath); } // Enable or disable translation tool and i18n source directories - transToolEnabled = getBooleanConfigParameter(CONFIG_TRANS_TOOL_ENABLED, false); - if (transToolEnabled) { - // + boolean translationToolEnabled = "enabled".equals(transToolEnabled); + if (translationToolEnabled) { if (transToolApplicationLanguagesDir != null && transToolApplicationOptLanguagesSrcDir != null) { // Check if configuration is valid, otherwise disable translation server mode } else { // disable, pathes not configured properly - transToolEnabled = false; - } - // error handling, notify on console about disabled translation tool - if (!transToolEnabled) { - logWarn( - "Translation configuration enabled but invalid translation tool source path defined. Disabling translation tool. Fix your configuration in spring config of i18Module", - null); - logWarn(" transToolApplicationSrcPath::" + appSrc + " transToolApplicationI18nSrcPath::" + optAppSrc, null); + translationToolEnabled = false; + log.warn("Translation configuration enabled but invalid translation tool source path defined. Disabling translation tool. Fix your configuration in spring config of i18Module", null); + log.warn(" transToolApplicationSrcPath::" + transToolApplicationSrcPath + " transToolApplicationI18nSrcPath::" + transToolApplicationOptSrcPath, null); } } - I18nManager i18nMgr = I18nManager.getInstance(); - i18nMgr.setCachingEnabled(cachingEnabled); - // Get all bundles that contain i18n files initBundleNames(); - // Set the base bundles for olatcore and the application. When a key is - // not found, the manager looks it up in the application base and the in - // the core base bundle before it gives up - applicationFallbackBundle = getStringConfigParameter(CONFIG_APPLICATION_FALLBACK_BUNDLE, "org.olat", false); - coreFallbackBundle = getStringConfigParameter(CONFIG_CORE_FALLBACK_BUNDLE, "org.olat.core", false); // Search for all available languages on the build path and initialize them doInitAvailableLanguages(); @@ -257,15 +249,13 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { // the persisted system configuration doInitLanguageConfiguration(); - logInfo("Configured i18nModule with default language::" + getDefaultLocale().toString() + " and the reference languages '" - + referenceLanguagesConfig + "' and the following enabled languages: " + enabledLanguagesKeys.toString(), null); + log.info("Configured i18nModule with default language::" + getDefaultLocale().toString() + " and the reference languages '" + + referenceLanguages + "' and the following enabled languages: " + enabledLanguagesKeys.toString(), null); } - /** - * - * @see org.olat.core.configuration.Destroyable#destroy() - */ + @Override public void destroy() { + super.destroy(); // remove from event channel if (I18N_CACHE_FLUSHED_EVENT_CHANNEL != null) { coordinatorManager.getCoordinator().getEventBus().deregisterFor(this, I18N_CACHE_FLUSHED_EVENT_CHANNEL); @@ -277,21 +267,20 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * Initialize the available languages and load all locales */ private void doInitAvailableLanguages() { - I18nManager i18nMgr = I18nManager.getInstance(); // Search all availableLanguages files that exist String i18nDirRelPath = File.separator + applicationFallbackBundle.replace(".", File.separator) + File.separator + I18nManager.I18N_DIRNAME; if (transToolApplicationLanguagesDir != null) { File coreSrcI18nDir = new File(transToolApplicationLanguagesDir, i18nDirRelPath); if (coreSrcI18nDir.exists()) { - for (String languageCode : i18nMgr.searchForAvailableLanguages(transToolApplicationLanguagesDir)) { + for (String languageCode : searchForAvailableLanguages(transToolApplicationLanguagesDir)) { if (availableLanguages.contains(languageCode)) { String path = ""; if (transToolApplicationOptLanguagesSrcDir != null) path = transToolApplicationOptLanguagesSrcDir.getAbsolutePath(); - logDebug("Skipping duplicate or previously loaded language::" + languageCode + " found in " +path , null); + log.debug("Skipping duplicate or previously loaded language::" + languageCode + " found in " +path , null); continue; } - logDebug("Detected translatable language " + languageCode + " in " + transToolApplicationLanguagesDir.getAbsolutePath(), null); + log.debug("Detected translatable language " + languageCode + " in " + transToolApplicationLanguagesDir.getAbsolutePath(), null); availableLanguages.add(languageCode); translatableLanguages.add(languageCode); translatableLangAppBaseDirLookup.put(languageCode, transToolApplicationLanguagesDir); @@ -300,12 +289,12 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { } // 2) Add languages from the translation tool source path if (isTransToolEnabled()) { - for (String languageCode : i18nMgr.searchForAvailableLanguages(transToolApplicationOptLanguagesSrcDir)) { + for (String languageCode : searchForAvailableLanguages(transToolApplicationOptLanguagesSrcDir)) { if (availableLanguages.contains(languageCode)) { - logDebug("Skipping duplicate or previously loaded language::" + languageCode + " found in " + transToolApplicationOptLanguagesSrcDir.getAbsolutePath(), null); + log.debug("Skipping duplicate or previously loaded language::" + languageCode + " found in " + transToolApplicationOptLanguagesSrcDir.getAbsolutePath(), null); continue; } - logDebug("Detected translatable language " + languageCode + " in " + transToolApplicationOptLanguagesSrcDir.getAbsolutePath(), null); + log.debug("Detected translatable language " + languageCode + " in " + transToolApplicationOptLanguagesSrcDir.getAbsolutePath(), null); availableLanguages.add(languageCode); translatableLanguages.add(languageCode); translatableLangAppBaseDirLookup.put(languageCode, transToolApplicationOptLanguagesSrcDir); @@ -316,12 +305,12 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { if(StringHelper.containsNonWhitespace(folderRoot)) { //started from WEB-INF/classes File libDir = new File(WebappHelper.getBuildOutputFolderRoot()); - for (String languageCode : i18nMgr.searchForAvailableLanguages(libDir)) { + for (String languageCode : searchForAvailableLanguages(libDir)) { if (availableLanguages.contains(languageCode)) { - logDebug("Skipping duplicate or previously loaded language::" + languageCode + " found in " + libDir.getAbsolutePath(), null); + log.debug("Skipping duplicate or previously loaded language::" + languageCode + " found in " + libDir.getAbsolutePath(), null); continue; } - logDebug("Detected non-translatable language " + languageCode + " in " + libDir.getAbsolutePath(), null); + log.debug("Detected non-translatable language " + languageCode + " in " + libDir.getAbsolutePath(), null); availableLanguages.add(languageCode); // don't add to translatable languages nor to source lookup maps - those // langs are read only @@ -332,23 +321,23 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { String[] enabledLanguages = enabledLanguagesConfig.split(","); for (String languageCode : enabledLanguages) { if (availableLanguages.contains(languageCode)) { - logWarn("Skipping duplicate or previously loaded language::" + languageCode + " found in " + log.warn("Skipping duplicate or previously loaded language::" + languageCode + " found in " + LANG_PACKS_DIRECTORY.getAbsolutePath(), null); continue; } - logDebug("Force non-translatable language " + languageCode + " defined from enabledLanguages.", null); + log.debug("Force non-translatable language " + languageCode + " defined from enabledLanguages.", null); availableLanguages.add(languageCode); } } // 4) Add languages from the customizing lang packs - for (String languageCode : i18nMgr.searchForAvailableLanguages(LANG_PACKS_DIRECTORY)) { + for (String languageCode : searchForAvailableLanguages(LANG_PACKS_DIRECTORY)) { if (availableLanguages.contains(languageCode)) { - logWarn("Skipping duplicate or previously loaded language::" + languageCode + " found in " + log.warn("Skipping duplicate or previously loaded language::" + languageCode + " found in " + LANG_PACKS_DIRECTORY.getAbsolutePath(), null); continue; } - logDebug("Detected non-translatable language " + languageCode + " in " + LANG_PACKS_DIRECTORY.getAbsolutePath(), null); + log.debug("Detected non-translatable language " + languageCode + " in " + LANG_PACKS_DIRECTORY.getAbsolutePath(), null); availableLanguages.add(languageCode); // don't add to translatable languages nor to source lookup maps - those // langs are read only @@ -363,9 +352,9 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { // // Build list of all locales and the overlay locales if available for (String langKey : availableLanguages) { - Locale locale = i18nMgr.createLocale(langKey); + Locale locale = createLocale(langKey); if (locale == null) { - logError("Could not create locale for lang::" + langKey + ", skipping language and remove it from list of available languages", + log.error("Could not create locale for lang::" + langKey + ", skipping language and remove it from list of available languages", null); toRemoveLangs.add(langKey); continue; @@ -377,12 +366,12 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { // // Add overlay if (isOverlayEnabled()) { - Locale overlayLocale = i18nMgr.createOverlay(locale); + Locale overlayLocale = createOverlay(locale); // Calculate the overlay key as used as reference. Note, this is not the // same as overlayLocale.toString(), this would add '_' for each element - String overlayKey = i18nMgr.getLocaleKey(overlayLocale); + String overlayKey = getLocaleKey(overlayLocale); if (overlayLocale == null) { - logError("Could not create overlay locale for lang::" + langKey + " (" + overlayKey + "), skipping language", null); + log.error("Could not create overlay locale for lang::" + langKey + " (" + overlayKey + "), skipping language", null); continue; } // Don't add same overlay twice @@ -402,38 +391,180 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { translatableLangAppBaseDirLookup.remove(langKey); } // Set fallback locale from configuration - String fallbackLangKey = getStringConfigParameter(CONFIG_FALLBACK_LANG, Locale.ENGLISH.toString(), false); // fallbackLangKey can't be null because EN is guaranteed to be available, // see above - fallbackLocale = allLocales.get(fallbackLangKey); + fallbackLocale = allLocales.get(fallbackLanguage); // Check if translation tool reference languages are available if (isTransToolEnabled() && transToolReferenceLanguages.size() == 0) { - logError("Did not find the fallback language configuration in the configuration, using language::en instead", null); + log.error("Did not find the fallback language configuration in the configuration, using language::en instead", null); } else { for (String langKey : transToolReferenceLanguages) { if (!allLocales.containsKey(langKey)) { - logError("The configured fallback language::" + langKey + " does not exist. Using language::en instead", null); + log.error("The configured fallback language::" + langKey + " does not exist. Using language::en instead", null); + } + } + } + } + + /** + * Search for available languages in the given directory. The translation + * files must start with 'LocalStrings_' and end with '.properties'. + * Everything in between is considered a language key. + * <p> + * If the directory contains jar files, those files are opened and searched + * for languages files as well. In this case, the algorythm only looks for + * translation files that are in the org/olat/core/_i18n package + * + * @param i18nDir + * @return set of language keys the system will find translations for + */ + Set<String> searchForAvailableLanguages(File i18nDir) { + Set<String> foundLanguages = new TreeSet<String>(); + i18nDir = new File(i18nDir.getAbsolutePath()+"/org/olat/_i18n"); + if (i18nDir.exists()) { + // First check for locale files + String[] langFiles = i18nDir.list(i18nFileFilter); + for (String langFileName : langFiles) { + String lang = langFileName.substring(I18nModule.LOCAL_STRINGS_FILE_PREFIX.length(), langFileName.lastIndexOf(".")); + foundLanguages.add(lang); + log.debug("Adding lang::" + lang + " from filename::" + langFileName + " from dir::" + i18nDir.getAbsolutePath(), null); + } + } + return foundLanguages; + } + + /** + * Create a local that represents the overlay locale for the given locale + * + * @param locale The original locale + * @return The overlay locale + */ + Locale createOverlay(Locale locale) { + String lang = locale.getLanguage(); + String country = (locale.getCountry() == null ? "" : locale.getCountry()); + String variant = createOverlayKeyForLanguage(locale.getVariant() == null ? "" : locale.getVariant()); + Locale overlay = new Locale(lang, country, variant); + return overlay; + } + + /** + * Add the overlay postfix to the given language key + * @param langKey + * @return + */ + String createOverlayKeyForLanguage(String langKey) { + return langKey + "__" + getOverlayName(); + } + + /** + * Helper method to create a locale from a given locale key ('de', 'de_CH', + * 'de_CH_ZH') + * + * @param localeKey + * @return the locale or NULL if no locale could be generated from this string + */ + Locale createLocale(String localeKey) { + Locale aloc = null; + // de + // de_CH + // de_CH_zueri + String[] parts = localeKey.split("_"); + switch (parts.length) { + case 1: + aloc = new Locale(parts[0]); + break; + case 2: + aloc = new Locale(parts[0], parts[1]); + break; + case 3: + String lastPart = parts[2]; + // Add all remaining parts to variant, variant can contain + // underscores according to Locale spec + for (int i = 3; i < parts.length; i++) { + String part = parts[i]; + lastPart = lastPart + "_" + part; + } + aloc = new Locale(parts[0], parts[1], lastPart); + break; + default: + return null; + } + // Test if the locale has been constructed correctly. E.g. when the + // language part is not existing in the ISO chart, the locale can + // convert to something else. + // E.g. he_HE_HE will convert automatically to iw_HE_HE + if (aloc.toString().equals(localeKey)) { + return aloc; + } else { + return null; + } + } + + /** + * Calculate the locale key that identifies the given locale. Adds support for + * the overlay mechanism. + * + * @param locale + * @return + */ + public String getLocaleKey(Locale locale) { + String key = localeToLocaleKey.get(locale); + if(key == null) { + String langKey = locale.getLanguage(); + String country = locale.getCountry(); + // Only add country when available - in case of an overlay country is + // set to + // an empty value + if (StringHelper.containsNonWhitespace(country)) { + langKey = langKey + "_" + country; + } + String variant = locale.getVariant(); + // Only add the _ separator if the variant contains something in + // addition to + // the overlay, otherways use the __ only + if (StringHelper.containsNonWhitespace(variant)) { + if (variant.startsWith("__" + getOverlayName())) { + langKey += variant; + } else { + langKey = langKey + "_" + variant; } } + + key = localeToLocaleKey.putIfAbsent(locale, langKey); + if(key == null) { + key = langKey; + } + } + return key; } + + private static FilenameFilter i18nFileFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + // don't add overlayLocales as selectable availableLanguages + // (LocaleStrings_de__VENDOR.properties) + if (name.startsWith(I18nModule.LOCAL_STRINGS_FILE_PREFIX) && name.indexOf("_") != 0 && name.endsWith(I18nModule.LOCAL_STRINGS_FILE_POSTFIX)) { return true; } + return false; + } + }; private void doInitLanguageConfiguration() { // Set the default language String defaultLanguageKey = getStringPropertyValue(CONFIG_DEFAULT_LANG, false); Locale newDefaultLocale = allLocales.get(defaultLanguageKey); if (newDefaultLocale == null) { - logError("Could not set default locale to value::" + defaultLanguageKey + " - no such language found. Using fallback locale instead", + log.error("Could not set default locale to value::" + defaultLanguageKey + " - no such language found. Using fallback locale instead", null); newDefaultLocale = allLocales.get(transToolReferenceLanguages.get(0)); } else if (!availableLanguages.contains(newDefaultLocale.toString())) { - logError("Did not find the default language::" + newDefaultLocale.toString() + log.error("Did not find the default language::" + newDefaultLocale.toString() + " in the available availableLanguages files! Using fallback locale instead", null); newDefaultLocale = allLocales.get(transToolReferenceLanguages.get(0)); } defaultLocale = newDefaultLocale; - logInfo("Setting default locale::" + newDefaultLocale.toString(), null); + log.info("Setting default locale::" + newDefaultLocale.toString(), null); // Enabling configured languages (a subset of the available languages) String[] enabledLanguages; @@ -450,12 +581,12 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { enabledLanguagesKeys.add(langKey); } // else skip this entry } - logInfo("Enabling languages::" + enabledLanguagesConfig, null); + log.info("Enabling languages::" + enabledLanguagesConfig, null); // Make sure that the configured default language is enabled if (!enabledLanguagesKeys.contains(getDefaultLocale().toString())) { String defLang = getDefaultLocale().toString(); enabledLanguagesKeys.add(defLang); - logWarn("The configured default language::" + defLang + " is not in the list of enabled languages. Enabling language::" + defLang, + log.warn("The configured default language::" + defLang + " is not in the list of enabled languages. Enabling language::" + defLang, null); } } @@ -476,11 +607,11 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * * @param newDefaultLocale */ - public static void setDefaultLocale(Locale newDefaultLocale) { + public void setDefaultLocale(Locale newDefaultLocale) { if (defaultLocale == null || !defaultLocale.toString().equals(newDefaultLocale.toString())) { // Just set the string property here. This will fire an event and // call the method initFromChangedProperties() - INSTANCE.setStringProperty(CONFIG_DEFAULT_LANG, newDefaultLocale.toString(), true); + setStringProperty(CONFIG_DEFAULT_LANG, newDefaultLocale.toString(), true); } } @@ -488,7 +619,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * @return The locale that is used when a string is not found in any other * locale */ - public static Locale getFallbackLocale() { + public Locale getFallbackLocale() { return fallbackLocale; } @@ -499,7 +630,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { /** * @return true: caching is enabled; false: caching is disabled */ - static boolean isCachingEnabled() { + public boolean isCachingEnabled() { return cachingEnabled; } @@ -509,7 +640,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * the enabled languages to get the list of languages that are enabled * to be used */ - public static Set<String> getAvailableLanguageKeys() { + public Set<String> getAvailableLanguageKeys() { return availableLanguages; } @@ -518,7 +649,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * tool. Theses are the languages that are available in the source * form. Languages embedded in jars can't be edited. */ - public static Set<String> getTranslatableLanguageKeys() { + public Set<String> getTranslatableLanguageKeys() { return translatableLanguages; } @@ -526,7 +657,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * @return the map (with dummy value) of all languages including * overlayLocales (as a String) */ - public static Map<String, Locale> getAllLocales() { + public Map<String, Locale> getAllLocales() { return allLocales; } @@ -534,7 +665,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * @return The lookup map of the overlay locales. Key: the locale; value: the * corresponding overlay */ - public static Map<Locale, Locale> getOverlayLocales() { + public Map<Locale, Locale> getOverlayLocales() { return overlayLocales; } @@ -543,7 +674,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * de_CH, en, ...). those are the languages which can be chosen by the * user */ - public static Collection<String> getEnabledLanguageKeys() { + public Collection<String> getEnabledLanguageKeys() { synchronized (enabledLanguagesKeys) { return new HashSet<String>(enabledLanguagesKeys); } @@ -552,8 +683,8 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { /** * @return as keys: a List of Strings with the supported languages overlay keys */ - public static Set<String> getOverlayLanguageKeys() { - return overlayLanguagesKeys; + public Set<String> getOverlayLanguageKeys() { + return overlayLanguagesKeys; } @@ -563,7 +694,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * * @param newEnabledLangKeys */ - public static void setEnabledLanguageKeys(Collection<String> newEnabledLangKeys) { + public void setEnabledLanguageKeys(Collection<String> newEnabledLangKeys) { if (!newEnabledLangKeys.equals(enabledLanguagesKeys)) { String newEnabledConfig = ""; for (String enabledKey : newEnabledLangKeys) { @@ -576,7 +707,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { // Just set the string property here. This will fire an event and // call the method initFromChangedProperties() - INSTANCE.setStringProperty(CONFIG_LANGUAGES_ENABLED, newEnabledConfig.toString(), true); + setStringProperty(CONFIG_LANGUAGES_ENABLED, newEnabledConfig.toString(), true); // No need to reinitialize i18n Module, setting the new property will already do this } } @@ -584,14 +715,14 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { /** * @return A list of language keys that are reference and fallback languages */ - public static List<String> getTransToolReferenceLanguages() { + public List<String> getTransToolReferenceLanguages() { return transToolReferenceLanguages; } /** * @return All bundles that contain a _i18n directory with translation files */ - public static List<String> getBundleNamesContainingI18nFiles() { + public List<String> getBundleNamesContainingI18nFiles() { return bundleNames; } @@ -599,7 +730,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * @return The bundle name that contains the commonly used translations from * the olatcore framework */ - public static String getCoreFallbackBundle() { + public String getCoreFallbackBundle() { return coreFallbackBundle; } @@ -607,7 +738,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * @return The bundle name that contains the commonly used translations from * the application */ - public static String getApplicationFallbackBundle() { + public String getApplicationFallbackBundle() { return applicationFallbackBundle; } @@ -617,7 +748,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * * @return true: enabled; false: disabled */ - public static boolean isOverlayEnabled() { + public boolean isOverlayEnabled() { return (overlayEnabled && StringHelper.containsNonWhitespace(overlayName)); } @@ -627,7 +758,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * * @return name of the overlay */ - public static String getOverlayName() { + public String getOverlayName() { if (isOverlayEnabled()) return overlayName; else return null; } @@ -636,17 +767,61 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * @return true: enable the translation tool; false: disable the translation * tool */ - public static boolean isTransToolEnabled() { - return transToolEnabled; + public boolean isTransToolEnabled() { + return "enabled".equals(transToolEnabled); } /** * search for bundles that contain i18n files. Searches in the org.olat.core * package */ - static void initBundleNames() { - I18nManager i18nMgr = I18nManager.getInstance(); - bundleNames = i18nMgr.searchForBundleNamesContainingI18nFiles(); + void initBundleNames() { + bundleNames = searchForBundleNamesContainingI18nFiles(); + } + + /** + * Search in all packages on the source patch for packages that contain an + * _i18n directory that can be used to store olatcore localization files + * + * @return set of bundles that contain olatcore i18n compatible localization + * files + */ + List<String> searchForBundleNamesContainingI18nFiles() { + List<String> foundBundles; + // 1) First search on normal source path of application + String srcPath = null; + File applicationDir = getTransToolApplicationLanguagesSrcDir(); + if (applicationDir != null) { + srcPath = applicationDir.getAbsolutePath(); + } else { + // Fall back to compiled classes + srcPath = WebappHelper.getBuildOutputFolderRoot(); + } + if(StringHelper.containsNonWhitespace(srcPath)) { + I18nDirectoriesVisitor srcVisitor = new I18nDirectoriesVisitor(srcPath, getTransToolReferenceLanguages()); + FileUtils.visitRecursively(new File(srcPath), srcVisitor); + foundBundles = srcVisitor.getBundlesContainingI18nFiles(); + // 3) For jUnit tests, add also the I18n test dir + if (Settings.isJUnitTest()) { + Resource testres = new ClassPathResource("olat.local.properties"); + String jUnitSrcPath = null; + try { + jUnitSrcPath = testres.getFile().getAbsolutePath(); + } catch (IOException e) { + throw new StartupException("Could not find classpath resource for: test-classes/olat.local.property ", e); + } + + + I18nDirectoriesVisitor juniSrcVisitor = new I18nDirectoriesVisitor(jUnitSrcPath, getTransToolReferenceLanguages()); + FileUtils.visitRecursively(new File(jUnitSrcPath), juniSrcVisitor); + foundBundles.addAll(juniSrcVisitor.getBundlesContainingI18nFiles()); + } + // Sort alphabetically + Collections.sort(foundBundles); + } else { + foundBundles = new ArrayList<String>(); + } + return foundBundles; } /** @@ -657,7 +832,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * @param bundleName * @return The file or null if the language is not read-write configured */ - public static File getPropertyFilesBaseDir(Locale locale, String bundleName) { + public File getPropertyFilesBaseDir(Locale locale, String bundleName) { // 1) Special case, junit test files are not in olat source path // We don't want translator to translate those files! if (Settings.isJUnitTest() && bundleName.startsWith("org.olat.core.util.i18n.junittestdata") ) { @@ -670,21 +845,19 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { return transToolApplicationLanguagesDir; } // 3) Locale files from core or application - String localeKey = I18nManager.getInstance().getLocaleKey(locale); + String localeKey = getLocaleKey(locale); return translatableLangAppBaseDirLookup.get(localeKey); } /** * Reinitialize the entire i18n system */ - public static void reInitializeAndFlushCache() { - synchronized (enabledLanguagesKeys) { - // Re-initialize all local caches - doReInitialize(); - // Notify other nodes to reInitialize the caches as well - I18nReInitializeCachesEvent changedConfigEvent = new I18nReInitializeCachesEvent(); - CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(changedConfigEvent, I18N_CACHE_FLUSHED_EVENT_CHANNEL); - } + public void reInitializeAndFlushCache() { + // Re-initialize all local caches + doReInitialize(); + // Notify other nodes to reInitialize the caches as well + I18nReInitializeCachesEvent changedConfigEvent = new I18nReInitializeCachesEvent(); + CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(changedConfigEvent, I18N_CACHE_FLUSHED_EVENT_CHANNEL); } /** @@ -692,7 +865,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * is decoupled from the reInitialize() to prevent endless firing of events * in the cluster. */ - private static void doReInitialize() { + private void doReInitialize() { synchronized (enabledLanguagesKeys) { // Clear everything availableLanguages.clear(); @@ -705,13 +878,14 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { transToolReferenceLanguages.clear(); I18nManager.getInstance().clearCaches(); // Now rebuild everything from scratch - INSTANCE.doInit(); + doInit(); } } /** * @see org.olat.core.configuration.AbstractOLATModule#event(org.olat.core.gui.control.Event) */ + @Override public void event(Event event) { // First delegate to AbstractOLATModule super.event(event); @@ -731,7 +905,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * * @return */ - public static File getTransToolApplicationLanguagesSrcDir() { + public File getTransToolApplicationLanguagesSrcDir() { return transToolApplicationLanguagesDir; } @@ -741,13 +915,7 @@ public class I18nModule extends AbstractOLATModule implements Destroyable { * * @return */ - public static File getTransToolApplicationOptLanguagesSrcDir() { + public File getTransToolApplicationOptLanguagesSrcDir() { return transToolApplicationOptLanguagesSrcDir; } - - @Override - public void setPersistedProperties(PersistedProperties persistedProperties) { - this.moduleConfigProperties = persistedProperties; - } - } diff --git a/src/main/java/org/olat/core/util/i18n/_spring/i18nCorecontext.xml b/src/main/java/org/olat/core/util/i18n/_spring/i18nCorecontext.xml deleted file mode 100644 index 0083981366bfc090a33b6ef10cdb91fbbe3a8fb3..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/util/i18n/_spring/i18nCorecontext.xml +++ /dev/null @@ -1,117 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans.xsd"> - -<bean id="I18nManager" class="org.olat.core.util.i18n.I18nManager" /> - -<bean id="i18nModule" class="org.olat.core.util.i18n.I18nModule" destroy-method="destroy" depends-on="I18nManager, org.olat.core.util.WebappHelper"> - <constructor-arg ref="coordinatorManager" /> - <property name="persistedProperties"> - <bean class="org.olat.core.configuration.PersistedProperties" scope="prototype" init-method="init" destroy-method="destroy"> - <constructor-arg index="0" ref="coordinatorManager"/> - <constructor-arg index="1" ref="i18nModule" /> - </bean> - </property> - -</bean> - - <bean id="triggerI18nModuleInit" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> - <property name="targetObject" ref="i18nModule" /> - <property name="targetMethod" value="init" /> - <property name="arguments"> - <value> - <!-- - Default setting for enabled languages: comma separated list of lang keys. Set to 'all' to - enable all languages that can be found in the source code - Example: - <enabledLanguages>en,de,fr,it,es,da,cs,el,ru,pl,zh_CN,zh_TW,lt,fa,pt_PT,pt_BR,tr,hu,sq,in,ar,rm,af,iw,vi,mn</enabledLanguages> - or - <enabledLanguages>all</enabledLanguages> - NOTE: this default setting will be overridden by the values configured in - olatdata/system/configuration/org.olat.core.util.i18n.I18nModule.properties - --> - enabledLanguages=${enabledLanguages} - <!-- - Default setting for the system default locale to use: language of login page - NOTE: this default setting will be overridden by the values configured in - olatdata/system/configuration/org.olat.core.util.i18n.I18nModule.properties - --> - defaultLanguage=${defaultlang} - <!-- - The language that is used as a fallback in case the system does not find a key in the - users language nor in the default language. Note that in this language - all keys must exist! Since developers only add the 'de' and 'en' keys it is strongly recommended - that you don't set it to any other value that this. If unsure, use the default 'de'. - --> - fallbackLanguage=${fallbacklang} - <!-- - The application fallback bundle contains the common words used everywhere in your web application. - During translation, when a translation is not found, the system checks if the fallback bundle contains - the translation. Here you find things you often use in your application. - If unsure, leave default value. - --> - applicationFallbackBundle=org.olat - <!-- - The olatcore fallback bundle contains the common words used everywhere in the core framework. - During translation, when a translation is not found, the system checks if the fallback bundle contains - the translation. Here you find things like 'yes', 'no' etc. Normally you don't change this. - In the fallback chain the system first checks for the application fallback and as last option it then - checks for the olatcore fallback - If unsure, leave default value. - --> - coreFallbackBundle=org.olat.core - <!-- - Name of the overlay that should be used to customize the language. E.g. if your overlay - files are labelled "de__customizing" you must set "customizing" here. The overlay properties files are - stored in olatdata/customizing/lang/overlay/* - If unsure, leave default value. - --> - overlayName=customizing - <!-- - Enable or disable the customizing overlay feature. If set to true it is not possible to customize - the interface text elements. If unsure, set to true. - --> - overlayEnabled=true - <!-- - Whether to cache i18n properties files (recommended in production). - If unsure, set to true. - --> - cachingEnabled=${localization.cache} - <!-- - Define language selection list style on login page. true=drop-box, false=in one line. - If unsure, leave default value. - --> - dropDownListEnabled=true - <!-- - Enable the translation tool. This is only enabled on the official OLAT translation server - at translation.olat.org. If you want to setup your own translation server you must specify - the following path in order to work properly: - i18n.application.src.dir : path to the source of your application code, typically olat3/webapp/WEB-INF/src - i18n.application.opt.src.dir : path to the source of your application i18n files, typically olat3_i18n/src/main/java - i18n.core.src.dir : path to the source of the framework core code, typically olatcore/src/main/java - i18n.core.opt.src.dir : path to the source of the framework i18n files, typically olatcore_i18n/src/main/java - In most cases you can set this value to disabled and ignore the application and core src path. - You can still use the translation tool to customize the languages using the overlay feature - If unsure, set to disabled in the olat.local.properties. - - Values are disabled / enabled, this is also used to enable the translation status job. - see your olat.properties or olat.local.properties for the value set. - --> - transToolEnabled=${is.translation.server} - transToolApplicationSrcPath=${i18n.application.src.dir} - transToolApplicationOptSrcPath=${i18n.application.opt.src.dir} - <!-- - The languages that serve as a base in the translation tool. Note that in those languages - all keys must exist! Since developers only add the 'de' and 'en' keys it is strongly recommended - that you don't set it to any other value that this. If unsure, use the default 'en,de'. - --> - transToolReferenceLanguages=de,en - </value> - </property> -</bean> - -</beans> diff --git a/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevController.java b/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevController.java index 80564f48230d69ee19ee8f63d9a25af74a18253e..311f951ec152fcbfa4126bf4075a98014f70782e 100644 --- a/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevController.java +++ b/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevController.java @@ -37,9 +37,6 @@ import org.springframework.beans.factory.annotation.Autowired; public class TranslationDevController extends FormBasicController { - @Autowired - private TranslationDevManager translationDevManager; - private String[] values = { "" }; private String[] keys = { "on" }; @@ -93,6 +90,11 @@ public class TranslationDevController extends FormBasicController { private TextElement addKeyValue; private TextElement addKeyKey; private FormLink submitAdd; + + @Autowired + private I18nModule i18nModule; + @Autowired + private TranslationDevManager translationDevManager; public TranslationDevController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); @@ -103,7 +105,7 @@ public class TranslationDevController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - if(!I18nModule.isTransToolEnabled()){ + if(!i18nModule.isTransToolEnabled()){ setFormWarning("devtools.warning"); } diff --git a/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevMainController.java b/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevMainController.java index b40197ca0837ccb6d37885e2ffcf5c2fbc22fb1a..a97a91e1491ff23a76aa1ff1c4aaa158d7a223fc 100644 --- a/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevMainController.java +++ b/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevMainController.java @@ -26,17 +26,17 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.MainLayoutBasicController; import org.olat.core.util.i18n.I18nModule; +import org.springframework.beans.factory.annotation.Autowired; /** - * Description:<br> - * TODO: rhaag Class Description for TranslationDevMainController - * * <P> * Initial Date: 23.09.2008 <br> * @author Roman Haag, frentix GmbH, roman.haag@frentix.com */ public class TranslationDevMainController extends MainLayoutBasicController { - private final VelocityContainer vc; + + @Autowired + private I18nModule i18nModule; /** * @param ureq @@ -44,18 +44,12 @@ public class TranslationDevMainController extends MainLayoutBasicController { */ public TranslationDevMainController(UserRequest ureq, WindowControl control) { super(ureq, control); - vc = createVelocityContainer("translationdev"); - String srcPath = I18nModule.getTransToolApplicationLanguagesSrcDir().getAbsolutePath(); + VelocityContainer vc = createVelocityContainer("translationdev"); + String srcPath = i18nModule.getTransToolApplicationLanguagesSrcDir().getAbsolutePath(); vc.contextPut("srcPath", srcPath); - //TODO RH: check for enabled debug-mode in order to prevent caching! -// vc.contextPut("cachingDisabled", I18nModule.isCachingEnabled()); - -// formFactory.addTextElement(name, maxLen, initialValue, i18nLabel, formItemContainer) putInitialPanel(vc); } - - /** * @see org.olat.core.gui.control.DefaultController#doDispose() */ @@ -71,4 +65,4 @@ public class TranslationDevMainController extends MainLayoutBasicController { protected void event(UserRequest ureq, Component source, Event event) { // } -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevManager.java b/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevManager.java index 3776ef6f83e5b01db0341b3cbe10fccfdb9ba760..14deaff880f2e559a24966d6661f49cd91ddf255 100644 --- a/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevManager.java +++ b/src/main/java/org/olat/core/util/i18n/devtools/TranslationDevManager.java @@ -33,9 +33,9 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; import java.util.Set; -import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -48,6 +48,8 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.i18n.I18nItem; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** @@ -59,27 +61,20 @@ import org.olat.core.util.i18n.I18nModule; * * @author Roman Haag, frentix GmbH, roman.haag@frentix.com */ +@Service("translationDevManager") public class TranslationDevManager extends BasicManager { - - private static TranslationDevManager INSTANCE; private static final OLog log = Tracing.createLoggerFor(TranslationDevManager.class); - I18nManager i18nMgr; - private StringBuffer logText = new StringBuffer(); - - /** - * [spring] - */ - private TranslationDevManager(I18nManager i18nManager) { - this.i18nMgr = i18nManager; - INSTANCE = this; - } - public static TranslationDevManager getInstance() { - return INSTANCE; - } + private StringBuffer logText = new StringBuffer(); + + @Autowired + private I18nManager i18nMgr; + @Autowired + private I18nModule i18nModule; + protected Set<String> getAllLanguages() { - return I18nModule.getAvailableLanguageKeys(); + return i18nModule.getAvailableLanguageKeys(); } protected void renameKeyTask(String bundleName, String origKey, String targetKey) { @@ -124,7 +119,7 @@ public class TranslationDevManager extends BasicManager { int counter = 0; Pattern resolvingKeyPattern = Pattern.compile("\\$\\{?("+originBundleName+")+:([\\w\\.\\-]*[\\w\\-])\\}?"); - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); Set<String> allLangs = getAllLanguages(); for (String langKey : allLangs) { Locale locale = i18nMgr.getLocaleOrNull(langKey); @@ -163,7 +158,7 @@ public class TranslationDevManager extends BasicManager { lastPos = matcher.end(); newValue.append(value.substring(lastPos)); log.info("Key:: " + key + " should get changed to value:: " + newValue.toString()); - logText.append(i18nMgr.getPropertiesFile(locale, bundleName, I18nModule.getPropertyFilesBaseDir(locale, bundleName)) + + logText.append(i18nMgr.getPropertiesFile(locale, bundleName, i18nModule.getPropertyFilesBaseDir(locale, bundleName)) + " update reference in lang::" + locale.getLanguage() + " bundle::" + bundleName + " key::" + key + " value::" + value + " \n\t to new value:: " + newValue.toString() + "\n"); counter ++; // changeValueForSingleKey(locale, bundleName, key, newValue.toString()); @@ -194,7 +189,6 @@ public class TranslationDevManager extends BasicManager { i18nMgr.saveOrUpdateProperties(tempProp, locale, bundleName); checkForEmptyPropertyAndDelete(locale, bundleName); - checkForEmptyBundleAndDelete(bundleName); } protected void addKey(Locale locale, String bundleName, String key, String value) { @@ -210,12 +204,6 @@ public class TranslationDevManager extends BasicManager { } } - private void checkForEmptyBundleAndDelete(String bundleName) { - // if _i18n is empty: - // TODO: RH: remove dir, remove .cvs - // deletePackage(bundleName); - } - public void movePackageTask(String originBundleName, String targetBundleName) { //remove package priority from metadata first deleteKey(null, originBundleName, I18nManager.METADATA_BUNDLE_PRIORITY_KEY); @@ -232,7 +220,7 @@ public class TranslationDevManager extends BasicManager { } public void movePackageByMovingSingleKeysTask(String originBundleName, String targetBundleName) { - Properties properties = i18nMgr.getPropertiesWithoutResolvingRecursively(I18nModule.getFallbackLocale(), originBundleName); + Properties properties = i18nMgr.getPropertiesWithoutResolvingRecursively(i18nModule.getFallbackLocale(), originBundleName); Set<Object> keys = properties.keySet(); for (Object keyObj : keys) { String key = (String) keyObj; @@ -272,7 +260,7 @@ public class TranslationDevManager extends BasicManager { public void renameLanguageTask(Locale sourceLocale, Locale targetLocale){ //check if targetLocale exists already - Set<String> allLangKeys = I18nModule.getAvailableLanguageKeys(); + Set<String> allLangKeys = i18nModule.getAvailableLanguageKeys(); if (allLangKeys.contains(targetLocale.getLanguage())){ log.error("Target Language " + targetLocale.getLanguage() + " already exists! "); } @@ -301,7 +289,7 @@ public class TranslationDevManager extends BasicManager { * @param reallyRemoveIt true: really remove it; false: dry run, only produce logging */ public void removeXKeysTask(boolean reallyRemoveIt){ - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); Set<String> allLangs = getAllLanguages(); int counter = 0; for (String langKey : allLangs) { @@ -320,7 +308,7 @@ public class TranslationDevManager extends BasicManager { } } log.info("XKEY detected in lang::" + locale.getLanguage() + " bundle::" + bundleName + " key::" + key); - File propertyFileDir = I18nModule.getPropertyFilesBaseDir(locale, bundleName); + File propertyFileDir = i18nModule.getPropertyFilesBaseDir(locale, bundleName); if(propertyFileDir != null) { File propertyFile = i18nMgr.getPropertiesFile(locale, bundleName, propertyFileDir); logText.append(propertyFile + " XKEY detected in lang::" + locale.getLanguage() + " bundle::" + bundleName + " key::" + key + " value::" + value + "\n"); @@ -339,7 +327,7 @@ public class TranslationDevManager extends BasicManager { } public void sortKeysTask(boolean reallySortIt){ - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); Set<String> allLangs = getAllLanguages(); int counter = 0; for (String langKey : allLangs) { @@ -366,7 +354,7 @@ public class TranslationDevManager extends BasicManager { * @param reallyRemoveIt true: really remove it; false: dry run, only produce logging */ public void removeTodoKeysTask(boolean reallyRemoveIt) { - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); Set<String> allLangs = getAllLanguages(); int counter = 0; String[] comparisonStrings = {"TODO"}; @@ -385,7 +373,7 @@ public class TranslationDevManager extends BasicManager { if (value.length() > comparisonStrings[i].length()+1) { log.warn("this is a TODO-Key WITH TEXT::" + value.substring(comparisonStrings[i].length()) + "::"); } else { - logText.append(i18nMgr.getPropertiesFile(locale, bundleName, I18nModule.getPropertyFilesBaseDir(locale, bundleName)) + + logText.append(i18nMgr.getPropertiesFile(locale, bundleName, i18nModule.getPropertyFilesBaseDir(locale, bundleName)) + " TODO-Key detected in lang::" + locale.getLanguage() + " bundle::" + bundleName + " key::" + key + " value::" + value + "\n"); if (reallyRemoveIt) { deleteKey(locale, bundleName, key); @@ -405,7 +393,7 @@ public class TranslationDevManager extends BasicManager { * @param reallyRemoveIt true: really remove it; false: dry run, only produce logging */ public void removeEmptyKeysTask(boolean reallyRemoveIt) { - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); int counter = 0; Set<String> allLangs = getAllLanguages(); for (String langKey : allLangs) { @@ -418,7 +406,7 @@ public class TranslationDevManager extends BasicManager { String value = properties.getProperty(key); if (!StringHelper.containsNonWhitespace(value) ) { log.info("empty Key detected in lang::" + locale.getLanguage() + " bundle::" + bundleName + " key::" + key + " value::" + value); - File propertyFileDir = I18nModule.getPropertyFilesBaseDir(locale, bundleName); + File propertyFileDir = i18nModule.getPropertyFilesBaseDir(locale, bundleName); if(propertyFileDir != null) { File propertyFile = i18nMgr.getPropertiesFile(locale, bundleName, propertyFileDir); logText.append(propertyFile + " empty Key detected in lang" + locale.getLanguage() + " bundle::" + bundleName + " key::" + key + " value::" + value + "\n"); @@ -447,7 +435,7 @@ public class TranslationDevManager extends BasicManager { // first get all available keys from de and en language Set<String> validCombinedKeys = new HashSet<String>(); //copy list to prevent concurrent modification exception - List<String> allBundles = new ArrayList<String>(I18nModule.getBundleNamesContainingI18nFiles()); + List<String> allBundles = new ArrayList<String>(i18nModule.getBundleNamesContainingI18nFiles()); for (String bundleName : allBundles) { for (String refLangKey : referenceLanguages) { Properties properties = i18nMgr.getPropertiesWithoutResolvingRecursively(i18nMgr.getLocaleOrNull(refLangKey), bundleName); @@ -520,7 +508,7 @@ public class TranslationDevManager extends BasicManager { * reallyCopy: set to true to create Props/keys in Head, false: only log them */ public void getLostTranslationsFromBranch(boolean reallyCopy, String[] referenceLanguages, String pathToOlatBranch, String pathToCoreBranch){ - List<String> allBundles = new ArrayList<String>(I18nModule.getBundleNamesContainingI18nFiles()); + List<String> allBundles = new ArrayList<String>(i18nModule.getBundleNamesContainingI18nFiles()); Set<String> allLangs = getAllLanguages(); //loop over all langs @@ -626,12 +614,12 @@ public class TranslationDevManager extends BasicManager { * false: dry run, only produce logging */ public void removeReferenceLanguageCopiesTask(boolean reallyRemoveIt){ - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); // don't remove EN and DE here, this is a shared Map!! int counter = 0; int aliasCounter = 0; //prepare exclusion list - String exKeys = FileUtils.load(new File(I18nModule.getTransToolApplicationLanguagesSrcDir() + "/org/olat/core/util/i18n/devtools/exclusionKeys.txt"), "UTF-8"); + String exKeys = FileUtils.load(new File(i18nModule.getTransToolApplicationLanguagesSrcDir() + "/org/olat/core/util/i18n/devtools/exclusionKeys.txt"), "UTF-8"); String[] exArray = exKeys.split("\n"); List<String> exList = new ArrayList<String>(Arrays.asList(exArray)); @@ -675,7 +663,7 @@ public class TranslationDevManager extends BasicManager { } if (readyToDelete) { counter++; - logText.append(i18nMgr.getPropertiesFile(locale, bundleName, I18nModule.getPropertyFilesBaseDir(locale, bundleName)) + + logText.append(i18nMgr.getPropertiesFile(locale, bundleName, i18nModule.getPropertyFilesBaseDir(locale, bundleName)) + " value of key found in reference -> remove lang::" + locale.getLanguage() + " bundle::" + bundleName + " key::" + key + " value::" + value + "\n"); } } @@ -689,9 +677,9 @@ public class TranslationDevManager extends BasicManager { // do this only for reference language! public List<I18nItem> getDouplicateKeys(){ - Locale refLocale = I18nModule.getDefaultLocale(); + Locale refLocale = i18nModule.getDefaultLocale(); List<I18nItem> doupList = new ArrayList<I18nItem>(); - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); Map<String, String> tempKeyMap = new HashMap<String, String>(); for (String bundleName : allBundles) { @@ -716,9 +704,9 @@ public class TranslationDevManager extends BasicManager { //do this only for reference language! public List<I18nItem> getDouplicateValues(){ - Locale refLocale = I18nModule.getDefaultLocale(); + Locale refLocale = i18nModule.getDefaultLocale(); List<I18nItem> doupList = new ArrayList<I18nItem>(); - List<String> allBundles = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> allBundles = i18nModule.getBundleNamesContainingI18nFiles(); Map<String, String> tempKeyMap = new HashMap<String, String>(); for (String bundleName : allBundles) { @@ -755,10 +743,10 @@ public class TranslationDevManager extends BasicManager { } private File getBundlePath(String bundleName){ - Locale locale = I18nModule.getAllLocales().get("de"); - File baseDir = I18nModule.getPropertyFilesBaseDir(locale, bundleName); + Locale locale = i18nModule.getAllLocales().get("de"); + File baseDir = i18nModule.getPropertyFilesBaseDir(locale, bundleName); if (baseDir != null) { - File deFile = I18nManager.getInstance().getPropertiesFile(locale, bundleName, baseDir); + File deFile = i18nMgr.getPropertiesFile(locale, bundleName, baseDir); return deFile.getParentFile(); } return null; @@ -800,43 +788,4 @@ public class TranslationDevManager extends BasicManager { out.close(); } } - - public void logToFile(String fname){ -// FileUtils.save(new File("/Users/rhaag/Desktop/devtoolsoutput/"+fname+".txt"), logText.toString(), "UTF-8"); -// logText = new StringBuffer(); - } - - -// String srcPath; -// if (bundleName.startsWith("org.olat.core")) { -// srcPath = I18nModule.getTransToolCoreLanguagesSrcDir().getAbsolutPath(); -// if (srcPath == null) { -// log.error("Can not add bundle priority to core while olatcore source path is not configured! Check olatcore.src in olat.properties"); -// return; -// } -// } else { -// srcPath = I18nModule.getTransToolApplicationLanguagesSrcDir().getAbsolutPath(); -// } -// File baseDir = new File(srcPath + bundleName.replace(".", "/")); -// if (baseDir.exists()) { -// addMissingBundlePriority(baseDir, priority); -// } else { -// log.error("Can not add priority to bundle::" + bundleName + " - invalid source path::" + baseDir.getAbsolutePath()); -// } -// } -// -// private void addMissingBundlePriority(File dir, int priority) { -// File[] files = dir.listFiles(DirectoryFilter.DIRECTORY_FILTER); -// for (File childDir : files) { -// if (childDir.getName().equals(I18nManager.I18N_DIRNAME )) { -// // add priority to file -// int bundle1Prio = getBundlePriority(metadata1, bundle1); -// -// } else { -// // do it recursively -// addMissingBundlePriority(childDir, priority); -// } -// } -// } - } diff --git a/src/main/java/org/olat/core/util/i18n/devtools/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/util/i18n/devtools/_i18n/LocalStrings_pl.properties index e3470096876240fbd42e067f91844ed8b63068b9..6b0c39a2ea9992bbbf01a329d0aa51df75ba4ec9 100644 --- a/src/main/java/org/olat/core/util/i18n/devtools/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/core/util/i18n/devtools/_i18n/LocalStrings_pl.properties @@ -1,16 +1,57 @@ -#Mon Mar 02 09:54:16 CET 2009 +#Thu Jul 27 15:34:48 CEST 2017 caching.enabled=Pami\u0119\u0107 podr\u0119czna jest aktywna. Przed skorzystaniem z narz\u0119dzi dla deweloper\u00F3w, powinna zosta\u0107 wy\u0142\u0105czona. coreasjar=Brasato za\u0142adowane jest jako Jar, dlatego nie mo\u017Cesz dokonywa\u0107 modyfikacji. devtools.title=Narz\u0119dzia deweloperskie dla t\u0142umacze\u0144 +devtools.warning=Modu\u0142 i18n musi zosta\u0107 w\u0142\u0105czony. Skonfiguruj nast\u0119puj\u0105ce linie w olat.local.properties\:<br/><br/>is.translation.server\=enabled<br/>i18n.application.src.dir\=${project.build.home.directory}/src/main/java +menu.i18nDev.alt=i18n maintenance +submitAddKey=Dodaj klucz\! +submitGetDupKeys=Pobierz zduplikowane klucze +submitGetDupVals=Pobierz zduplikowane warto\u015Bci +submitMerge=Scal +submitMove=Przesu\u0144 +submitMoveKey=Przenie\u015B klucz +submitRemoveDeleted=Usu\u0144 skasowane klucze +submitRemoveEmpty=Usu\u0144 puste klucze +submitRemoveKey=Usu\u0144 klucz +submitRemovePackage=Usu\u0144 pakiet +submitRemoveTodo=Usu\u0144 klucze do zrobienia +submitRenameKey=Zmie\u0144 nazw\u0119 klucza +submitRenameLanguage=Zmie\u0144 nazw\u0119 j\u0119zyka +submitSort=Sortuj +task.add.key=Dodaj nowy klucz +task.add.key.bundle=Pakiet +task.add.key.key=Klucz +task.add.key.value=Warto\u015B\u0107 task.delete.key=Usu\u0144 klucz task.delete.package=Usu\u0144 pakiet task.find.douplicates=Znajd\u017A duplikaty task.find.unreferenced.keys=Znajd\u017A niepowi\u0105zane klucze -task.merge.package=Po\u0142\u0105cz pekiety +task.merge.package=Po\u0142\u0105cz pakiety task.move.key=Przesu\u0144 klucze +task.move.key.key=Klucz +task.move.key.to.bundle=Przesu\u0144 klucz task.move.language=Przesu\u0144 j\u0119zyk task.move.package=Przesu\u0144 pakiet +task.move.package.source=\u0179r\u00F3d\u0142o +task.move.package.target=Cel +task.remove.deletedKeys=Usu\u0144 skasowane klucze +task.remove.emptyKeys=Usu\u0144 puste klucze +task.remove.key=Usu\u0144 klucz +task.remove.key.bundle=Pakiet +task.remove.key.key=Klucz +task.remove.package=Usu\u0144 pakiet +task.remove.package.bundle=Pakiet +task.remove.todoKeys=Usu\u0144 klucze do zrobienia +task.remove.xKeys=Usu\u0144 klucze x task.remove.xkeys=Usu\u0144 klucze x task.rename.key=Zmie\u0144 nazw\u0119 klucza +task.rename.key.bundle=Pakiet +task.rename.key.orig=Oryginalna nazwa klucza +task.rename.key.origBundle=Oryginalny Pakiet +task.rename.key.target=Docelowa nazwa klucza +task.rename.key.targetBundle=Docelowy Pakiet task.rename.language=Zmie\u0144 nazw\u0119 j\u0119zyka +task.rename.language.source=J\u0119zyk \u017Ar\u00F3d\u0142owy +task.rename.language.target=J\u0119zyk docelowy +task.sort.keys=Sortuj wszystkie klucze task.unknown.keys=Poka\u017C/usu\u0144 nieprawid\u0142owe klucze diff --git a/src/main/java/org/olat/core/util/i18n/devtools/_spring/devtoolsCorecontext.xml b/src/main/java/org/olat/core/util/i18n/devtools/_spring/devtoolsCorecontext.xml index e4c33b1f1b5650940352fb6a16cb88dc0ea1a5ca..ff6bcb4ce67b0f8e9ded994a502d9dcdf1671ad4 100644 --- a/src/main/java/org/olat/core/util/i18n/devtools/_spring/devtoolsCorecontext.xml +++ b/src/main/java/org/olat/core/util/i18n/devtools/_spring/devtoolsCorecontext.xml @@ -5,9 +5,6 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> -<bean id="translationDevManager" class="org.olat.core.util.i18n.devtools.TranslationDevManager"> - <constructor-arg ref="I18nManager" /> -</bean> <!-- Devel / snoop user session --> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> <property name="order" value="15120" /> diff --git a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigController.java b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigController.java index a49cb3bd4225d2b401baf2755c8ca6f98173b90f..0485dcf8481ebdbb793955592934cc6491c69c30 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigController.java @@ -40,6 +40,7 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle import org.olat.core.util.ArrayHelper; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; +import org.springframework.beans.factory.annotation.Autowired; /** * <h3>Description:</h3> This controller offers a workflow to configure the @@ -68,6 +69,11 @@ class I18nConfigController extends FormBasicController { private FormLink createLanguageLink, deleteLanguageLink, importPackageLink, exportPackageLink, deletePackageLink; private CloseableModalController cmc; private Controller subCtr; + + @Autowired + private I18nManager i18nMgr; + @Autowired + private I18nModule i18nModule; /** * Constructor for the language configuration workflow @@ -86,15 +92,14 @@ class I18nConfigController extends FormBasicController { */ @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - I18nManager i18nMgr = I18nManager.getInstance(); // // Add default languages pulldown - Set<String> availableKeys = I18nModule.getAvailableLanguageKeys(); + Set<String> availableKeys = i18nModule.getAvailableLanguageKeys(); String[] defaultlangKeys = ArrayHelper.toArray(availableKeys); String[] defaultLangValues = new String[defaultlangKeys.length]; for (int i = 0; i < defaultlangKeys.length; i++) { String key = defaultlangKeys[i]; - String explLang = i18nMgr.getLanguageInEnglish(key, I18nModule.isOverlayEnabled()); + String explLang = i18nMgr.getLanguageInEnglish(key, i18nModule.isOverlayEnabled()); String all = explLang; if (explLang != null && !explLang.equals(key)) all += " (" + key + ")"; defaultLangValues[i] = all; @@ -111,10 +116,10 @@ class I18nConfigController extends FormBasicController { // Add enabled languages checkboxes String[] availablelangKeys = ArrayHelper.toArray(availableKeys); String[] availableValues = new String[availablelangKeys.length]; - int referenceKeyCount = i18nMgr.countI18nItems(I18nModule.getFallbackLocale(), null, true); + int referenceKeyCount = i18nMgr.countI18nItems(i18nModule.getFallbackLocale(), null, true); for (int i = 0; i < availablelangKeys.length; i++) { String key = availablelangKeys[i]; - String explLang = i18nMgr.getLanguageInEnglish(key, I18nModule.isOverlayEnabled()); + String explLang = i18nMgr.getLanguageInEnglish(key, i18nModule.isOverlayEnabled()); String all = explLang; if (explLang != null && !explLang.equals(key)) all += " (" + key + ")"; // count translation status @@ -133,12 +138,12 @@ class I18nConfigController extends FormBasicController { enabledLangSelection.setEscapeHtml(false); enabledLangSelection.addActionListener(FormEvent.ONCLICK); // Radios/Checkboxes need onclick because of IE bug OLAT-5753 // Enable current enabled languages - for (String langKey : I18nModule.getEnabledLanguageKeys()) { + for (String langKey : i18nModule.getEnabledLanguageKeys()) { enabledLangSelection.select(langKey, true); } // // Add create / delete links, but only when translation tool is configured - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { createLanguageLink = uifactory.addFormLink("configuration.management.create", formLayout, Link.BUTTON); deleteLanguageLink = uifactory.addFormLink("configuration.management.delete", formLayout, Link.BUTTON); } @@ -166,12 +171,12 @@ class I18nConfigController extends FormBasicController { if (source == defaultLangSelection) { // Get new default language and update I18nModule accordingly String langKey = defaultLangSelection.getSelectedKey(); - Locale defaultLocale = I18nManager.getInstance().getLocaleOrNull(langKey); + Locale defaultLocale = i18nMgr.getLocaleOrNull(langKey); this.flc.contextPut("defaultLangKey", defaultLocale.toString()); - I18nModule.setDefaultLocale(defaultLocale); + i18nModule.setDefaultLocale(defaultLocale); // Make sure this language is in the list of enabled languages enabledLangSelection.select(langKey, true); - I18nModule.getEnabledLanguageKeys().add(langKey); + i18nModule.getEnabledLanguageKeys().add(langKey); } else if (source == enabledLangSelection) { // Get enabled values, make sure the default language is enabled and @@ -195,7 +200,7 @@ class I18nConfigController extends FormBasicController { // showWarning("configuration.fallback.lang.must.be.enabed", fallbackLangKey); // } - I18nModule.setEnabledLanguageKeys(enabledLangKeys); + i18nModule.setEnabledLanguageKeys(enabledLangKeys); } else if (source == createLanguageLink) { // Show new language sub form in an overlay window diff --git a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubDeleteLangController.java b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubDeleteLangController.java index 4346c295905956959464c013f7705e8ce73d7ffe..541d10682b6aee955c5c01f0c6640c15b3fd72bf 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubDeleteLangController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubDeleteLangController.java @@ -46,6 +46,7 @@ import org.olat.core.logging.AssertException; import org.olat.core.util.ArrayHelper; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -68,6 +69,11 @@ class I18nConfigSubDeleteLangController extends FormBasicController { private DialogBoxController dialogCtr; private FormLink cancelButton; private FormSubmit submitButton; + + @Autowired + private I18nManager i18nMgr; + @Autowired + private I18nModule i18nModule; /** * Constructor for the delete-language workflow @@ -77,7 +83,7 @@ class I18nConfigSubDeleteLangController extends FormBasicController { */ public I18nConfigSubDeleteLangController(UserRequest ureq, WindowControl control) { super(ureq, control, LAYOUT_VERTICAL); - if (!I18nModule.isTransToolEnabled()) { throw new AssertException( + if (!i18nModule.isTransToolEnabled()) { throw new AssertException( "Languages can only be deleted when the translation tool is enabled and the translation tool source pathes are configured in the olat.properties"); } initForm(ureq); } @@ -88,13 +94,12 @@ class I18nConfigSubDeleteLangController extends FormBasicController { */ @Override protected void initForm(FormItemContainer formLayout, Controller listener,UserRequest ureq) { - I18nManager i18nMgr = I18nManager.getInstance(); // A title, displayed in fieldset setFormTitle("configuration.management.delete.title"); setFormDescription("configuration.management.delete.description"); // // Add languages checkboxes - Set<String> deletableKeysUnsorted = I18nModule.getTranslatableLanguageKeys(); + Set<String> deletableKeysUnsorted = i18nModule.getTranslatableLanguageKeys(); String[] deletableKeys = ArrayHelper.toArray(deletableKeysUnsorted); String[] availableValues = new String[deletableKeys.length]; for (int i = 0; i < deletableKeys.length; i++) { @@ -132,10 +137,10 @@ class I18nConfigSubDeleteLangController extends FormBasicController { showError("configuration.management.delete.error", defaultKey); return; } - String fallbackKey = I18nModule.getFallbackLocale().toString(); + String fallbackKey = i18nModule.getFallbackLocale().toString(); if (toDelete.contains(fallbackKey)) { deleteLangSelection.select(fallbackKey, false); - showError("configuration.management.delete.error", I18nModule.getFallbackLocale().toString()); + showError("configuration.management.delete.error", i18nModule.getFallbackLocale().toString()); return; } dialogCtr = activateYesNoDialog(ureq, translate("configuration.management.delete.confirm.title"), translate( @@ -146,12 +151,13 @@ class I18nConfigSubDeleteLangController extends FormBasicController { * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, * org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) */ + @Override public void event(UserRequest ureq, Controller source, Event event) { if (source == dialogCtr) { if (DialogBoxUIFactory.isYesEvent(event)) { // Yes case, delete now for (String deleteLang : deleteLangSelection.getSelectedKeys()) { - I18nManager.getInstance().deleteLanguage(deleteLang, true); + i18nMgr.deleteLanguage(deleteLang, true); logAudit("Deleted language::" + deleteLang, null); } // wow, everything worked fine diff --git a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubDeletePackageController.java b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubDeletePackageController.java index e1c28ae035d2f1919f9910caf53e9d7eaa3af1d5..949464188b95f331c6074a19a16316bd546e49c0 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubDeletePackageController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubDeletePackageController.java @@ -43,6 +43,7 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.util.i18n.I18nModule; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -64,6 +65,9 @@ class I18nConfigSubDeletePackageController extends FormBasicController { private DialogBoxController dialogCtr; private FormLink cancelButton; private FormSubmit submitButton; + + @Autowired + private I18nModule i18nModule; /** * Constructor for the delete-language pack workflow @@ -121,7 +125,7 @@ class I18nConfigSubDeletePackageController extends FormBasicController { logAudit("Deleted language pack::" + deleteLangPack, null); } // Reset i18n system - I18nModule.reInitializeAndFlushCache(); + i18nModule.reInitializeAndFlushCache(); // wow, everything worked fine showInfo("configuration.management.package.delete.success", deleteLangPackSelection.getSelectedKeys().toString()); fireEvent(ureq, Event.DONE_EVENT); diff --git a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubExportLangController.java b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubExportLangController.java index 719f9a824e46a47aed88817573e408546935e1b9..91d0b7a807202d83e96e6c3caa7fd78d988cf4f5 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubExportLangController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubExportLangController.java @@ -47,6 +47,7 @@ import org.olat.core.util.ArrayHelper; import org.olat.core.util.CodeHelper; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -67,6 +68,11 @@ class I18nConfigSubExportLangController extends FormBasicController { private MultipleSelectionElement exportLangSelection; private FormLink cancelButton; private FormSubmit submitButton; + + @Autowired + private I18nModule i18nModule; + @Autowired + private I18nManager i18nMgr; /** * Constructor for the export-language workflow @@ -85,13 +91,12 @@ class I18nConfigSubExportLangController extends FormBasicController { */ @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - I18nManager i18nMgr = I18nManager.getInstance(); // A title, displayed in fieldset setFormTitle("configuration.management.package.export.title"); setFormDescription("configuration.management.package.export.description"); // // Add languages checkboxes - Set<String> availableKeysUnsorted = I18nModule.getAvailableLanguageKeys(); + Set<String> availableKeysUnsorted = i18nModule.getAvailableLanguageKeys(); String[] availableKeys = ArrayHelper.toArray(availableKeysUnsorted); String[] availableValues = new String[availableKeys.length]; for (int i = 0; i < availableKeys.length; i++) { @@ -127,7 +132,7 @@ class I18nConfigSubExportLangController extends FormBasicController { } String tmpFileName = CodeHelper.getGlobalForeverUniqueID(); // crate new temp file - File exportFile = I18nManager.getInstance().createLanguageJarFile(toExport, tmpFileName); + File exportFile = i18nMgr.createLanguageJarFile(toExport, tmpFileName); if (exportFile != null) { String fileName = "language_export_" + Settings.getApplicationName() + "_" + Settings.getVersion() + ".jar"; // Create a temporary media resource that gets deleted from the diff --git a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubImportLangController.java b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubImportLangController.java index e5429c050e1f161c515ccf4eb038bfe76ea9a446..23ee6e9611046bca2611b549c4bbb0ca2578d993 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubImportLangController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubImportLangController.java @@ -41,6 +41,7 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.util.ArrayHelper; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; +import org.springframework.beans.factory.annotation.Autowired; /** * <h3>Description:</h3> This form allows the user to import languages from a @@ -61,6 +62,11 @@ class I18nConfigSubImportLangController extends FormBasicController { private FileElement importFile; private FormLink cancelButton; private MultipleSelectionElement importKeys; + + @Autowired + private I18nModule i18nModule; + @Autowired + private I18nManager i18nManager; public I18nConfigSubImportLangController(UserRequest ureq, WindowControl control) { super(ureq, control, LAYOUT_VERTICAL); @@ -71,7 +77,7 @@ class I18nConfigSubImportLangController extends FormBasicController { protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { // A title, displayed in fieldset setFormTitle("configuration.management.package.import.title"); - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { setFormDescription("configuration.management.package.import.description.transserver"); } else { setFormDescription("configuration.management.package.import.description"); @@ -108,15 +114,15 @@ class I18nConfigSubImportLangController extends FormBasicController { Collection<String> importLangKeys = importKeys.getSelectedKeys(); Set<String> alreadyInstalledLangs = new HashSet<String>(); for (String langKey : importLangKeys) { - if (I18nModule.getAvailableLanguageKeys().contains(langKey)) { + if (i18nModule.getAvailableLanguageKeys().contains(langKey)) { alreadyInstalledLangs.add(langKey); } } - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { // In translation mode importing will copy the language package // over an existing language or create a new language File tmpJar = importFile.getUploadFile(); - I18nManager.getInstance().copyLanguagesFromJar(tmpJar, importLangKeys); + i18nManager.copyLanguagesFromJar(tmpJar, importLangKeys); logAudit("Uploaded languages from jar::" + importFile.getUploadFileName(), null); showInfo("configuration.management.package.import.success", importLangKeys.toString()); @@ -139,7 +145,7 @@ class I18nConfigSubImportLangController extends FormBasicController { } } // Reset i18n system - I18nModule.reInitializeAndFlushCache(); + i18nModule.reInitializeAndFlushCache(); fireEvent(ureq, Event.DONE_EVENT); } } @@ -153,7 +159,7 @@ class I18nConfigSubImportLangController extends FormBasicController { } else if (source == importFile) { if (importFile.isUploadSuccess()) { File tmpJar = importFile.getUploadFile(); - Set<String> importLangKeys = I18nManager.getInstance().sarchForAvailableLanguagesInJarFile(tmpJar, true); + Set<String> importLangKeys = i18nManager.sarchForAvailableLanguagesInJarFile(tmpJar, true); if (importLangKeys.size() == 0) { showError("configuration.management.package.import.failure.empty"); return; diff --git a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubNewLangController.java b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubNewLangController.java index 397c6ba305e140931a2927af8d718a0aae2476b9..ccd78fd9d2c1d6f411ef9159a799df383bde4740 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubNewLangController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/I18nConfigSubNewLangController.java @@ -51,6 +51,7 @@ import org.olat.core.util.Util; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -72,6 +73,9 @@ import org.olat.user.UserManager; class I18nConfigSubNewLangController extends FormBasicController { private TextElement newLanguage, newCountry, newVariant, newTranslatedInEnglish, newTranslatedInLanguage, newTranslator; private FormLink cancelButton; + + @Autowired + private I18nModule i18nModule; /** * Constructor for the new-language workflow @@ -81,7 +85,7 @@ class I18nConfigSubNewLangController extends FormBasicController { */ protected I18nConfigSubNewLangController(UserRequest ureq, WindowControl control) { super(ureq, control, LAYOUT_DEFAULT); - if (!I18nModule.isTransToolEnabled()) { throw new AssertException( + if (!i18nModule.isTransToolEnabled()) { throw new AssertException( "New languages can only be created when the translation tool is enabled and the translation tool source pathes are configured in the olat.properties"); } initForm(ureq); } diff --git a/src/main/java/org/olat/core/util/i18n/ui/InlineTranslationInterceptHandlerController.java b/src/main/java/org/olat/core/util/i18n/ui/InlineTranslationInterceptHandlerController.java index 790cf85b08a852515c0bd54a1a352ad5c71eb185..c65e010f507546376e3aa49aac0710d6c1dbb248 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/InlineTranslationInterceptHandlerController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/InlineTranslationInterceptHandlerController.java @@ -25,6 +25,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringEscapeUtils; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.ComponentRenderer; @@ -48,6 +49,7 @@ import org.olat.core.util.i18n.I18nItem; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; import org.olat.core.util.prefs.Preferences; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -86,6 +88,11 @@ public class InlineTranslationInterceptHandlerController extends BasicController private static final Pattern patternInput = Pattern.compile("<input[^>]*?" + decoratedTranslatedPattern + ".*?>"); private static final Pattern patAttribute = Pattern.compile("<[^>]*?" + decoratedTranslatedPattern + "[^>]*?>"); + @Autowired + private I18nManager i18nMgr; + @Autowired + private I18nModule i18nModule; + /** * Constructor * @@ -200,16 +207,14 @@ public class InlineTranslationInterceptHandlerController extends BasicController if (StringHelper.containsNonWhitespace(bundle) && StringHelper.containsNonWhitespace(key)) { // Get userconfigured reference locale Preferences guiPrefs = ureq.getUserSession().getGuiPreferences(); - List<String> referenceLangs = I18nModule.getTransToolReferenceLanguages(); - String referencePrefs = (String) guiPrefs.get(I18nModule.class, I18nModule.GUI_PREFS_PREFERRED_REFERENCE_LANG, referenceLangs - .get(0)); - I18nManager i18nMgr = I18nManager.getInstance(); + List<String> referenceLangs = i18nModule.getTransToolReferenceLanguages(); + String referencePrefs = (String) guiPrefs.get(I18nModule.class, I18nModule.GUI_PREFS_PREFERRED_REFERENCE_LANG, referenceLangs.get(0)); Locale referenceLocale = i18nMgr.getLocaleOrNull(referencePrefs); // Set target local to current user language Locale targetLocale = i18nMgr.getLocaleOrNull(ureq.getLocale().toString()); - if (I18nModule.isOverlayEnabled() && !I18nModule.isTransToolEnabled()) { + if (i18nModule.isOverlayEnabled() && !i18nModule.isTransToolEnabled()) { // use overlay locale when in customizing mode - targetLocale = I18nModule.getOverlayLocales().get(targetLocale); + targetLocale = i18nModule.getOverlayLocales().get(targetLocale); } List<I18nItem> i18nItems = i18nMgr.findExistingAndMissingI18nItems(referenceLocale, targetLocale, bundle, false); if(i18nItems.isEmpty()) { @@ -222,7 +227,7 @@ public class InlineTranslationInterceptHandlerController extends BasicController // running - // must be done before instantiating the translation controller i18nMgr.setMarkLocalizedStringsEnabled(ureq.getUserSession(), false); - i18nItemEditCtr = new TranslationToolI18nItemEditCrumbController(ureq, getWindowControl(), i18nItems, referenceLocale, !I18nModule.isTransToolEnabled()); + i18nItemEditCtr = new TranslationToolI18nItemEditCrumbController(ureq, getWindowControl(), i18nItems, referenceLocale, !i18nModule.isTransToolEnabled()); listenTo(i18nItemEditCtr); // set current key from the package as current translation item for (I18nItem item : i18nItems) { @@ -251,7 +256,7 @@ public class InlineTranslationInterceptHandlerController extends BasicController protected void event(UserRequest ureq, Controller source, Event event) { if (source == cmc) { // user closed dialog, go back to inline translation mode - I18nManager.getInstance().setMarkLocalizedStringsEnabled(ureq.getUserSession(), true); + i18nMgr.setMarkLocalizedStringsEnabled(ureq.getUserSession(), true); } } @@ -459,7 +464,7 @@ public class InlineTranslationInterceptHandlerController extends BasicController inlineTranslationURLBuilder.buildURI(link, new String[] { ARG_BUNDLE, ARG_KEY, ARG_IDENT }, arguments); link.append("\" title=\""); String combinedKey = arguments[0] + ":" + arguments[1]; - if (I18nModule.isTransToolEnabled()) { + if (CoreSpringFactory.getImpl(I18nModule.class).isTransToolEnabled()) { link.append(StringEscapeUtils.escapeHtml(inlineTrans.translate("inline.translate", new String[] { combinedKey }))); } else { link.append(StringEscapeUtils.escapeHtml(inlineTrans.translate("inline.customize.translate", new String[] { combinedKey }))); diff --git a/src/main/java/org/olat/core/util/i18n/ui/SingleKeyTranslatorController.java b/src/main/java/org/olat/core/util/i18n/ui/SingleKeyTranslatorController.java index cb94ae14990b9d4b4ed1bcdc1a5993d38e3d9a96..82235c18f85381d22aefa715d92e86ab01fd2616 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/SingleKeyTranslatorController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/SingleKeyTranslatorController.java @@ -40,6 +40,7 @@ import org.olat.core.util.Util; import org.olat.core.util.i18n.I18nItem; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -61,7 +62,10 @@ public class SingleKeyTranslatorController extends FormBasicController { private static final String LBL_NAME_PREFIX = "lbl."; private Map<String, TextElement> textElements; + @Autowired private I18nManager i18nMng; + @Autowired + private I18nModule i18nModule; public SingleKeyTranslatorController(UserRequest ureq, WindowControl wControl, String keyToTranslate, Class<?> translatorBaseClass) { this(ureq,wControl,new String[]{keyToTranslate},translatorBaseClass); @@ -94,12 +98,9 @@ public class SingleKeyTranslatorController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - // load 18n-stuff - i18nMng = I18nManager.getInstance(); + Map<Locale, Locale> allOverlays = i18nModule.getOverlayLocales(); - Map<Locale, Locale> allOverlays = I18nModule.getOverlayLocales(); - - Collection<String> enabledKeys = I18nModule.getEnabledLanguageKeys(); + Collection<String> enabledKeys = i18nModule.getEnabledLanguageKeys(); bundles = new ArrayList<I18nRowBundle>(); for (String key : enabledKeys) { Locale loc = i18nMng.getLocaleOrNull(key); diff --git a/src/main/java/org/olat/core/util/i18n/ui/TranslationToolI18nItemEditCrumbController.java b/src/main/java/org/olat/core/util/i18n/ui/TranslationToolI18nItemEditCrumbController.java index d378cb02ea052babfa3073a8c1ba4282c084bf35..fa41cbea99c56d8d6b1d513839220f72990c9fc8 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/TranslationToolI18nItemEditCrumbController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/TranslationToolI18nItemEditCrumbController.java @@ -46,6 +46,7 @@ import org.olat.core.util.i18n.I18nItem; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; import org.olat.core.util.prefs.Preferences; +import org.springframework.beans.factory.annotation.Autowired; /** * <h3>Description:</h3> This controller can be used to edit one or more @@ -83,7 +84,10 @@ public class TranslationToolI18nItemEditCrumbController extends CrumbFormBasicCo // true when the overlay files are edited and not the language files itself private boolean customizingMode = false; - private final I18nManager i18nMgr; + @Autowired + private I18nManager i18nMgr; + @Autowired + private I18nModule i18nModule; /** * Constructor for the item edit controller. Use the @@ -101,12 +105,11 @@ public class TranslationToolI18nItemEditCrumbController extends CrumbFormBasicCo public TranslationToolI18nItemEditCrumbController(UserRequest ureq, WindowControl control, List<I18nItem> i18nItems, Locale referenceLocale, boolean customizingMode) { super(ureq, control, "translationToolI18nItemEdit"); - i18nMgr = I18nManager.getInstance(); this.customizingMode = customizingMode; this.i18nItems = i18nItems; if(referenceLocale == null) { Preferences guiPrefs = ureq.getUserSession().getGuiPreferences(); - List<String> referenceLangs = I18nModule.getTransToolReferenceLanguages(); + List<String> referenceLangs = i18nModule.getTransToolReferenceLanguages(); String referencePrefs = (String)guiPrefs.get(I18nModule.class, I18nModule.GUI_PREFS_PREFERRED_REFERENCE_LANG, referenceLangs.get(0)); this.referenceLocale = i18nMgr.getLocaleOrNull(referencePrefs); if(this.referenceLocale == null) { @@ -200,7 +203,7 @@ public class TranslationToolI18nItemEditCrumbController extends CrumbFormBasicCo flc.contextPut("compareSwitchEnabled", compareEnabledPrefs); // Add compare language selection - Set<String> availableLangKeys = I18nModule.getAvailableLanguageKeys(); + Set<String> availableLangKeys = i18nModule.getAvailableLanguageKeys(); String[] comparelangKeys = ArrayHelper.toArray(availableLangKeys); String[] compareLangValues = new String[comparelangKeys.length]; for (int i = 0; i < comparelangKeys.length; i++) { @@ -218,14 +221,14 @@ public class TranslationToolI18nItemEditCrumbController extends CrumbFormBasicCo if (compareLocale == null) compareLocale = I18nModule.getDefaultLocale(); compareLangSelection = uifactory.addDropdownSingleselect("compareLangSelection", flc, comparelangKeys, compareLangValues, null); compareLangSelection.setDomReplacementWrapperRequired(false); - compareLangSelection.select(i18nMgr.getLocaleKey(compareLocale), true); - flc.contextPut("compareLanguageKey", i18nMgr.getLocaleKey(compareLocale)); + compareLangSelection.select(i18nModule.getLocaleKey(compareLocale), true); + flc.contextPut("compareLanguageKey", i18nModule.getLocaleKey(compareLocale)); compareLangSelection.addActionListener(FormEvent.ONCHANGE); compareLangSelection.setEnabled(compareEnabledPrefs.booleanValue()); // Add target box - flc.contextPut("targetLanguageKey", i18nMgr.getLocaleKey(currentItem.getLocale())); - flc.contextPut("targetLanguage", i18nMgr.getLanguageTranslated(i18nMgr.getLocaleKey(currentItem.getLocale()), false)); + flc.contextPut("targetLanguageKey", i18nModule.getLocaleKey(currentItem.getLocale())); + flc.contextPut("targetLanguage", i18nMgr.getLanguageTranslated(i18nModule.getLocaleKey(currentItem.getLocale()), false)); targetArea = uifactory.addTextAreaElement("targetArea", "edit.targetArea", -1, 5, -1, true, null, flc); // Add annotation box annotationArea = uifactory.addTextAreaElement("annotationArea", "edit.annotationArea", -1, 1, -1, true, null, flc); @@ -254,11 +257,11 @@ public class TranslationToolI18nItemEditCrumbController extends CrumbFormBasicCo // don't edit annotations in customizing mode annotationArea.setEnabled(false); // target lang flags and lang name - Locale origLocale = I18nModule.getAllLocales().get(i18nMgr.createOrigianlLocaleKeyForOverlay(currentItem.getLocale())); + Locale origLocale = i18nModule.getAllLocales().get(i18nMgr.createOrigianlLocaleKeyForOverlay(currentItem.getLocale())); if(origLocale == null) { origLocale = currentItem.getLocale(); } - String localeKey = i18nMgr.getLocaleKey(origLocale); + String localeKey = i18nModule.getLocaleKey(origLocale); flc.contextPut("targetLanguageKey", localeKey); flc.contextPut("targetLanguage", i18nMgr.getLanguageTranslated(localeKey, true)); } diff --git a/src/main/java/org/olat/core/util/i18n/ui/TranslationToolLauncherController.java b/src/main/java/org/olat/core/util/i18n/ui/TranslationToolLauncherController.java index ea3789dfcad06767ee343fc179432174267cf764..8d9bc978de863efed676ed7adceeb14217d936f8 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/TranslationToolLauncherController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/TranslationToolLauncherController.java @@ -35,6 +35,7 @@ import org.olat.core.gui.control.generic.popup.PopupBrowserWindow; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; import org.olat.core.util.prefs.Preferences; +import org.springframework.beans.factory.annotation.Autowired; /** * <h3>Description:</h3> This controller offers a panel for translators. On the @@ -52,6 +53,9 @@ import org.olat.core.util.prefs.Preferences; public class TranslationToolLauncherController extends BasicController { private VelocityContainer translationToolLauncherVC; private Link startTranslationToolLink, enableInlineTranslationLink, disableInlineTranslationLink, cacheFlushLink; + + @Autowired + private I18nModule i18nModule; /** * Constructor for the translation tool start panel controller @@ -66,7 +70,7 @@ public class TranslationToolLauncherController extends BasicController { startTranslationToolLink = LinkFactory.createButton("start", translationToolLauncherVC, this); startTranslationToolLink.setTarget("_transtool"); // Add link to flush the cache - if (I18nManager.getInstance().isCachingEnabled()) { + if (i18nModule.isCachingEnabled()) { cacheFlushLink = LinkFactory.createButton("cache.flush", translationToolLauncherVC, this); } // Add inline translation status and link @@ -74,11 +78,11 @@ public class TranslationToolLauncherController extends BasicController { updateInlineTranslationStatusAndLink(guiPrefs); putInitialPanel(translationToolLauncherVC); // Enable or disable entire translation tool - boolean isTranslationToolEnabled = I18nModule.isTransToolEnabled(); + boolean isTranslationToolEnabled = i18nModule.isTransToolEnabled(); translationToolLauncherVC.contextPut("transToolEnabled", Boolean.valueOf(isTranslationToolEnabled)); // Enable or disable customizing tool. The customzing tool is only enabled // when not configured as translation tool server - translationToolLauncherVC.contextPut("customizingToolEnabled", Boolean.valueOf(!isTranslationToolEnabled && I18nModule.isOverlayEnabled())); + translationToolLauncherVC.contextPut("customizingToolEnabled", Boolean.valueOf(!isTranslationToolEnabled && i18nModule.isOverlayEnabled())); } /* @@ -93,8 +97,9 @@ public class TranslationToolLauncherController extends BasicController { if (source == startTranslationToolLink) { // wrap the content controller into a full header layout ControllerCreator controllerCreator = new ControllerCreator() { + @Override public Controller createController(UserRequest uureq, WindowControl wControl) { - return new TranslationToolMainController(uureq, wControl, !I18nModule.isTransToolEnabled()); + return new TranslationToolMainController(uureq, wControl, !i18nModule.isTransToolEnabled()); } }; // no need for later disposal, opens in popup window and will be disposed @@ -112,7 +117,7 @@ public class TranslationToolLauncherController extends BasicController { } else if (source == cacheFlushLink) { // clear i18n cache - I18nModule.reInitializeAndFlushCache(); + i18nModule.reInitializeAndFlushCache(); showInfo("cache.flush.ok"); } } diff --git a/src/main/java/org/olat/core/util/i18n/ui/TranslationToolStartCrumbController.java b/src/main/java/org/olat/core/util/i18n/ui/TranslationToolStartCrumbController.java index bd63a8b253881ba1bed026f79e55c1b2581642f3..15af7b4c197e67f3501427219c43ba23c46cd780 100644 --- a/src/main/java/org/olat/core/util/i18n/ui/TranslationToolStartCrumbController.java +++ b/src/main/java/org/olat/core/util/i18n/ui/TranslationToolStartCrumbController.java @@ -50,6 +50,7 @@ import org.olat.core.util.i18n.I18nItem; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; import org.olat.core.util.prefs.Preferences; +import org.springframework.beans.factory.annotation.Autowired; /** * <h3>Description:</h3> This is the start controller for the translation tool @@ -112,6 +113,12 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { private Locale targetLocale; // true when the overlay files are edited and not the language files itself private boolean customizingMode = false; + + @Autowired + private I18nModule i18nModule; + @Autowired + private I18nManager i18nManager; + /** * Constructor for the start crumb controller * @@ -135,12 +142,12 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { FormUIFactory formFactory = FormUIFactory.getInstance(); - I18nManager i18nMgr = I18nManager.getInstance(); - List<String> bundleNames = I18nModule.getBundleNamesContainingI18nFiles(); + + List<String> bundleNames = i18nModule.getBundleNamesContainingI18nFiles(); String[] bundlesKeys = buildBundleArrayKeys(bundleNames, true); String[] bundlesValues = buildBundleArrayValues(bundleNames, true); // call init methods for each form part - initLanguageSelectorElements(ureq.getUserSession(), formFactory, i18nMgr, formLayout); + initLanguageSelectorElements(ureq.getUserSession(), formFactory, formLayout); initMissingItemsElements(formFactory, formLayout, bundlesKeys, bundlesValues); initExistingItemsElements(formFactory, formLayout, bundlesKeys, bundlesValues); initAllItemsElements(formFactory, formLayout, bundlesKeys, bundlesValues); @@ -155,22 +162,22 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { this.flc.contextPut("customizingPrefix", (customizingMode ? "customize." : "")); } - private void initLanguageSelectorElements(UserSession usess, FormUIFactory formFactory, I18nManager i18nMgr, + private void initLanguageSelectorElements(UserSession usess, FormUIFactory formFactory, FormItemContainer formLayout) { // Add language selection as a subform List<String> referenceLangs; if (customizingMode) { // Add all enabled languages that can be customized - referenceLangs = new ArrayList<String>(I18nModule.getEnabledLanguageKeys()); + referenceLangs = new ArrayList<>(i18nModule.getEnabledLanguageKeys()); } else { // Add configured reference languages in translation mode - referenceLangs = I18nModule.getTransToolReferenceLanguages(); + referenceLangs = i18nModule.getTransToolReferenceLanguages(); } String[] referencelangKeys = ArrayHelper.toArray(referenceLangs); String[] referenceLangValues = new String[referencelangKeys.length]; for (int i = 0; i < referencelangKeys.length; i++) { String key = referencelangKeys[i]; - String explLang = i18nMgr.getLanguageInEnglish(key, false); + String explLang = i18nManager.getLanguageInEnglish(key, false); String all = explLang; if (explLang != null && !explLang.equals(key)) all += " (" + key + ")"; referenceLangValues[i] = all; @@ -178,13 +185,13 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { ArrayHelper.sort(referencelangKeys, referenceLangValues, false, true, false); // Build css classes for reference languages // Use first reference locale as default - referenceLocale = i18nMgr.getLocaleOrNull(referenceLangs.get(0)); + referenceLocale = i18nManager.getLocaleOrNull(referenceLangs.get(0)); // Override with user preset Preferences guiPrefs = usess.getGuiPreferences(); String referencePrefs = (String) guiPrefs.get(I18nModule.class, I18nModule.GUI_PREFS_PREFERRED_REFERENCE_LANG, referenceLangs.get(0)); for (String refLang : referencelangKeys) { if (referencePrefs.equals(refLang)) { - referenceLocale = i18nMgr.getLocaleOrNull(referencePrefs); + referenceLocale = i18nManager.getLocaleOrNull(referencePrefs); break; } } @@ -197,10 +204,10 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { Set<String> translatableKeys; if (customizingMode) { // Use all enabled languages in customizing mode - translatableKeys = I18nModule.getOverlayLanguageKeys(); + translatableKeys = i18nModule.getOverlayLanguageKeys(); } else { // Allow translators to also translate other languages if they really desire. Show all languages. - translatableKeys = I18nModule.getTranslatableLanguageKeys(); + translatableKeys = i18nModule.getTranslatableLanguageKeys(); } String[] targetlangKeys = ArrayHelper.toArray(translatableKeys); String[] targetLangValues = new String[targetlangKeys.length]; @@ -211,10 +218,10 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { // overlay enabled, this would double the customizing extension to the key String explLang; if (customizingMode) { - String origKey = i18nMgr.createOrigianlLocaleKeyForOverlay(I18nModule.getAllLocales().get(key)); - explLang = i18nMgr.getLanguageInEnglish(origKey, true); + String origKey = i18nManager.createOrigianlLocaleKeyForOverlay(i18nModule.getAllLocales().get(key)); + explLang = i18nManager.getLanguageInEnglish(origKey, true); } else { - explLang = i18nMgr.getLanguageInEnglish(key, false); + explLang = i18nManager.getLanguageInEnglish(key, false); } String all = explLang; if (explLang != null && !explLang.equals(key)) all += " (" + key + ")"; @@ -226,26 +233,26 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { // Select current language if in list or the first one in the menu if (customizingMode) { // Use same as reference language in customizing mode - targetLocale = I18nModule.getOverlayLocales().get(referenceLocale); + targetLocale = i18nModule.getOverlayLocales().get(referenceLocale); // Disable target lang selection - user should only choose reference language, target is updated automatically targetLangSelection.setEnabled(false); } else { // Use users current language in translation mode targetLocale = getTranslator().getLocale(); - if (!Arrays.asList(targetlangKeys).contains(i18nMgr.getLocaleKey(targetLocale))) { - targetLocale = i18nMgr.getLocaleOrNull(targetlangKeys[0]); + if (!Arrays.asList(targetlangKeys).contains(i18nModule.getLocaleKey(targetLocale))) { + targetLocale = i18nManager.getLocaleOrNull(targetlangKeys[0]); } } - targetLangSelection.select(i18nMgr.getLocaleKey(targetLocale), true); + targetLangSelection.select(i18nModule.getLocaleKey(targetLocale), true); // Add lang key for image - don't use customizing lang key if (customizingMode) { - this.flc.contextPut("targetLangKey", i18nMgr.createOrigianlLocaleKeyForOverlay(targetLocale)); + this.flc.contextPut("targetLangKey", i18nManager.createOrigianlLocaleKeyForOverlay(targetLocale)); } else { this.flc.contextPut("targetLangKey", targetLocale.toString()); } targetLangSelection.addActionListener(FormEvent.ONCHANGE); // Add progress bar as normal component (not a form element) - int bundlesCount = i18nMgr.countBundles(null, true); + int bundlesCount = i18nManager.countBundles(null, true); progressBar = new ProgressBar("progressBar", 300, 0, 0, translate("start.progressBar.unitLabel", bundlesCount + "")); this.flc.put("progressBar", progressBar); } @@ -389,10 +396,9 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { * */ private void updateStatistics() { - I18nManager i18nMgr = I18nManager.getInstance(); // update progress bar with all package values - int toTranslateCount = i18nMgr.countI18nItems(referenceLocale, null, true); - int translatedCount = i18nMgr.countI18nItems(targetLocale, null, true); + int toTranslateCount = i18nManager.countI18nItems(referenceLocale, null, true); + int translatedCount = i18nManager.countI18nItems(targetLocale, null, true); progressBar.setMax(toTranslateCount); progressBar.setActual(translatedCount); // calculate package dependent values for missing keys display @@ -400,9 +406,9 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { if (missingBundle.equals(ALL_BUNDLES_IDENTIFYER)) { this.flc.contextPut("missingCount", (toTranslateCount - translatedCount)); } else { - int missingToTranslateCount = i18nMgr.countI18nItems(referenceLocale, missingBundle, missingBundlesIncludeBundlesChildrenSwitch + int missingToTranslateCount = i18nManager.countI18nItems(referenceLocale, missingBundle, missingBundlesIncludeBundlesChildrenSwitch .isSelected(0)); - int missingTranslatedCount = i18nMgr.countI18nItems(targetLocale, missingBundle, missingBundlesIncludeBundlesChildrenSwitch + int missingTranslatedCount = i18nManager.countI18nItems(targetLocale, missingBundle, missingBundlesIncludeBundlesChildrenSwitch .isSelected(0)); this.flc.contextPut("missingCount", (missingToTranslateCount - missingTranslatedCount)); } @@ -410,7 +416,7 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { if (existingBundle.equals(ALL_BUNDLES_IDENTIFYER)) { this.flc.contextPut("existingCount", translatedCount); } else { - int existingTranslateCount = i18nMgr.countI18nItems(referenceLocale, existingBundle, existingBundlesIncludeBundlesChildrenSwitch.isSelected(0)); + int existingTranslateCount = i18nManager.countI18nItems(referenceLocale, existingBundle, existingBundlesIncludeBundlesChildrenSwitch.isSelected(0)); this.flc.contextPut("existingCount", existingTranslateCount); } // calculate package dependent values for all keys display @@ -418,7 +424,7 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { if (allBundle.equals(ALL_BUNDLES_IDENTIFYER)) { this.flc.contextPut("allCount", toTranslateCount); } else { - int allToTranslateCount = i18nMgr.countI18nItems(referenceLocale, allBundle, allBundlesIncludeBundlesChildrenSwitch.isSelected(0)); + int allToTranslateCount = i18nManager.countI18nItems(referenceLocale, allBundle, allBundlesIncludeBundlesChildrenSwitch.isSelected(0)); this.flc.contextPut("allCount", allToTranslateCount); } } @@ -428,10 +434,9 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { * instead of the translation texts */ private void setCustomizingTextLabels() { - I18nManager i18nMgr = I18nManager.getInstance(); referenceLangSelection.setLabel("start.customize.referenceLangSelection", null); targetLangSelection.setLabel("start.customize.targetLangSelection", null); - int bundlesCount = i18nMgr.countBundles(null, true); + int bundlesCount = i18nManager.countBundles(null, true); progressBar.setUnitLabel(translate("start.customize.progressBar.unitLabel", bundlesCount + "")); missingTranslateButton.setI18nKey("generic.customize.translateButton"); allTranslateButton.setI18nKey("generic.customize.translateButton"); @@ -448,13 +453,12 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { * org.olat.core.gui.components.form.flexible.impl.FormEvent) */ protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { - I18nManager i18nMgr = I18nManager.getInstance(); if (source == targetLangSelection) { String langKey = targetLangSelection.getSelectedKey(); - targetLocale = i18nMgr.getLocaleOrNull(langKey); + targetLocale = i18nManager.getLocaleOrNull(langKey); // Add lang key for image - don't use customizing lang key if (customizingMode) { - this.flc.contextPut("targetLangKey", i18nMgr.createOrigianlLocaleKeyForOverlay(targetLocale)); + this.flc.contextPut("targetLangKey", i18nManager.createOrigianlLocaleKeyForOverlay(targetLocale)); } else { this.flc.contextPut("targetLangKey", targetLocale.toString()); } @@ -462,17 +466,17 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { } else if (source == referenceLangSelection) { String langKey = referenceLangSelection.getSelectedKey(); - referenceLocale = i18nMgr.getLocaleOrNull(langKey); + referenceLocale = i18nManager.getLocaleOrNull(langKey); // update in gui prefs Preferences guiPrefs = ureq.getUserSession().getGuiPreferences(); guiPrefs.putAndSave(I18nModule.class, I18nModule.GUI_PREFS_PREFERRED_REFERENCE_LANG, referenceLocale.toString()); // update GUI - this.flc.contextPut("referenceLangKey", i18nMgr.getLocaleKey(referenceLocale)); + this.flc.contextPut("referenceLangKey", i18nModule.getLocaleKey(referenceLocale)); // Set target language to reference language when in customizing mode if (customizingMode) { - targetLocale = I18nModule.getOverlayLocales().get(referenceLocale); - targetLangSelection.select(i18nMgr.getLocaleKey(targetLocale), true); - this.flc.contextPut("targetLangKey", i18nMgr.getLocaleKey(referenceLocale)); + targetLocale = i18nModule.getOverlayLocales().get(referenceLocale); + targetLangSelection.select(i18nModule.getLocaleKey(targetLocale), true); + this.flc.contextPut("targetLangKey", i18nModule.getLocaleKey(referenceLocale)); } updateStatistics(); @@ -481,10 +485,10 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { if (bundle.equals(ALL_BUNDLES_IDENTIFYER)) bundle = null; boolean includeBundlesChildren = missingBundlesIncludeBundlesChildrenSwitch.isSelected(0); // use the fallback locale because it won't find the key if not already translated in the searchLocale - List<I18nItem> i18nItems = i18nMgr.findMissingI18nItems(referenceLocale, targetLocale, bundle, + List<I18nItem> i18nItems = i18nManager.findMissingI18nItems(referenceLocale, targetLocale, bundle, includeBundlesChildren); boolean prioSortEnabled = missingBundlesPrioritySortSwitch.isSelected(0); - i18nMgr.sortI18nItems(i18nItems, prioSortEnabled, prioSortEnabled); + i18nManager.sortI18nItems(i18nItems, prioSortEnabled, prioSortEnabled); deactivateAndDisposeChildCrumbController(); // first the list controller TranslationToolI18nItemListCrumbController i18nItemlistCrumbCtr = new TranslationToolI18nItemListCrumbController(ureq, @@ -501,9 +505,9 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { String bundle = existingBundlesSelection.getSelectedKey(); if (bundle.equals(ALL_BUNDLES_IDENTIFYER)) bundle = null; boolean includeBundlesChildren = existingBundlesIncludeBundlesChildrenSwitch.isSelected(0); - List<I18nItem> i18nItems = i18nMgr.findExistingI18nItems(targetLocale, bundle, includeBundlesChildren); + List<I18nItem> i18nItems = i18nManager.findExistingI18nItems(targetLocale, bundle, includeBundlesChildren); boolean prioSortEnabled = existingBundlesPrioritySortSwitch.isSelected(0); - i18nMgr.sortI18nItems(i18nItems, prioSortEnabled, prioSortEnabled); + i18nManager.sortI18nItems(i18nItems, prioSortEnabled, prioSortEnabled); deactivateAndDisposeChildCrumbController(); // first the list controller TranslationToolI18nItemListCrumbController i18nItemlistCrumbCtr = new TranslationToolI18nItemListCrumbController(ureq, @@ -520,10 +524,10 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { String bundle = allBundlesSelection.getSelectedKey(); if (bundle.equals(ALL_BUNDLES_IDENTIFYER)) bundle = null; boolean includeBundlesChildren = allBundlesIncludeBundlesChildrenSwitch.isSelected(0); - List<I18nItem> i18nItems = i18nMgr.findExistingAndMissingI18nItems(referenceLocale, targetLocale, bundle, + List<I18nItem> i18nItems = i18nManager.findExistingAndMissingI18nItems(referenceLocale, targetLocale, bundle, includeBundlesChildren); boolean prioSortEnabled = allBundlesPrioritySortSwitch.isSelected(0); - i18nMgr.sortI18nItems(i18nItems, prioSortEnabled, prioSortEnabled); + i18nManager.sortI18nItems(i18nItems, prioSortEnabled, prioSortEnabled); deactivateAndDisposeChildCrumbController(); // first the list controller TranslationToolI18nItemListCrumbController i18nItemlistCrumbCtr = new TranslationToolI18nItemListCrumbController(ureq, @@ -545,14 +549,14 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { Locale searchLocale = (searchReferenceTargetSelection.getSelectedKey().equals(KEYS_REFERENCE) ? referenceLocale : targetLocale); if (searchKeyValueSelection.getSelectedKey().equals(KEYS_KEY)) { // use the fallback locale because it won't find the key if not already translated in the searchLocale - i18nItems = i18nMgr.findI18nItemsByKeySearch(searchString, I18nModule.getFallbackLocale(), targetLocale, bundle, + i18nItems = i18nManager.findI18nItemsByKeySearch(searchString, i18nModule.getFallbackLocale(), targetLocale, bundle, includeBundlesChildren); } else { - i18nItems = i18nMgr.findI18nItemsByValueSearch(searchString, searchLocale, targetLocale, bundle, + i18nItems = i18nManager.findI18nItemsByValueSearch(searchString, searchLocale, targetLocale, bundle, includeBundlesChildren); } boolean prioSortEnabled = searchBundlesPrioritySortSwitch.isSelected(0); - I18nManager.getInstance().sortI18nItems(i18nItems, prioSortEnabled, prioSortEnabled); + i18nManager.sortI18nItems(i18nItems, prioSortEnabled, prioSortEnabled); deactivateAndDisposeChildCrumbController(); // first the list controller TranslationToolI18nItemListCrumbController i18nItemlistCrumbCtr = new TranslationToolI18nItemListCrumbController(ureq, @@ -607,28 +611,28 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { } else if (source == missingBundlesPrioritySortSwitch) { boolean enabled = missingBundlesPrioritySortSwitch.isSelected(0); - List<String> bundleNames = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> bundleNames = i18nModule.getBundleNamesContainingI18nFiles(); String[] bundlesKeys = buildBundleArrayKeys(bundleNames, enabled); String[] bundlesValues = buildBundleArrayValues(bundleNames, enabled); missingBundlesSelection.setKeysAndValues(bundlesKeys, bundlesValues, null); } else if (source == existingBundlesPrioritySortSwitch) { boolean enabled = existingBundlesPrioritySortSwitch.isSelected(0); - List<String> bundleNames = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> bundleNames = i18nModule.getBundleNamesContainingI18nFiles(); String[] bundlesKeys = buildBundleArrayKeys(bundleNames, enabled); String[] bundlesValues = buildBundleArrayValues(bundleNames, enabled); existingBundlesSelection.setKeysAndValues(bundlesKeys, bundlesValues, null); } else if (source == allBundlesPrioritySortSwitch) { boolean enabled = allBundlesPrioritySortSwitch.isSelected(0); - List<String> bundleNames = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> bundleNames = i18nModule.getBundleNamesContainingI18nFiles(); String[] bundlesKeys = buildBundleArrayKeys(bundleNames, enabled); String[] bundlesValues = buildBundleArrayValues(bundleNames, enabled); allBundlesSelection.setKeysAndValues(bundlesKeys, bundlesValues, null); } else if (source == searchBundlesPrioritySortSwitch) { boolean enabled = searchBundlesPrioritySortSwitch.isSelected(0); - List<String> bundleNames = I18nModule.getBundleNamesContainingI18nFiles(); + List<String> bundleNames = i18nModule.getBundleNamesContainingI18nFiles(); String[] bundlesKeys = buildBundleArrayKeys(bundleNames, enabled); String[] bundlesValues = buildBundleArrayValues(bundleNames, enabled); searchBundlesSelection.setKeysAndValues(bundlesKeys, bundlesValues, null); @@ -675,7 +679,7 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { for (String bundle : bundleNames) { copy.add(bundle); } - I18nManager.getInstance().sortBundles(copy, true); + i18nManager.sortBundles(copy, true); bundlesListKeys.addAll(copy); } else { bundlesListKeys.addAll(bundleNames); @@ -700,7 +704,7 @@ class TranslationToolStartCrumbController extends CrumbFormBasicController { for (String bundle : bundleNames) { copy.add(bundle); } - I18nManager.getInstance().sortBundles(copy, true); + i18nManager.sortBundles(copy, true); bundlesListValues.addAll(copy); } else { bundlesListValues.addAll(bundleNames); diff --git a/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java b/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java index 5f15ce49b91734a6eee4e8ea7880f3027b3b7035..a4c8b902e88dfcd297c6b2d506f8156864dc95b7 100644 --- a/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java +++ b/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java @@ -1454,11 +1454,18 @@ public class MailManagerImpl implements MailManager, InitializingBean { if (attachments != null && !attachments.isEmpty()) { // with attachment use multipart message - Multipart multipart = new MimeMultipart(); + Multipart multipart = new MimeMultipart("mixed"); // 1) add body part - BodyPart messageBodyPart = new MimeBodyPart(); - messageBodyPart.setText(body); - multipart.addBodyPart(messageBodyPart); + if(StringHelper.isHtml(body)) { + Multipart alternativePart = createMultipartAlternative(body); + MimeBodyPart wrap = new MimeBodyPart(); + wrap.setContent(alternativePart); + multipart.addBodyPart(wrap); + } else { + BodyPart messageBodyPart = new MimeBodyPart(); + messageBodyPart.setText(body); + multipart.addBodyPart(messageBodyPart); + } // 2) add attachments for (DBMailAttachment attachment : attachments) { // abort if attachment does not exist @@ -1468,7 +1475,7 @@ public class MailManagerImpl implements MailManager, InitializingBean { + (attachment == null ? null : attachment.getName()), null); return msg; } - messageBodyPart = new MimeBodyPart(); + BodyPart messageBodyPart = new MimeBodyPart(); VFSLeaf data = getAttachmentDatas(attachment); DataSource source = new VFSDataSource(attachment.getName(), attachment.getMimetype(), data); @@ -1480,7 +1487,11 @@ public class MailManagerImpl implements MailManager, InitializingBean { msg.setContent(multipart); } else { // without attachment everything is easy, just set as text - msg.setText(body, "utf-8"); + if(StringHelper.isHtml(body)) { + msg.setContent(createMultipartAlternative(body)); + } else { + msg.setText(body, "utf-8"); + } } msg.setSentDate(new Date()); msg.saveChanges(); diff --git a/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java b/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java index 031897abccbb0ae6a446254eb124b06d83bb2e16..655aef4d8a164354dba3abf4eb09591b9ae85386 100644 --- a/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java +++ b/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java @@ -121,6 +121,11 @@ public class EMailIdentity implements Identity { return data.get(UserConstants.EMAIL); } + @Override + public String getInstitutionalEmail() { + return data.get(UserConstants.INSTITUTIONALEMAIL); + } + @Override public Date getLastModified() { return null; diff --git a/src/main/java/org/olat/core/util/openxml/HTMLToOpenXMLHandler.java b/src/main/java/org/olat/core/util/openxml/HTMLToOpenXMLHandler.java index 09efd2ee2f5f2b1ad9b40b0225f8798519ccf4dc..3159fe5037659f2da045698835103cb3fd766e9d 100644 --- a/src/main/java/org/olat/core/util/openxml/HTMLToOpenXMLHandler.java +++ b/src/main/java/org/olat/core/util/openxml/HTMLToOpenXMLHandler.java @@ -167,6 +167,17 @@ public class HTMLToOpenXMLHandler extends DefaultHandler { return null; } + protected void trimTextBuffer() { + if(textBuffer == null) return; + + String text = textBuffer.toString().trim(); + if(text.length() == 0) { + textBuffer = null; + } else { + textBuffer = new StringBuilder(text); + } + } + protected void flushText() { if(textBuffer == null) return; @@ -403,7 +414,7 @@ public class HTMLToOpenXMLHandler extends DefaultHandler { @Override public void startElement(String uri, String localName, String qName, Attributes attributes) { String tag = localName.toLowerCase(); - if("p".equalsIgnoreCase(tag)) { + if("p".equals(tag)) { getCurrentParagraph(pNeedNewParagraph); } else if("span".equalsIgnoreCase(tag)) { flushText(); @@ -419,18 +430,18 @@ public class HTMLToOpenXMLHandler extends DefaultHandler { styleStack.add(new StyleStatus(tag, styles)); } else if("br".equals(tag)) { closeParagraph(); - } else if("em".equalsIgnoreCase(tag)) { + } else if("em".equals(tag)) { flushText(); Style[] styles = setTextPreferences(Style.italic); styleStack.add(new StyleStatus(tag, styles)); - } else if("strong".equalsIgnoreCase(tag)) { + } else if("strong".equals(tag)) { flushText(); Style[] styles = setTextPreferences(Style.bold); styleStack.add(new StyleStatus(tag, styles)); } else if("img".equals(tag)) { String path = attributes.getValue("src"); setImage(path); - } else if("table".equalsIgnoreCase(tag)) { + } else if("table".equals(tag)) { startTable(); } else if("tr".equals(tag)) { startCurrentTableRow(); @@ -456,9 +467,11 @@ public class HTMLToOpenXMLHandler extends DefaultHandler { appendParagraph(new Spacing(120, 0)); pNeedNewParagraph = false; } else { + getCurrentParagraph(pNeedNewParagraph); styleStack.add(new StyleStatus(tag, new Style[0])); } } else { + getCurrentParagraph(pNeedNewParagraph); styleStack.add(new StyleStatus(tag, new Style[0])); } } @@ -506,6 +519,7 @@ public class HTMLToOpenXMLHandler extends DefaultHandler { popStyle(tag); } else if("div".equals(tag)) { popStyle(tag); + closeParagraph(); } } diff --git a/src/main/java/org/olat/core/util/openxml/OpenXMLCellType.java b/src/main/java/org/olat/core/util/openxml/OpenXMLCellType.java new file mode 100644 index 0000000000000000000000000000000000000000..b560cf026d09d61cb31f8420c72bb33aea6c21d8 --- /dev/null +++ b/src/main/java/org/olat/core/util/openxml/OpenXMLCellType.java @@ -0,0 +1,32 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.util.openxml; + +/** + * + * Initial date: 10 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public enum OpenXMLCellType { + number, + sharedString, + date +} diff --git a/src/main/java/org/olat/core/util/openxml/OpenXMLDocument.java b/src/main/java/org/olat/core/util/openxml/OpenXMLDocument.java index 1bcc4bb516f247fdff710ce366d23455ec8dacd0..dfaabdda7ff9adcd8cfc3fb8f84e0a962ce8af91 100644 --- a/src/main/java/org/olat/core/util/openxml/OpenXMLDocument.java +++ b/src/main/java/org/olat/core/util/openxml/OpenXMLDocument.java @@ -268,7 +268,7 @@ public class OpenXMLDocument { if(StringHelper.containsNonWhitespace(documentHeader)) { try(InputStream headerIn = OpenXMLDocument.class.getResourceAsStream("_resources/header.xml")) { - String headerTemplate = IOUtils.toString(headerIn); + String headerTemplate = IOUtils.toString(headerIn, "UTF-8"); String header = headerTemplate.replace("[oodocumentitlte]", documentHeader); String headerId = generateId(); diff --git a/src/main/java/org/olat/core/util/openxml/OpenXMLWorkbookStyles.java b/src/main/java/org/olat/core/util/openxml/OpenXMLWorkbookStyles.java index 3d08008f54c59df95fc67b4335b316680e84bfd7..4885c5906b5ac7e7b64ff7f325e917f425811589 100644 --- a/src/main/java/org/olat/core/util/openxml/OpenXMLWorkbookStyles.java +++ b/src/main/java/org/olat/core/util/openxml/OpenXMLWorkbookStyles.java @@ -35,9 +35,11 @@ import org.olat.core.util.openxml.workbookstyle.Font.FontStyle; * */ public class OpenXMLWorkbookStyles { - + + public static final String PERCENT_FORMAT = "10"; public static final String DATE_FORMAT = "14"; public static final String TIME_FORMAT = "21"; + public static final String DATE_TIME_FORMAT = "22"; private List<Font> fonts = new ArrayList<>(); private List<Fill> fills = new ArrayList<>(); @@ -56,8 +58,10 @@ public class OpenXMLWorkbookStyles { private final CellStyle borderRightStyle; private final CellStyle dateStyle; private final CellStyle durationStyle; + private final CellStyle dateTimeStyle; private final CellStyle headerStyle; private final CellStyle correctStyle; + private final CellStyle percentStyle; public OpenXMLWorkbookStyles() { standardFont = new Font(fonts.size(), "12", "1", "Calibri", "2", "minor", FontStyle.none); @@ -83,12 +87,16 @@ public class OpenXMLWorkbookStyles { cellXfs.add(borderRightStyle); dateStyle = new CellStyle(cellXfs.size(), DATE_FORMAT, standardFont, noneFile, noBorder, null, "1"); cellXfs.add(dateStyle); + dateTimeStyle = new CellStyle(cellXfs.size(), DATE_TIME_FORMAT, standardFont, noneFile, noBorder, null, "1"); + cellXfs.add(dateTimeStyle); durationStyle = new CellStyle(cellXfs.size(), TIME_FORMAT, standardFont, noneFile, borderRight, null, "1"); cellXfs.add(durationStyle); headerStyle = new CellStyle(cellXfs.size(), "0", boldFont, noneFile, noBorder, null, null); cellXfs.add(headerStyle); correctStyle = new CellStyle(cellXfs.size(), "0", boldFont, correctFill, noBorder, null, null); cellXfs.add(correctStyle); + percentStyle = new CellStyle(cellXfs.size(), PERCENT_FORMAT, standardFont, noneFile, borderRight, null, "1"); + cellXfs.add(percentStyle); } public CellStyle getBorderRightStyle() { @@ -107,6 +115,10 @@ public class OpenXMLWorkbookStyles { return dateStyle; } + public CellStyle getDateTimeStyle() { + return dateTimeStyle; + } + public CellStyle getDurationStyle() { return dateStyle; } @@ -119,6 +131,10 @@ public class OpenXMLWorkbookStyles { return correctStyle; } + public CellStyle getPercentStyle() { + return percentStyle; + } + public List<Font> getFonts() { return fonts; } diff --git a/src/main/java/org/olat/core/util/openxml/OpenXMLWorksheet.java b/src/main/java/org/olat/core/util/openxml/OpenXMLWorksheet.java index 86c512f55d7d3e31c7ea07ea2c83b6dd52a0c04c..298c27270300a505625fbf811d1976a9672eb716 100644 --- a/src/main/java/org/olat/core/util/openxml/OpenXMLWorksheet.java +++ b/src/main/java/org/olat/core/util/openxml/OpenXMLWorksheet.java @@ -22,7 +22,9 @@ package org.olat.core.util.openxml; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.zip.ZipOutputStream; import javax.xml.stream.XMLStreamException; @@ -61,6 +63,7 @@ public class OpenXMLWorksheet { private Row row; private int rowPosition = 0; + private Map<Integer,Integer> columnsWidth = new HashMap<>(); public OpenXMLWorksheet(String id, OpenXMLWorkbook workbook, ZipOutputStream zout) { this.id = id; @@ -71,7 +74,7 @@ public class OpenXMLWorksheet { public String getId() { return id; } - + public int getHeaderRows() { return headerRows; } @@ -80,6 +83,9 @@ public class OpenXMLWorksheet { this.headerRows = headerRows; } + public void setColumnWidth(int pos, int width) { + columnsWidth.put(pos, width); + } public Row newRow() { if(!opened) { @@ -126,12 +132,12 @@ public class OpenXMLWorksheet { if(style != null && style.getIndex() > 0) { writer.writeAttribute("s", Integer.toString(style.getIndex())); } - if(cell.getType() == CellType.sharedString) { + if(cell.getType() == OpenXMLCellType.sharedString) { writer.writeAttribute("t", "s"); } writer.writeStartElement("v"); - if(cell.getType() == CellType.date) { + if(cell.getType() == OpenXMLCellType.date) { cal.setTime((Date)cell.getValue()); double val = internalGetExcelDate(cal, false); writer.writeCharacters(Double.toString(val)); @@ -215,6 +221,21 @@ public class OpenXMLWorksheet { writer.writeAttribute("defaultRowHeight", "15"); writer.writeAttribute("x14ac:dyDescent", "0"); writer.writeEndElement(); + + if(columnsWidth != null && columnsWidth.size() > 0) { + writer.writeStartElement("cols"); + for(Map.Entry<Integer, Integer> columnWidth:columnsWidth.entrySet()) { + Integer pos = columnWidth.getKey(); + Integer width = columnWidth.getValue(); + writer.writeStartElement("col"); + writer.writeAttribute("min", pos.toString()); + writer.writeAttribute("max", pos.toString()); + writer.writeAttribute("width", width.toString()); + writer.writeAttribute("customWidth", "1"); + writer.writeEndElement(); + } + writer.writeEndElement(); + } writer.writeStartElement("sheetData"); } catch(XMLStreamException e) { @@ -352,7 +373,7 @@ public class OpenXMLWorksheet { public Cell addCell(int column, String value, CellStyle style) { Cell cell = getOrCreateCell(column); cell.setStyle(style); - cell.setType(CellType.sharedString); + cell.setType(OpenXMLCellType.sharedString); if(value != null) { int sharedIndex = workbook.getSharedStrings().add(value); if(sharedIndex >= 0) { @@ -365,7 +386,22 @@ public class OpenXMLWorksheet { public Cell addCell(int column, Number value, CellStyle style) { Cell cell = getOrCreateCell(column); cell.setStyle(style); - cell.setType(CellType.number); + cell.setType(OpenXMLCellType.number); + cell.setValue(value); + return cell; + } + + /** + * The accepted types are number or percent + * @param column The index of the column + * @param value The value + * @param type The type, number or percent + * @return + */ + public Cell addCell(int column, Number value, CellStyle style, OpenXMLCellType type) { + Cell cell = getOrCreateCell(column); + cell.setStyle(style); + cell.setType(type); cell.setValue(value); return cell; } @@ -380,7 +416,7 @@ public class OpenXMLWorksheet { public Cell addCell(int column, Date value, CellStyle style) { Cell cell = getOrCreateCell(column); cell.setStyle(style); - cell.setType(CellType.date); + cell.setType(OpenXMLCellType.date); cell.setValue(value); return cell; } @@ -409,14 +445,14 @@ public class OpenXMLWorksheet { public static class Cell { private Object value; - private CellType type; + private OpenXMLCellType type; private CellStyle style; public Cell() { // } - public Cell(Object value, CellType type, CellStyle style) { + public Cell(Object value, OpenXMLCellType type, CellStyle style) { this.value = value; this.type = type; this.style = style; @@ -430,11 +466,11 @@ public class OpenXMLWorksheet { this.value = value; } - public CellType getType() { + public OpenXMLCellType getType() { return type; } - public void setType(CellType type) { + public void setType(OpenXMLCellType type) { this.type = type; } @@ -446,10 +482,4 @@ public class OpenXMLWorksheet { this.style = style; } } - - public enum CellType { - number, - sharedString, - date - } } diff --git a/src/main/java/org/olat/core/util/pdf/PdfDocument.java b/src/main/java/org/olat/core/util/pdf/PdfDocument.java index 359f57084f961b0b9d914aa24bbada924a839943..ab6309aa97f99bd1f3c767151ae65503bf98a4db 100644 --- a/src/main/java/org/olat/core/util/pdf/PdfDocument.java +++ b/src/main/java/org/olat/core/util/pdf/PdfDocument.java @@ -79,12 +79,20 @@ public class PdfDocument { } public PDPage addPage() throws IOException { + return addPage(PDPage.PAGE_SIZE_A4); + } + + public PDPage addPageLandscape() throws IOException { + return addPage(new PDRectangle(PDPage.PAGE_SIZE_A4.getHeight(), PDPage.PAGE_SIZE_A4.getWidth())); + } + + public PDPage addPage(PDRectangle size) throws IOException { if(currentContentStream != null) { currentContentStream.close(); } - PDPage page = new PDPage(PDPage.PAGE_SIZE_A4); - document.addPage(page); + PDPage page = new PDPage(size); + document.addPage(page); currentPage = page; currentContentStream = new PDPageContentStream(document, currentPage); diff --git a/src/main/java/org/olat/core/util/vfs/QuotaManager.java b/src/main/java/org/olat/core/util/vfs/QuotaManager.java index f1a79eb6aafb36fb70c536553ecb718b0f9c9f8a..46e429c3e05e100c397a687c0a8b7c55e51b0872 100644 --- a/src/main/java/org/olat/core/util/vfs/QuotaManager.java +++ b/src/main/java/org/olat/core/util/vfs/QuotaManager.java @@ -158,17 +158,15 @@ public abstract class QuotaManager { * The controller must fire the following events: * <ul> * <li>Event.CANCELLED_EVENT</li> - * <li>Event.CHANGED_EVENT</li> * </ul> * @param ureq * @param wControl * @param relPath - * @param modalMode * @return */ - public abstract Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode); + public abstract Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath); - public abstract Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode); + public abstract Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath); /** * Check if a user has the rights to launch the quota editor tool diff --git a/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java b/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java index 26e2b2f86c17463e1e39a59ab8845688af148fc9..7b6670b6bfa774f0a8091bd205e51cd6893e6907 100644 --- a/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java +++ b/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java @@ -30,8 +30,6 @@ import java.io.InputStream; import javax.servlet.http.HttpServletResponse; -import org.olat.core.CoreSpringFactory; -import org.olat.core.commons.modules.bc.FilesInfoMBean; import org.olat.core.gui.media.MediaResource; import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; @@ -45,11 +43,9 @@ public class VFSMediaResource implements MediaResource { private String encoding; boolean unknownMimeType = false; private boolean downloadable = false; - private FilesInfoMBean filesInfoMBean; public VFSMediaResource(VFSLeaf vfsLeaf) { this.vfsLeaf = vfsLeaf; - this.filesInfoMBean = (FilesInfoMBean) CoreSpringFactory.getBean(FilesInfoMBean.class.getCanonicalName()); } @Override @@ -96,7 +92,6 @@ public class VFSMediaResource implements MediaResource { @Override public InputStream getInputStream() { - filesInfoMBean.logDownload(getSize()); return vfsLeaf.getInputStream(); } @@ -112,7 +107,7 @@ public class VFSMediaResource implements MediaResource { @Override public void prepare(HttpServletResponse hres) { String filename = StringHelper.urlEncodeUTF8(vfsLeaf.getName()); - if (unknownMimeType) { + if (unknownMimeType || downloadable) { hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + filename); } else { hres.setHeader("Content-Disposition", "filename*=UTF-8''" + filename); @@ -135,6 +130,20 @@ public class VFSMediaResource implements MediaResource { this.encoding = encoding; } + /** + * Set to true to force the browser to download the resource. This is done by + * a) set the content-disposition to attachment + * b) set the mime-type to some non-existing mime-type for browser-executable, + * xss-relevant resource such as html files. Since the browser does not + * understand the mime-type, the file gets downloaded instead of executed. + * + * NOTE: make sure when writing the link to properly set the target or + * download attribute depending on the mime-type or the downloadable nature + * of the file! + * + * @param downloadable true: force browser to download; false: let browser + * decide, might render inline in browser window + */ public void setDownloadable(boolean downloadable) { this.downloadable = downloadable; } diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java index 81dd4854444f24629e6ac0bb657e33d722ba5a8d..8be9355f24c0444bfaf03c030168e752085986cf 100644 --- a/src/main/java/org/olat/course/CourseFactory.java +++ b/src/main/java/org/olat/course/CourseFactory.java @@ -46,6 +46,7 @@ import org.apache.commons.io.IOUtils; import org.olat.admin.quota.QuotaConstants; import org.olat.commons.calendar.CalendarManager; import org.olat.commons.calendar.CalendarNotificationManager; +import org.olat.commons.calendar.manager.ImportToCalendarManager; import org.olat.commons.calendar.ui.components.KalendarRenderWrapper; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; @@ -376,8 +377,9 @@ public class CourseFactory { CoursePropertyManager propertyManager = PersistingCoursePropertyManager.getInstance(res); propertyManager.deleteAllCourseProperties(); // delete course calendar - CalendarManager calManager = CoreSpringFactory.getImpl(CalendarManager.class); - calManager.deleteCourseCalendar(res); + CoreSpringFactory.getImpl(ImportToCalendarManager.class).deleteCourseImportedCalendars(res); + CoreSpringFactory.getImpl(CalendarManager.class).deleteCourseCalendar(res); + // delete IM messages CoreSpringFactory.getImpl(InstantMessagingService.class).deleteMessages(res); //delete tasks diff --git a/src/main/java/org/olat/course/_spring/courseContext.xml b/src/main/java/org/olat/course/_spring/courseContext.xml index 1962ce090859bc526d0d42727de34688c58a64fe..c76f5a488258f784f0b9b09ee6e0ed750d2237da 100644 --- a/src/main/java/org/olat/course/_spring/courseContext.xml +++ b/src/main/java/org/olat/course/_spring/courseContext.xml @@ -84,7 +84,7 @@ <property name="className" value="org.olat.course.assessment.AssessableCourseNodeAdminController"/> </bean> </property> - <property name="navigationKey" value="certificates" /> + <property name="navigationKey" value="course" /> <property name="i18nActionKey" value="admin.menu.title"/> <property name="i18nDescriptionKey" value="admin.menu.title.alt"/> <property name="translationPackage" value="org.olat.course.assessment"/> diff --git a/src/main/java/org/olat/course/assessment/AssessmentHelper.java b/src/main/java/org/olat/course/assessment/AssessmentHelper.java index 6ec0b0f8d96cfc9b1600eb2b8c95c99a614fa8ed..2331d773c3147eb2356651c2f071a6c1d17f3c81 100644 --- a/src/main/java/org/olat/course/assessment/AssessmentHelper.java +++ b/src/main/java/org/olat/course/assessment/AssessmentHelper.java @@ -48,6 +48,7 @@ import org.olat.core.util.tree.TreeVisitor; import org.olat.core.util.tree.Visitor; import org.olat.course.ICourse; import org.olat.course.assessment.model.AssessmentNodeData; +import org.olat.course.assessment.model.AssessmentNodesLastModified; import org.olat.course.nodes.AssessableCourseNode; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.CourseNodeConfiguration; @@ -93,6 +94,8 @@ public class AssessmentHelper { public static final String KEY_TOTAL_NODES = "totalNodes"; public static final String KEY_ATTEMPTED_NODES = "attemptedNodes"; public static final String KEY_PASSED_NODES = "attemptedNodes"; + public static final String KEY_LAST_USER_MODIFIED = "lastUserModified"; + public static final String KEY_LAST_COACH_MODIFIED = "lastCoachModified"; /** * String to symbolize 'not available' or 'not assigned' in assessments @@ -432,12 +435,13 @@ public class AssessmentHelper { * @return list of object arrays or null if empty */ public static List<AssessmentNodeData> getAssessmentNodeDataList(UserCourseEnvironment userCourseEnv, + AssessmentNodesLastModified lastModifications, boolean followUserVisibility, boolean discardEmptyNodes, boolean discardComments) { List<AssessmentNodeData> data = new ArrayList<AssessmentNodeData>(50); ScoreAccounting scoreAccounting = userCourseEnv.getScoreAccounting(); scoreAccounting.evaluateAll(); getAssessmentNodeDataList(0, userCourseEnv.getCourseEnvironment().getRunStructure().getRootNode(), - scoreAccounting, userCourseEnv, followUserVisibility, discardEmptyNodes, discardComments, data); + scoreAccounting, userCourseEnv, followUserVisibility, discardEmptyNodes, discardComments, data, lastModifications); return data; } @@ -455,13 +459,14 @@ public class AssessmentHelper { boolean followUserVisibility, boolean discardEmptyNodes, boolean discardComments) { List<AssessmentNodeData> data = new ArrayList<AssessmentNodeData>(50); getAssessmentNodeDataList(0, userCourseEnv.getCourseEnvironment().getRunStructure().getRootNode(), - evaluatedScoreAccounting, userCourseEnv, followUserVisibility, discardEmptyNodes, discardComments, data); + evaluatedScoreAccounting, userCourseEnv, followUserVisibility, discardEmptyNodes, discardComments, data, null); return data; } public static int getAssessmentNodeDataList(int recursionLevel, CourseNode courseNode, ScoreAccounting scoreAccounting, - UserCourseEnvironment userCourseEnv, boolean followUserVisibility, boolean discardEmptyNodes, boolean discardComments, List<AssessmentNodeData> data) { + UserCourseEnvironment userCourseEnv, boolean followUserVisibility, boolean discardEmptyNodes, boolean discardComments, + List<AssessmentNodeData> data, AssessmentNodesLastModified lastModifications) { // 1) Get list of children data using recursion of this method AssessmentNodeData assessmentNodeData = new AssessmentNodeData(recursionLevel, courseNode); data.add(assessmentNodeData); @@ -470,7 +475,7 @@ public class AssessmentHelper { for (int i = 0; i < courseNode.getChildCount(); i++) { CourseNode child = (CourseNode) courseNode.getChildAt(i); numOfChildren += getAssessmentNodeDataList(recursionLevel + 1, child, scoreAccounting, - userCourseEnv, followUserVisibility, discardEmptyNodes, discardComments, data); + userCourseEnv, followUserVisibility, discardEmptyNodes, discardComments, data, lastModifications); } // 2) Get data of this node only if @@ -490,6 +495,14 @@ public class AssessmentHelper { assessmentNodeData.setNumOfAssessmentDocs(scoreEvaluation.getNumOfAssessmentDocs()); } assessmentNodeData.setUserVisibility(scoreEvaluation.getUserVisible()); + assessmentNodeData.setLastModified(scoreEvaluation.getLastModified()); + assessmentNodeData.setLastUserModified(scoreEvaluation.getLastUserModified()); + assessmentNodeData.setLastCoachModified(scoreEvaluation.getLastCoachModified()); + if(lastModifications != null) { + lastModifications.addLastModified(scoreEvaluation.getLastModified()); + lastModifications.addLastUserModified(scoreEvaluation.getLastUserModified()); + lastModifications.addLastCoachModified(scoreEvaluation.getLastCoachModified()); + } if(!followUserVisibility || scoreEvaluation.getUserVisible() == null || scoreEvaluation.getUserVisible().booleanValue()) { // details diff --git a/src/main/java/org/olat/course/assessment/AssessmentManager.java b/src/main/java/org/olat/course/assessment/AssessmentManager.java index 629abda4af4590d1415e93bec7ffd271760b17fc..167b56f6adef5d4f103d09a4ef903eb9f6b2d70a 100644 --- a/src/main/java/org/olat/course/assessment/AssessmentManager.java +++ b/src/main/java/org/olat/course/assessment/AssessmentManager.java @@ -38,6 +38,7 @@ import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; /** @@ -64,7 +65,17 @@ public interface AssessmentManager { * @param assessedIdentity The user whose score is changed * @param attempts The new attempts */ - public void saveNodeAttempts(CourseNode courseNode, Identity identity, Identity assessedIdentity, Integer attempts); + public void saveNodeAttempts(CourseNode courseNode, Identity identity, Identity assessedIdentity, Integer attempts, Role by); + + /** + * Change the last modification dates. + * + * @param courseNode The course node + * @param identity The identity which does the action + * @param assessedIdentity The assessed identity + * @param by The role of the identity which does the action. + */ + public void updateLastModifications(CourseNode courseNode, Identity assessedIdentity, UserCourseEnvironment userCourseEnvironment, Role by); /** * Save an assessment comment for this node for a user. If there is already a comment property available, @@ -111,7 +122,7 @@ public interface AssessmentManager { * @param courseNode * @param identity */ - public void incrementNodeAttempts(CourseNode courseNode, Identity identity, UserCourseEnvironment userCourseEnvironment); + public void incrementNodeAttempts(CourseNode courseNode, Identity identity, UserCourseEnvironment userCourseEnvironment, Role by); /** * Increment the users attempts for this course node, but without logging (aimed at background job). @@ -212,7 +223,8 @@ public interface AssessmentManager { */ public void saveScoreEvaluation(AssessableCourseNode courseNode, Identity identity, Identity assessedIdentity, - ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, boolean incrementUserAttempts); + ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, + boolean incrementUserAttempts, Role by); /** * Provides an OLATResourceable for locking (of score/passed etc.) purposes (if doInSync is called on score/passed data) diff --git a/src/main/java/org/olat/course/assessment/EfficiencyStatement.java b/src/main/java/org/olat/course/assessment/EfficiencyStatement.java index 229030fd83d57b7e6b146a26e671ab1100d4ef7a..7003844f7a8e26fd340e758cd58937a4168de069 100644 --- a/src/main/java/org/olat/course/assessment/EfficiencyStatement.java +++ b/src/main/java/org/olat/course/assessment/EfficiencyStatement.java @@ -45,34 +45,62 @@ public class EfficiencyStatement { private Long courseRepoEntryKey; private String displayableUserInfo; private long lastUpdated; + private long lastUserModified; + private long lastCoachModified; public long getLastUpdated() { return lastUpdated; } + public void setLastUpdated(long lastUpdated) { this.lastUpdated = lastUpdated; } + + public long getLastUserModified() { + return lastUserModified; + } + + public void setLastUserModified(long lastUserModified) { + this.lastUserModified = lastUserModified; + } + + public long getLastCoachModified() { + return lastCoachModified; + } + + public void setLastCoachModified(long lastCoachModified) { + this.lastCoachModified = lastCoachModified; + } + public List<Map<String,Object>> getAssessmentNodes() { return assessmentNodes; } + public void setAssessmentNodes(List<Map<String,Object>> assessmentNodes) { this.assessmentNodes = assessmentNodes; } + public Long getCourseRepoEntryKey() { return courseRepoEntryKey; } + public void setCourseRepoEntryKey(Long courseRepoEntryKey) { this.courseRepoEntryKey = courseRepoEntryKey; } + public String getCourseTitle() { return courseTitle; } + public void setCourseTitle(String courseTitle) { this.courseTitle = courseTitle; } + public String getDisplayableUserInfo() { return displayableUserInfo; } + + public void setDisplayableUserInfo(String displayableUserInfo) { this.displayableUserInfo = displayableUserInfo; } diff --git a/src/main/java/org/olat/course/assessment/UserEfficiencyStatement.java b/src/main/java/org/olat/course/assessment/UserEfficiencyStatement.java index 2a9a9f53cab2918bffeb7b0d484d0f989e8b3ebc..226ba10359ce0fddacc45e3f8b96d80d18a7cb3f 100644 --- a/src/main/java/org/olat/course/assessment/UserEfficiencyStatement.java +++ b/src/main/java/org/olat/course/assessment/UserEfficiencyStatement.java @@ -41,6 +41,10 @@ public interface UserEfficiencyStatement { public Date getLastModified(); + public Date getLastUserModified(); + + public Date getLastCoachModified(); + public Date getCreationDate(); public Long getCourseRepoKey(); diff --git a/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_de.properties index 547238d3953c8ec999a681c123897807a6377b44..8f0cfd61c5ac2a4a3f9048e1204483411643f9cc 100644 --- a/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_de.properties @@ -152,6 +152,8 @@ table.header.status=Status table.header.type=Typ table.header.initialLaunchDate=Erster Kursstart table.header.lastScoreDate=Letzte Aktualisierung +table.header.lastUserModificationDate=Letzte Benutzer Aktualisierung +table.header.lastCoachModificationDate=Letzte Betreuer Aktualisierung notifications.title=Kurs "{0}" notifications.header=Neue Testresultate in Kurs "{0}" notifications.entry={3}: "{0}" ausgef\u00FChrt von {1} mit {2} Punkten diff --git a/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_en.properties index c1491559dc5d36d611115e0da4b5e160a9416014..9059ab4b427e4cb2d75cdd52b866358852e65a60 100644 --- a/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_en.properties @@ -1,13 +1,13 @@ -#Wed Dec 17 15:43:14 CET 2014 +#Fri Aug 18 08:56:34 CEST 2017 action.choose=Select -artefact.title=Evidence of achievement for course {0} -assessment.testresults.finished=<font color\="green">Assessment completed</font> -assessment.testresults.open=<font color\="orange">Assessment pending</font> +admin.assessable.coursenode=Settings for assessable course elements +admin.info.box=Show info box on start admin.menu.title=Course admin.menu.title.alt=$\:admin.menu.title settings -admin.info.box=Show info box on start admin.user.changelog=Show assessment changelog to user -admin.assessable.coursenode=Settings for assessable course elements +artefact.title=Evidence of achievement for course {0} +assessment.testresults.finished=<font color\="green">Assessment completed</font> +assessment.testresults.open=<font color\="orange">Assessment pending</font> cmd.all.users=Show all users cmd.filterCourseNodes=Show assessable course elements cmd.filterGroups=Supervised groups with access to selected course element @@ -84,7 +84,6 @@ group=Group\: group.link=Open group groupchoose.nogroups=No groups found. Either there are no groups in this course or you have no coaching rights. groupchoose.title=Selection of course group - home.link=Visiting card identityoverview.title=Assessment overview index.intro=By means of this tool you can assess your course participants. You can see test or assessment results and modify them. @@ -123,9 +122,9 @@ nodesoverview.nonodes=This course does not have any assessable course elements. notifications.entry={3}\: "{0}" taken by {1}, score\: {2} notifications.entry.attempt={2}\: "{0}" executed by {1} notifications.entry.ep=Portfolio +notifications.entry.gta=Group task notifications.entry.iqtest=Test notifications.entry.ita=Task -notifications.entry.gta=Group task notifications.entry.ms=Assessment notifications.entry.scorm=SCORM test notifications.entry.ta=Task @@ -154,10 +153,12 @@ table.header.certificate=Certificate table.header.course=Course name table.header.delete=Delete table.header.details=Details -table.header.details.ta=Task table.header.details.gta=$\:table.header.details.ta +table.header.details.ta=Task table.header.initialLaunchDate=Initial course launch +table.header.lastCoachModificationDate=Last coach update table.header.lastScoreDate=Last update +table.header.lastUserModificationDate=Last user update table.header.launchcourse=Start course table.header.max=Max. table.header.min=Min. diff --git a/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_fr.properties index 9846c994bdaa6b8030922f7304e833c57c0c355a..772ae515b79c92c4cff93b82add53e487bcfd476 100644 --- a/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Thu Jun 08 21:27:39 CEST 2017 +#Fri Aug 18 09:02:59 CEST 2017 action.choose=S\u00E9lectionner admin.assessable.coursenode=Param\u00E8tres pour les \u00E9l\u00E9ments de cours destin\u00E9s \u00E0 l'\u00E9valuation admin.info.box=Montrer les informations au d\u00E9part @@ -156,7 +156,9 @@ table.header.details=D\u00E9tails table.header.details.gta=$\:table.header.details.ta table.header.details.ta=devoir table.header.initialLaunchDate=D\u00E9but du cours +table.header.lastCoachModificationDate=Derni\u00E8re modification du coach table.header.lastScoreDate=Derni\u00E8re mise \u00E0 jour +table.header.lastUserModificationDate=Derni\u00E8re modification de l'utilisateur table.header.launchcourse=D\u00E9marrer cours table.header.max=Max. table.header.min=Min. diff --git a/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_pt_BR.properties index f78ca0074a5849aed83bbefa6cf420e266d3cbf5..959260e253a9c42e645a48ddfca62ecd0c3fff16 100644 --- a/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/assessment/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Thu Jun 22 17:01:56 CEST 2017 +#Tue Sep 05 22:51:54 CEST 2017 action.choose=Selecionar admin.assessable.coursenode=Configura\u00E7\u00F5es para elementos de curso avali\u00E1veis admin.info.box=Mostrar caixa de informa\u00E7\u00F5es no in\u00EDcio @@ -157,7 +157,9 @@ table.header.details=Detalhes table.header.details.gta=$\:table.header.details.ta table.header.details.ta=Tarefa table.header.initialLaunchDate=Lan\u00E7amento inicial de curso +table.header.lastCoachModificationDate=\u00DAltima atualiza\u00E7\u00E3o do treinador table.header.lastScoreDate=\u00DAltima atualiza\u00E7\u00E3o +table.header.lastUserModificationDate=\u00DAltima atualiza\u00E7\u00E3o de usu\u00E1rio table.header.launchcourse=Iniciar curso table.header.max=Max. table.header.min=Min. diff --git a/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml b/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml index 95cedcd772ae719f834159d590a29914d9ed1179..7d54429b1dd5c11f86031092d8bc49d7111f8d98 100644 --- a/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml +++ b/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml @@ -7,16 +7,14 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - - <context:component-scan base-package="org.olat.course.assessment" /> - <bean id="assessmentNotificationsTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="assessmentNotificationsTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="assessmentNotificationsJob" /> <property name="cronExpression" value="1 * * * * ?" /> <property name="startDelay" value="55000" /> </bean> - <bean id="assessmentNotificationsJob" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="assessmentNotificationsJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.course.assessment.manager.AssessmentModeNotificationJob" /> </bean> @@ -28,7 +26,7 @@ <property name="className" value="org.olat.course.assessment.ui.mode.AssessmentModeAdminController"/> </bean> </property> - <property name="navigationKey" value="certificates" /> + <property name="navigationKey" value="assessmentMode" /> <property name="i18nActionKey" value="admin.menu.title"/> <property name="i18nDescriptionKey" value="admin.menu.title.alt"/> <property name="translationPackage" value="org.olat.course.assessment.ui.mode"/> diff --git a/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java b/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java index 9d74870fe85315946d6a67550dce20ced3daaeac..2a43b3170378376f70f3f0bb1ed579ec06927070 100644 --- a/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java +++ b/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java @@ -119,7 +119,7 @@ public class DataStepForm extends StepFormBasicController { OlatRootFileImpl file = new OlatRootFileImpl(savedDatas.getDataBackupFile(), null); InputStream in = file.getInputStream(); try { - dataVal = IOUtils.toString(in); + dataVal = IOUtils.toString(in, "UTF-8"); } catch (IOException e) { logError("", e); } finally { @@ -238,7 +238,7 @@ public class DataStepForm extends StepFormBasicController { OutputStream out = inputFile.getOutputStream(false); try { - IOUtils.write(val, out); + IOUtils.write(val, out, "UTF-8"); datas.setDataBackupFile(inputFile.getRelPath()); } catch (IOException e) { logError("", e); diff --git a/src/main/java/org/olat/course/assessment/bulk/ValidationStepForm.java b/src/main/java/org/olat/course/assessment/bulk/ValidationStepForm.java index 2c2709c840a574ba077783ccac8f17d65745f54a..989fc82068aeb73f03d9e52723ce0d8798b26d16 100644 --- a/src/main/java/org/olat/course/assessment/bulk/ValidationStepForm.java +++ b/src/main/java/org/olat/course/assessment/bulk/ValidationStepForm.java @@ -163,8 +163,10 @@ public class ValidationStepForm extends StepFormBasicController { } for(String prop : userPropsToSearch) { - identity = userManager.findIdentityKeyWithProperty(prop, assessedId); - if(identity != null) { + List<Identity> found = userManager.findIdentitiesWithProperty(prop, assessedId); + if(found.size() > 0) { + // ignore multiple hits, just take the first one + identity = found.get(0); idToIdentityMap.put(assessedId, identity); continue; } diff --git a/src/main/java/org/olat/course/assessment/bulk/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/assessment/bulk/_i18n/LocalStrings_de.properties index 8a83ed650ac0b2e537b20fb723aeb438341228ef..bb6cc975939f92dfb16cb3c60edac4c715b9a142 100644 --- a/src/main/java/org/olat/course/assessment/bulk/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/assessment/bulk/_i18n/LocalStrings_de.properties @@ -91,7 +91,7 @@ form.step3.delimiter.tab=$org.olat.course.assessment\:form.step3.delimiter.tab new.bulk=Neue Massenbewertung starten passed.false=$org.olat.course.assessment\:passed.false passed.true=$org.olat.course.assessment\:passed.true -return.files=R\u00FCchgabedateien (ZIP Archiv mit Unterordner pro Teilnehmer) +return.files=R\u00FCckgabedateien (ZIP Archiv mit Unterordner pro Teilnehmer) return.mime=Die Datei ist kein ZIP Archiv schedule.date=Datum schedule.delayed=Sp\u00E4ter, nach Datum diff --git a/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java b/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java index 7105185a05b9d713f0827905a40266702a4fd6be..52bb19b95700db90a396bf12ba164627cf6bbc18 100644 --- a/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java +++ b/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java @@ -93,6 +93,7 @@ import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import org.olat.user.UserManager; import org.olat.util.logging.activity.LoggingResourceable; @@ -387,7 +388,7 @@ public class BulkAssessmentTask implements LongRunnable, TaskAwareRunnable, Sequ } // Update score,passed properties in db, and the user's efficiency statement - courseNode.updateUserScoreEvaluation(se, uce, coachIdentity, false); + courseNode.updateUserScoreEvaluation(se, uce, coachIdentity, false, Role.auto); } } @@ -398,7 +399,7 @@ public class BulkAssessmentTask implements LongRunnable, TaskAwareRunnable, Sequ ScoreEvaluation se = new ScoreEvaluation(oldScore, passed); // Update score,passed properties in db, and the user's efficiency statement boolean incrementAttempts = false; - courseNode.updateUserScoreEvaluation(se, uce, coachIdentity, incrementAttempts); + courseNode.updateUserScoreEvaluation(se, uce, coachIdentity, incrementAttempts, Role.auto); } boolean identityHasReturnFile = false; diff --git a/src/main/java/org/olat/course/assessment/manager/CourseAssessmentManagerImpl.java b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentManagerImpl.java index 5f6b5f31b626e45ae650ca0baa064b32b0091d49..98877b30c3e9e13ce352eaea536384f6ff344bb6 100644 --- a/src/main/java/org/olat/course/assessment/manager/CourseAssessmentManagerImpl.java +++ b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentManagerImpl.java @@ -52,6 +52,7 @@ import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.AssessmentLoggingAction; import org.olat.course.assessment.AssessmentManager; import org.olat.course.assessment.model.AssessmentNodeData; +import org.olat.course.assessment.model.AssessmentNodesLastModified; import org.olat.course.auditing.UserNodeAuditManager; import org.olat.course.certificate.CertificateTemplate; import org.olat.course.certificate.CertificatesManager; @@ -60,12 +61,14 @@ import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.nodes.AssessableCourseNode; import org.olat.course.nodes.CourseNode; import org.olat.course.run.environment.CourseEnvironment; +import org.olat.course.run.scoring.AssessmentEvaluation; import org.olat.course.run.scoring.ScoreAccounting; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentService; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.repository.RepositoryEntry; import org.olat.util.logging.activity.LoggingResourceable; @@ -138,12 +141,20 @@ public class CourseAssessmentManagerImpl implements AssessmentManager { } Float score = null; Boolean passed = null; + Date lastUserModified = null; + Date lastCoachModified = null; if(scoreEvaluation != null) { score = scoreEvaluation.getScore(); passed = scoreEvaluation.getPassed(); } + if(scoreEvaluation instanceof AssessmentEvaluation) { + AssessmentEvaluation eval = (AssessmentEvaluation)scoreEvaluation; + lastCoachModified = eval.getLastCoachModified(); + lastUserModified = eval.getLastUserModified(); + } return assessmentService - .createAssessmentEntry(assessedIdentity, null, cgm.getCourseEntry(), courseNode.getIdent(), referenceEntry, score, passed); + .createAssessmentEntry(assessedIdentity, null, cgm.getCourseEntry(), courseNode.getIdent(), referenceEntry, + score, passed, lastUserModified, lastCoachModified); } @Override @@ -152,10 +163,15 @@ public class CourseAssessmentManagerImpl implements AssessmentManager { } @Override - public void saveNodeAttempts(CourseNode courseNode, Identity identity, Identity assessedIdentity, Integer attempts) { + public void saveNodeAttempts(CourseNode courseNode, Identity identity, Identity assessedIdentity, Integer attempts, Role by) { ICourse course = CourseFactory.loadCourse(cgm.getCourseEntry()); AssessmentEntry nodeAssessment = getOrCreate(assessedIdentity, courseNode); + if(by == Role.coach) { + nodeAssessment.setLastCoachModified(new Date()); + } else if(by == Role.user) { + nodeAssessment.setLastUserModified(new Date()); + } nodeAssessment.setAttempts(attempts); assessmentService.updateAssessmentEntry(nodeAssessment); @@ -281,13 +297,21 @@ public class CourseAssessmentManagerImpl implements AssessmentManager { } @Override - public void incrementNodeAttempts(CourseNode courseNode, Identity assessedIdentity, UserCourseEnvironment userCourseEnv) { + public void incrementNodeAttempts(CourseNode courseNode, Identity assessedIdentity, UserCourseEnvironment userCourseEnv, Role by) { ICourse course = CourseFactory.loadCourse(cgm.getCourseEntry()); AssessmentEntry nodeAssessment = getOrCreate(assessedIdentity, courseNode); int attempts = nodeAssessment.getAttempts() == null ? 1 :nodeAssessment.getAttempts().intValue() + 1; nodeAssessment.setAttempts(attempts); + if(by == Role.coach) { + nodeAssessment.setLastCoachModified(new Date()); + } else if(by == Role.user) { + nodeAssessment.setLastUserModified(new Date()); + } assessmentService.updateAssessmentEntry(nodeAssessment); + DBFactory.getInstance().commit(); + userCourseEnv.getScoreAccounting().evaluateAll(true); + DBFactory.getInstance().commit(); if(courseNode instanceof AssessableCourseNode) { // Update users efficiency statement efficiencyStatementManager.updateUserEfficiencyStatement(userCourseEnv); @@ -322,10 +346,27 @@ public class CourseAssessmentManagerImpl implements AssessmentManager { CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(ace, course); } + @Override + public void updateLastModifications(CourseNode courseNode, Identity assessedIdentity, UserCourseEnvironment userCourseEnv, Role by) { + AssessmentEntry nodeAssessment = getOrCreate(assessedIdentity, courseNode); + if(by == Role.coach) { + nodeAssessment.setLastCoachModified(new Date()); + } else if(by == Role.user) { + nodeAssessment.setLastUserModified(new Date()); + } + assessmentService.updateAssessmentEntry(nodeAssessment); + DBFactory.getInstance().commit(); + userCourseEnv.getScoreAccounting().evaluateAll(true); + if(courseNode instanceof AssessableCourseNode) { + // Update users efficiency statement + efficiencyStatementManager.updateUserEfficiencyStatement(userCourseEnv); + } + } + @Override public void saveScoreEvaluation(AssessableCourseNode courseNode, Identity identity, Identity assessedIdentity, ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnv, - boolean incrementUserAttempts) { + boolean incrementUserAttempts, Role by) { final ICourse course = CourseFactory.loadCourse(cgm.getCourseEntry()); final CourseEnvironment courseEnv = userCourseEnv.getCourseEnvironment(); @@ -339,6 +380,11 @@ public class CourseAssessmentManagerImpl implements AssessmentManager { if(referenceEntry != null && !referenceEntry.equals(assessmentEntry.getReferenceEntry())) { assessmentEntry.setReferenceEntry(referenceEntry); } + if(by == Role.coach) { + assessmentEntry.setLastCoachModified(new Date()); + } else if(by == Role.user) { + assessmentEntry.setLastUserModified(new Date()); + } if(score == null) { assessmentEntry.setScore(null); } else { @@ -413,9 +459,10 @@ public class CourseAssessmentManagerImpl implements AssessmentManager { // write only when enabled for this course if (courseEnv.getCourseConfig().isEfficencyStatementEnabled()) { List<AssessmentNodeData> data = new ArrayList<AssessmentNodeData>(50); + AssessmentNodesLastModified lastModifications = new AssessmentNodesLastModified(); AssessmentHelper.getAssessmentNodeDataList(0, courseEnv.getRunStructure().getRootNode(), - scoreAccounting, userCourseEnv, true, true, true, data); - efficiencyStatementManager.updateUserEfficiencyStatement(assessedIdentity, courseEnv, data, cgm.getCourseEntry()); + scoreAccounting, userCourseEnv, true, true, true, data, lastModifications); + efficiencyStatementManager.updateUserEfficiencyStatement(assessedIdentity, courseEnv, data, lastModifications, cgm.getCourseEntry()); } if(course.getCourseConfig().isAutomaticCertificationEnabled()) { diff --git a/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java b/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java index b3eea997c07ed9e5650b84ed82a32ee56b71d4b8..705ad0bf5cefa8ab2c9c67848c11bfb929588986 100644 --- a/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java +++ b/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java @@ -54,6 +54,7 @@ import org.olat.course.assessment.EfficiencyStatement; import org.olat.course.assessment.EfficiencyStatementArchiver; import org.olat.course.assessment.UserEfficiencyStatement; import org.olat.course.assessment.model.AssessmentNodeData; +import org.olat.course.assessment.model.AssessmentNodesLastModified; import org.olat.course.assessment.model.UserEfficiencyStatementImpl; import org.olat.course.assessment.model.UserEfficiencyStatementLight; import org.olat.course.assessment.model.UserEfficiencyStatementStandalone; @@ -166,15 +167,17 @@ public class EfficiencyStatementManager implements UserDataDeletable { CourseConfig cc = userCourseEnv.getCourseEnvironment().getCourseConfig(); // write only when enabled for this course if (cc.isEfficencyStatementEnabled()) { - Identity identity = userCourseEnv.getIdentityEnvironment().getIdentity(); - List<AssessmentNodeData> assessmentNodeList = AssessmentHelper.getAssessmentNodeDataList(userCourseEnv, true, true, true); - updateUserEfficiencyStatement(identity, userCourseEnv.getCourseEnvironment(), assessmentNodeList, repoEntry); + Identity identity = userCourseEnv.getIdentityEnvironment().getIdentity(); + AssessmentNodesLastModified lastModifications = new AssessmentNodesLastModified(); + List<AssessmentNodeData> assessmentNodeList = AssessmentHelper.getAssessmentNodeDataList(userCourseEnv, lastModifications, true, true, true); + updateUserEfficiencyStatement(identity, userCourseEnv.getCourseEnvironment(), assessmentNodeList, lastModifications, repoEntry); } } - public void updateUserEfficiencyStatement(Identity assessedIdentity, final CourseEnvironment courseEnv, List<AssessmentNodeData> assessmentNodeList, final RepositoryEntry repoEntry) { + public void updateUserEfficiencyStatement(Identity assessedIdentity, final CourseEnvironment courseEnv, + List<AssessmentNodeData> assessmentNodeList, AssessmentNodesLastModified lastModifications, final RepositoryEntry repoEntry) { List<Map<String,Object>> assessmentNodes = AssessmentHelper.assessmentNodeDataListToMap(assessmentNodeList); - + EfficiencyStatement efficiencyStatement = new EfficiencyStatement(); efficiencyStatement.setAssessmentNodes(assessmentNodes); efficiencyStatement.setCourseTitle(courseEnv.getCourseTitle()); @@ -182,6 +185,14 @@ public class EfficiencyStatementManager implements UserDataDeletable { String userInfos = userManager.getUserDisplayName(assessedIdentity); efficiencyStatement.setDisplayableUserInfo(userInfos); efficiencyStatement.setLastUpdated(System.currentTimeMillis()); + if(lastModifications != null) { + if(lastModifications.getLastUserModified() != null) { + efficiencyStatement.setLastUserModified(lastModifications.getLastUserModified().getTime()); + } + if(lastModifications.getLastCoachModified() != null) { + efficiencyStatement.setLastCoachModified(lastModifications.getLastCoachModified().getTime()); + } + } boolean debug = log.isDebug(); UserEfficiencyStatementImpl efficiencyProperty = getUserEfficiencyStatementFull(repoEntry, assessedIdentity); @@ -195,8 +206,9 @@ public class EfficiencyStatementManager implements UserDataDeletable { efficiencyProperty.setResource(repoEntry.getOlatResource()); efficiencyProperty.setCourseRepoKey(repoEntry.getKey()); } - - fillEfficiencyStatement(efficiencyStatement, efficiencyProperty); + efficiencyProperty.setShortTitle(courseEnv.getRunStructure().getRootNode().getShortTitle()); + efficiencyProperty.setTitle(courseEnv.getRunStructure().getRootNode().getLongTitle()); + fillEfficiencyStatement(efficiencyStatement, lastModifications, efficiencyProperty); dbInstance.getCurrentEntityManager().persist(efficiencyProperty); if (debug) { log.debug("creating new efficiency statement property::" + efficiencyProperty.getKey() + " for id::" + assessedIdentity.getName() + " repoEntry::" + repoEntry.getKey()); @@ -205,8 +217,10 @@ public class EfficiencyStatementManager implements UserDataDeletable { // update existing if (debug) { log.debug("updating efficiency statement property::" + efficiencyProperty.getKey() + " for id::" + assessedIdentity.getName() + " repoEntry::" + repoEntry.getKey()); - } - fillEfficiencyStatement(efficiencyStatement, efficiencyProperty); + } + efficiencyProperty.setShortTitle(courseEnv.getRunStructure().getRootNode().getShortTitle()); + efficiencyProperty.setTitle(courseEnv.getRunStructure().getRootNode().getLongTitle()); + fillEfficiencyStatement(efficiencyStatement, lastModifications, efficiencyProperty); dbInstance.getCurrentEntityManager().merge(efficiencyProperty); } } else { @@ -226,7 +240,18 @@ public class EfficiencyStatementManager implements UserDataDeletable { CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(ace, courseOres); } - public void fillEfficiencyStatement(EfficiencyStatement efficiencyStatement, UserEfficiencyStatementImpl efficiencyProperty) { + public void fillEfficiencyStatement(EfficiencyStatement efficiencyStatement, AssessmentNodesLastModified lastModifications, UserEfficiencyStatementImpl efficiencyProperty) { + if(lastModifications != null) { + if(lastModifications.getLastUserModified() != null + && (efficiencyProperty.getLastUserModified() == null || efficiencyProperty.getLastUserModified().before(lastModifications.getLastUserModified()))) { + efficiencyProperty.setLastUserModified(lastModifications.getLastUserModified()); + } + if(lastModifications.getLastCoachModified() != null + && (efficiencyProperty.getLastCoachModified() == null || efficiencyProperty.getLastCoachModified().before(lastModifications.getLastCoachModified()))) { + efficiencyProperty.setLastCoachModified(lastModifications.getLastCoachModified()); + } + } + List<Map<String,Object>> nodeData = efficiencyStatement.getAssessmentNodes(); if(!nodeData.isEmpty()) { Map<String,Object> rootNode = nodeData.get(0); @@ -264,6 +289,21 @@ public class EfficiencyStatementManager implements UserDataDeletable { int passedNodes = getPassedNodes(nodeData); efficiencyProperty.setPassedNodes(passedNodes); + + for(Map<String,Object> node:nodeData) { + Date lastUserModified = (Date)node.get(AssessmentHelper.KEY_LAST_USER_MODIFIED); + if(lastUserModified != null) { + if(efficiencyProperty.getLastUserModified() == null || efficiencyProperty.getLastUserModified().before(lastUserModified)) { + efficiencyProperty.setLastUserModified(lastUserModified); + } + } + Date lastCoachModified = (Date)node.get(AssessmentHelper.KEY_LAST_COACH_MODIFIED); + if(lastCoachModified != null) { + if(efficiencyProperty.getLastCoachModified() == null || efficiencyProperty.getLastCoachModified().before(lastCoachModified)) { + efficiencyProperty.setLastCoachModified(lastCoachModified); + } + } + } } efficiencyProperty.setLastModified(new Date()); @@ -599,6 +639,10 @@ public class EfficiencyStatementManager implements UserDataDeletable { .getResultList(); } + public List<Identity> findIdentitiesWithEfficiencyStatements(RepositoryEntryRef repoEntry) { + return findIdentitiesWithEfficiencyStatements(repoEntry.getKey()); + } + /** * Find all identities who have an efficiency statement for this course repository entry * @param courseRepoEntryKey diff --git a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManager.java b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManager.java index 6a354efee745e21d5272e2aef942c28c847d9bf7..c25afe5d699b7cf1eb122562355875074852e82b 100644 --- a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManager.java +++ b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManager.java @@ -26,7 +26,9 @@ import java.util.Map; import org.olat.basesecurity.IdentityRef; import org.olat.core.id.Identity; import org.olat.course.assessment.UserCourseInformations; +import org.olat.group.BusinessGroupRef; import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryEntryRef; import org.olat.resource.OLATResource; /** @@ -43,6 +45,10 @@ public interface UserCourseInformationsManager { public Date getInitialLaunchDate(OLATResource resource, IdentityRef identity); + public Date getInitialLaunchDate(RepositoryEntryRef entry, IdentityRef identity); + + public Date getInitialParticipantLaunchDate(RepositoryEntryRef entry, BusinessGroupRef businessGroup); + public Date getRecentLaunchDate(OLATResource resource, IdentityRef identity); /** diff --git a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java index f97267f00d34ffb292cf9c453b4ccc37c47dec80..1f8e179a7c94c1079db6adb45641a51b7e1a531a 100644 --- a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java +++ b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java @@ -30,6 +30,7 @@ import java.util.Set; import javax.persistence.FlushModeType; import javax.persistence.TypedQuery; +import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.PersistenceHelper; @@ -42,7 +43,9 @@ import org.olat.core.util.coordinate.SyncerExecutor; import org.olat.core.util.resource.OresHelper; import org.olat.course.assessment.UserCourseInformations; import org.olat.course.assessment.model.UserCourseInfosImpl; +import org.olat.group.BusinessGroupRef; import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryEntryRef; import org.olat.resource.OLATResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -204,10 +207,60 @@ public class UserCourseInformationsManagerImpl implements UserCourseInformations } return infoList.get(0); } catch (Exception e) { - log.error("Cannot retrieve course informations for: " + resource.getResourceableId(), e); + log.error("Cannot retrieve course informations for resource: " + resource.getResourceableId(), e); return null; } } + + @Override + public Date getInitialLaunchDate(RepositoryEntryRef entry, IdentityRef identity) { + try { + StringBuilder sb = new StringBuilder(); + sb.append("select infos.initialLaunch from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ") + .append(" inner join infos.resource as resource") + .append(" inner join repositoryentry as entry on (resource.key=entry.olatResource.key)") + .append(" where infos.identity.key=:identityKey and entry.key=:entryKey"); + + List<Date> infoList = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Date.class) + .setParameter("identityKey", identity.getKey()) + .setParameter("entryKey", entry.getKey()) + .getResultList(); + + if(infoList.isEmpty()) { + return null; + } + return infoList.get(0); + } catch (Exception e) { + log.error("Cannot retrieve course informations for entry: " + entry.getKey(), e); + return null; + } + } + + @Override + public Date getInitialParticipantLaunchDate(RepositoryEntryRef entry, BusinessGroupRef businessGroup) { + StringBuilder sb = new StringBuilder(); + sb.append("select min(infos.initialLaunch) from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ") + .append(" inner join infos.resource as resource") + .append(" inner join repositoryentry as entry on (resource.key=entry.olatResource.key and entry.key=:entryKey)") + .append(" inner join entry.groups as relGroup on relGroup.defaultGroup=false") + .append(" inner join relGroup.group as baseGroup") + .append(" inner join businessgroup as bg on (relGroup.group.key=bg.baseGroup.key and bg.key=:groupKey)") + .append(" inner join baseGroup.members as memberships on (memberships.role = '").append(GroupRoles.participant.name()).append("')") + .append(" inner join memberships.identity as ident") + .append(" where infos.identity.key=memberships.identity.key"); + + List<Date> infoList = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Date.class) + .setParameter("groupKey", businessGroup.getKey()) + .setParameter("entryKey", entry.getKey()) + .getResultList(); + + if(infoList.isEmpty()) { + return null; + } + return infoList.get(0); + } /** * Return a map of identity keys to initial launch date. diff --git a/src/main/java/org/olat/course/assessment/model/AssessmentNodeData.java b/src/main/java/org/olat/course/assessment/model/AssessmentNodeData.java index ef84de8e3dbe23b01f7d283d615e79b385c1d980..b05a6f58569ba8b9fa191420f60099a3c294d931 100644 --- a/src/main/java/org/olat/course/assessment/model/AssessmentNodeData.java +++ b/src/main/java/org/olat/course/assessment/model/AssessmentNodeData.java @@ -23,6 +23,8 @@ import static org.olat.course.assessment.AssessmentHelper.KEY_ATTEMPTS; import static org.olat.course.assessment.AssessmentHelper.KEY_DETAILS; import static org.olat.course.assessment.AssessmentHelper.KEY_IDENTIFYER; import static org.olat.course.assessment.AssessmentHelper.KEY_INDENT; +import static org.olat.course.assessment.AssessmentHelper.KEY_LAST_COACH_MODIFIED; +import static org.olat.course.assessment.AssessmentHelper.KEY_LAST_USER_MODIFIED; import static org.olat.course.assessment.AssessmentHelper.KEY_MAX; import static org.olat.course.assessment.AssessmentHelper.KEY_MIN; import static org.olat.course.assessment.AssessmentHelper.KEY_PASSED; @@ -33,6 +35,7 @@ import static org.olat.course.assessment.AssessmentHelper.KEY_TITLE_LONG; import static org.olat.course.assessment.AssessmentHelper.KEY_TITLE_SHORT; import static org.olat.course.assessment.AssessmentHelper.KEY_TYPE; +import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -72,6 +75,10 @@ public class AssessmentNodeData { private int numOfAssessmentDocs; + private Date lastModified; + private Date lastUserModified; + private Date lastCoachModified; + private boolean selectable; private boolean onyx = false; @@ -215,6 +222,30 @@ public class AssessmentNodeData { this.numOfAssessmentDocs = numOfAssessmentDocs; } + public Date getLastModified() { + return lastModified; + } + + public void setLastModified(Date lastModified) { + this.lastModified = lastModified; + } + + public Date getLastUserModified() { + return lastUserModified; + } + + public void setLastUserModified(Date lastUserModified) { + this.lastUserModified = lastUserModified; + } + + public Date getLastCoachModified() { + return lastCoachModified; + } + + public void setLastCoachModified(Date lastCoachModified) { + this.lastCoachModified = lastCoachModified; + } + public boolean isOnyx() { return onyx; } @@ -258,6 +289,12 @@ public class AssessmentNodeData { if (passed != null) { nodeData.put(KEY_PASSED, passed); } + if(lastUserModified != null) { + nodeData.put(KEY_LAST_USER_MODIFIED, lastUserModified); + } + if(lastCoachModified != null) { + nodeData.put(KEY_LAST_COACH_MODIFIED, lastCoachModified); + } nodeData.put(KEY_SELECTABLE, selectable ? Boolean.TRUE : Boolean.FALSE); return nodeData; } @@ -280,6 +317,13 @@ public class AssessmentNodeData { if(nodeData.get(KEY_SELECTABLE) instanceof Boolean) { selectable = ((Boolean)nodeData.get(KEY_SELECTABLE)).booleanValue(); } + if(nodeData.get(KEY_LAST_USER_MODIFIED) instanceof Date) { + lastUserModified = ((Date)nodeData.get(KEY_LAST_USER_MODIFIED)); + } + if(nodeData.get(KEY_LAST_COACH_MODIFIED) instanceof Date) { + lastCoachModified = ((Date)nodeData.get(KEY_LAST_COACH_MODIFIED)); + } + } @Override diff --git a/src/main/java/org/olat/course/assessment/model/AssessmentNodesLastModified.java b/src/main/java/org/olat/course/assessment/model/AssessmentNodesLastModified.java new file mode 100644 index 0000000000000000000000000000000000000000..159015f85a63d4f348815f16c209b6601f676b6e --- /dev/null +++ b/src/main/java/org/olat/course/assessment/model/AssessmentNodesLastModified.java @@ -0,0 +1,77 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.assessment.model; + +import java.util.Date; + +/** + * + * Initial date: 14 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AssessmentNodesLastModified { + + private Date lastModified; + private Date lastUserModified; + private Date lastCoachModified; + + public Date getLastModified() { + return lastModified; + } + + public void addLastModified(Date date) { + if(date == null) return; + + if(lastModified == null) { + lastModified = date; + } else if(lastModified != null && lastModified.before(date)) { + lastModified = date; + } + } + + public Date getLastUserModified() { + return lastUserModified; + } + + public void addLastUserModified(Date date) { + if(date == null) return; + + if(lastUserModified == null) { + lastUserModified = date; + } else if(lastUserModified != null && lastUserModified.before(date)) { + lastUserModified = date; + } + } + + public Date getLastCoachModified() { + return lastCoachModified; + } + + public void addLastCoachModified(Date date) { + if(date == null) return; + + if(lastCoachModified == null) { + lastCoachModified = date; + } else if(lastCoachModified != null && lastCoachModified.before(date)) { + lastCoachModified = date; + } + } +} diff --git a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml index d17e726464a5bcd4df31095373b690eab44752b2..49c302f498f529ba4a4a4d10b468fca726280fa4 100644 --- a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml +++ b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml @@ -20,6 +20,8 @@ <version name="version" access="field" column="version" type="int"/> <property name="creationDate" column="creationdate" type="timestamp" /> <property name="lastModified" column="lastmodified" type="timestamp" /> + <property name="lastUserModified" column="lastusermodified" type="timestamp" /> + <property name="lastCoachModified" column="lastcoachmodified" type="timestamp" /> <property name="score" column="score" type="float" /> <property name="passed" column="passed" type="boolean" /> @@ -66,6 +68,8 @@ <version name="version" access="field" column="version" type="int"/> <property name="creationDate" column="creationdate" type="timestamp" /> <property name="lastModified" column="lastmodified" type="timestamp" /> + <property name="lastUserModified" column="lastusermodified" type="timestamp" /> + <property name="lastCoachModified" column="lastcoachmodified" type="timestamp" /> <property name="score" column="score" type="float" /> <property name="passed" column="passed" type="boolean" /> @@ -104,6 +108,8 @@ <version name="version" access="field" column="version" type="int"/> <property name="creationDate" column="creationdate" type="timestamp" /> <property name="lastModified" column="lastmodified" type="timestamp" /> + <property name="lastUserModified" column="lastusermodified" type="timestamp" /> + <property name="lastCoachModified" column="lastcoachmodified" type="timestamp" /> <property name="score" column="score" type="float" /> <property name="passed" column="passed" type="boolean" /> diff --git a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.java b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.java index 40865dcd4786222bb6985928b5822720774beadb..2b4838673ec4864bb6e3d2dd420e147e2126469e 100644 --- a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.java +++ b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.java @@ -51,6 +51,12 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use private String statementXml; private Date lastModified; + private Date lastUserModified; + private Date lastCoachModified; + + public UserEfficiencyStatementImpl() { + // + } @Override public Date getLastModified() { @@ -62,6 +68,22 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use this.lastModified = lastModified; } + public Date getLastUserModified() { + return lastUserModified; + } + + public void setLastUserModified(Date lastUserModified) { + this.lastUserModified = lastUserModified; + } + + public Date getLastCoachModified() { + return lastCoachModified; + } + + public void setLastCoachModified(Date lastCoachModified) { + this.lastCoachModified = lastCoachModified; + } + @Override public Float getScore() { return score; diff --git a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementLight.java b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementLight.java index bfd22f56b16c3553103e6da2a99e4c47b8e008d6..f256aacf073ae3a4f13d09d77f9267a3def4492b 100644 --- a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementLight.java +++ b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementLight.java @@ -53,6 +53,8 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us private Long archivedResourceKey; private Date lastModified; + private Date lastUserModified; + private Date lastCoachModified; @Override public Date getLastModified() { @@ -64,6 +66,22 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us this.lastModified = lastModified; } + public Date getLastUserModified() { + return lastUserModified; + } + + public void setLastUserModified(Date lastUserModified) { + this.lastUserModified = lastUserModified; + } + + public Date getLastCoachModified() { + return lastCoachModified; + } + + public void setLastCoachModified(Date lastCoachModified) { + this.lastCoachModified = lastCoachModified; + } + @Override public Float getScore() { return score; diff --git a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementStandalone.java b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementStandalone.java index 1a3d2a9c3e546d6f482a01d4d01fdb411ab0d0d9..3effbfee69654c221d02a500ff3d0c9f9bd2e0f1 100644 --- a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementStandalone.java +++ b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementStandalone.java @@ -53,6 +53,8 @@ public class UserEfficiencyStatementStandalone extends PersistentObject implemen private String statementXml; private Date lastModified; + private Date lastUserModified; + private Date lastCoachModified; @Override public Date getLastModified() { @@ -64,6 +66,22 @@ public class UserEfficiencyStatementStandalone extends PersistentObject implemen this.lastModified = lastModified; } + public Date getLastUserModified() { + return lastUserModified; + } + + public void setLastUserModified(Date lastUserModified) { + this.lastUserModified = lastUserModified; + } + + public Date getLastCoachModified() { + return lastCoachModified; + } + + public void setLastCoachModified(Date lastCoachModified) { + this.lastCoachModified = lastCoachModified; + } + @Override public Float getScore() { return score; diff --git a/src/main/java/org/olat/course/assessment/portfolio/EfficiencyStatementMediaHandler.java b/src/main/java/org/olat/course/assessment/portfolio/EfficiencyStatementMediaHandler.java index 6731660e7882c6e3710e3d509dce6b508c99303e..a74eac51a8b63d4a74b749c63bfe5c09d0b84181 100644 --- a/src/main/java/org/olat/course/assessment/portfolio/EfficiencyStatementMediaHandler.java +++ b/src/main/java/org/olat/course/assessment/portfolio/EfficiencyStatementMediaHandler.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -35,6 +36,7 @@ import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementControlle import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.handler.AbstractMediaHandler; import org.olat.modules.portfolio.manager.MediaDAO; @@ -120,7 +122,7 @@ public class EfficiencyStatementMediaHandler extends AbstractMediaHandler { } @Override - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { String statementXml = media.getContent(); EfficiencyStatement statement = null; if(StringHelper.containsNonWhitespace(statementXml)) { diff --git a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModel.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModel.java index a51f767870898f02161262d010e22d8ba3e43235..0ffa2d57dc3e58db525dc09d348cab052ff18a4c 100644 --- a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModel.java +++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModel.java @@ -27,7 +27,10 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFle import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; import org.olat.core.gui.translator.Translator; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; +import org.olat.course.CorruptedCourseException; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentMode; @@ -45,6 +48,8 @@ import org.olat.course.nodes.CourseNode; */ public class AssessmentModeListModel extends DefaultFlexiTableDataModel<AssessmentMode> implements SortableFlexiTableDataModel<AssessmentMode> { + private static final OLog log = Tracing.createLoggerFor(AssessmentModeListModel.class); + private final Translator translator; private final AssessmentModeCoordinationService coordinationService; @@ -72,27 +77,35 @@ public class AssessmentModeListModel extends DefaultFlexiTableDataModel<Assessme case status: { List<String> warnings = null; Status status = mode.getStatus(); - if(StringHelper.containsNonWhitespace(mode.getStartElement())) { - ICourse course = CourseFactory.loadCourse(mode.getRepositoryEntry()); - CourseNode node = course.getRunStructure().getNode(mode.getStartElement()); - if(node == null) { - warnings = new ArrayList<>(2); - warnings.add(translator.translate("warning.missing.start.element")); - } - } - if(StringHelper.containsNonWhitespace(mode.getElementList())) { - ICourse course = CourseFactory.loadCourse(mode.getRepositoryEntry()); - String elements = mode.getElementList(); - for(String element:elements.split(",")) { - CourseNode node = course.getRunStructure().getNode(element); + try { + if(StringHelper.containsNonWhitespace(mode.getStartElement())) { + ICourse course = CourseFactory.loadCourse(mode.getRepositoryEntry()); + CourseNode node = course.getRunStructure().getNode(mode.getStartElement()); if(node == null) { - if(warnings == null) { - warnings = new ArrayList<>(2); + warnings = new ArrayList<>(2); + warnings.add(translator.translate("warning.missing.start.element")); + } + } + if(StringHelper.containsNonWhitespace(mode.getElementList())) { + ICourse course = CourseFactory.loadCourse(mode.getRepositoryEntry()); + String elements = mode.getElementList(); + for(String element:elements.split(",")) { + CourseNode node = course.getRunStructure().getNode(element); + if(node == null) { + if(warnings == null) { + warnings = new ArrayList<>(2); + } + warnings.add(translator.translate("warning.missing.element")); + break; } - warnings.add(translator.translate("warning.missing.element")); - break; } } + } catch (CorruptedCourseException e) { + log.error("", e); + if(warnings == null) { + warnings = new ArrayList<>(2); + } + warnings.add(translator.translate("cif.error.corrupted")); } return new EnhancedStatus(status, warnings); } diff --git a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_fr.properties index e083be2a6ebc2af9bd59cc5746aac23e5fcdd549..2b5d9954fde5595c543fbf5b541901a78f95a06c 100644 --- a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_fr.properties @@ -48,7 +48,7 @@ error.course.element.mandatory=Choisissez s'il vous pla\u00EEt au moins un \u00E error.group.missing=Vous devez choisir au moins un groupe. error.in.assessment=Vous ne pouvez pas effacer la configuration d'une \u00E9valuation en cours. error.ip.range=Vous ne vous trouvez pas dans le r\u00E9seau ad\u00E9quat. -error.ip.range.desc=L'examen ne peut \u00EAtre r\u00E9aliser que depuis un r\u00E9seau pr\u00E9alablement autoris\u00E9, contactez s'il-vous-pla\u00EEt l'administrateur de l'examen. Votre adresse IP est\: {0} +error.ip.range.desc=L'examen ne peut \u00EAtre r\u00E9aliser que depuis un r\u00E9seau pr\u00E9alablement autoris\u00E9, contactez s'il vous pla\u00EEt l'administrateur de l'examen. Votre adresse IP est\: {0} error.safe.exam=Veuillez utiliser, s'il vous pla\u00EEt, le Safe Exam Browser. error.safe.exam.desc=Voss n'utilisez pas <a href\="http\://safeexambrowser.org" target\="_blank">Safe Exam Browser</a> ou alors une configuration erron\u00E9e de Safe Exam Browse. Utilisez s'il-vous-pla\u00EEt la configuration Safe Exam Browser pr\u00E9vu par le responsable de l'examen pour votre syst\u00E8me d'exploitation. form.mode.description=Cr\u00E9er une configuration d'\u00E9valuation pour utiliser ce cours ou une parte de ses \u00E9l\u00E9ments de cours de mani\u00E8re prot\u00E9g\u00E9 avec des possibilit\u00E9s limit\u00E9s. diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java index d626b3fbf31eec0ab5f23521791cfb5fd6999427..f975473b8ffaa56e50ab984c6640130b1ca4979e 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java @@ -63,6 +63,7 @@ import org.olat.course.nodes.AssessableCourseNode; import org.olat.course.run.scoring.ScoreAccounting; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.modules.assessment.ui.event.AssessmentFormEvent; @@ -315,7 +316,7 @@ public class AssessmentForm extends FormBasicController { ScoreEvaluation reopenedEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(), AssessmentEntryStatus.inReview, scoreEval.getUserVisible(), scoreEval.getFullyAssessed(), scoreEval.getAssessmentID()); - assessableCourseNode.updateUserScoreEvaluation(reopenedEval, assessedUserCourseEnv, getIdentity(), false); + assessableCourseNode.updateUserScoreEvaluation(reopenedEval, assessedUserCourseEnv, getIdentity(), false, Role.coach); updateStatus(reopenedEval); } } @@ -337,7 +338,7 @@ public class AssessmentForm extends FormBasicController { Boolean updatedPassed = null; if (isHasAttempts() && isAttemptsDirty()) { - assessableCourseNode.updateUserAttempts(new Integer(getAttempts()), assessedUserCourseEnv, getIdentity()); + assessableCourseNode.updateUserAttempts(new Integer(getAttempts()), assessedUserCourseEnv, getIdentity(), Role.coach); } if (isHasScore()) { @@ -368,7 +369,7 @@ public class AssessmentForm extends FormBasicController { } else { scoreEval = new ScoreEvaluation(updatedScore, updatedPassed, null, visibility, null, null); } - assessableCourseNode.updateUserScoreEvaluation(scoreEval, assessedUserCourseEnv, getIdentity(), false); + assessableCourseNode.updateUserScoreEvaluation(scoreEval, assessedUserCourseEnv, getIdentity(), false, Role.coach); if (isHasComment() && isUserCommentDirty()) { String newComment = getUserComment().getValue(); diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityAssessmentOverviewController.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityAssessmentOverviewController.java index aa51bff7267effcc204fe81297a317dc48a7c6e1..ac6eb53e4e0a10a387e37603b17bc2e5a0485236 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityAssessmentOverviewController.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityAssessmentOverviewController.java @@ -242,6 +242,10 @@ public class IdentityAssessmentOverviewController extends FormBasicController im columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(NodeCols.passed, new PassedCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(NodeCols.numOfAssessmentDocs)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(NodeCols.status, new AssessmentStatusCellRenderer(getLocale()))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, NodeCols.lastModified)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(NodeCols.lastUserModified)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, NodeCols.lastCoachModified)); + if(nodesSelectable) { DefaultFlexiColumnModel selectCol = new DefaultFlexiColumnModel("select", NodeCols.select.ordinal(), CMD_SELECT_NODE, new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("select"), CMD_SELECT_NODE), null)); @@ -278,7 +282,7 @@ public class IdentityAssessmentOverviewController extends FormBasicController im List<AssessmentNodeData> nodesTableList; if (loadNodesFromCourse) { // get list of course node and user data and populate table data model - nodesTableList = AssessmentHelper.getAssessmentNodeDataList(userCourseEnvironment, followUserResultsVisibility, discardEmptyNodes, true); + nodesTableList = AssessmentHelper.getAssessmentNodeDataList(userCourseEnvironment, null, followUserResultsVisibility, discardEmptyNodes, true); } else { // use list from efficiency statement nodesTableList = preloadedNodesList; diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityAssessmentOverviewTableModel.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityAssessmentOverviewTableModel.java index 64aa05045ed9a3425b61af9f5ba699c35036e366..f344f864c65604a3b68900297256dd933c9dae79 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityAssessmentOverviewTableModel.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityAssessmentOverviewTableModel.java @@ -109,6 +109,9 @@ public class IdentityAssessmentOverviewTableModel extends DefaultFlexiTableDataM return nodeData.getNumOfAssessmentDocs(); } case select: return nodeData.isSelectable(); + case lastModified: return nodeData.getLastModified(); + case lastUserModified: return nodeData.getLastUserModified(); + case lastCoachModified: return nodeData.getLastCoachModified(); default: return "ERROR"; } } @@ -136,7 +139,10 @@ public class IdentityAssessmentOverviewTableModel extends DefaultFlexiTableDataM status("table.header.status", true), passed("table.header.passed", true), select("table.action.select", false), - numOfAssessmentDocs("table.header.num.assessmentDocs", true); + numOfAssessmentDocs("table.header.num.assessmentDocs", true), + lastModified("table.header.lastScoreDate", true), + lastUserModified("table.header.lastUserModificationDate", true), + lastCoachModified("table.header.lastCoachModificationDate", true); private final String i18nKey; private final boolean sortable; diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java index 2168f49f35903f184bbed68bba698321a5436690..d5c96424fef0f3655620cb1fbdc6a2d6f8321f3d 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java @@ -91,6 +91,7 @@ import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.modules.assessment.ui.AssessedIdentityController; import org.olat.modules.assessment.ui.AssessedIdentityElementRow; @@ -251,8 +252,13 @@ public class IdentityListCourseNodeController extends FormBasicController implem } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.assessmentStatus, new AssessmentStatusCellRenderer(getLocale()))); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.initialLaunchDate, select)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.lastScoreUpdate, select)); + if(courseNode.getParent() == null) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.initialLaunchDate, select)); + } + + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, IdentityCourseElementCols.lastModified, select)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.lastUserModified, select)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, IdentityCourseElementCols.lastCoachModified, select)); if(course.getCourseConfig().isCertificateEnabled()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.certificate, new DownloadCertificateCellRenderer())); @@ -646,7 +652,7 @@ public class IdentityListCourseNodeController extends FormBasicController implem ScoreEvaluation scoreEval = assessableCourseNode.getUserScoreEvaluation(assessedUserCourseEnv); ScoreEvaluation doneEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(), scoreEval.getAssessmentStatus(), visibility, scoreEval.getFullyAssessed(), scoreEval.getAssessmentID()); - assessableCourseNode.updateUserScoreEvaluation(doneEval, assessedUserCourseEnv, getIdentity(), false); + assessableCourseNode.updateUserScoreEvaluation(doneEval, assessedUserCourseEnv, getIdentity(), false, Role.coach); } updateModel(ureq, null, null, null); } @@ -679,7 +685,7 @@ public class IdentityListCourseNodeController extends FormBasicController implem ScoreEvaluation scoreEval = assessableCourseNode.getUserScoreEvaluation(assessedUserCourseEnv); ScoreEvaluation doneEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(), AssessmentEntryStatus.done, null, scoreEval.getFullyAssessed(), scoreEval.getAssessmentID()); - assessableCourseNode.updateUserScoreEvaluation(doneEval, assessedUserCourseEnv, getIdentity(), false); + assessableCourseNode.updateUserScoreEvaluation(doneEval, assessedUserCourseEnv, getIdentity(), false, Role.coach); } updateModel(ureq, null, null, null); diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeTableModel.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeTableModel.java index bc25f7d5ea063c511027c856468e22c807eeeee4..80cb2d4c12e8305103904c1f4450efc4af18d679 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeTableModel.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeTableModel.java @@ -147,7 +147,9 @@ public class IdentityListCourseNodeTableModel extends DefaultFlexiTableDataModel return certificate == null ? null : certificate.getNextRecertificationDate(); } case initialLaunchDate: return row.getInitialCourseLaunchDate(); - case lastScoreUpdate: return row.getLastModified(); + case lastModified: return row.getLastModified(); + case lastUserModified: return row.getLastUserModified(); + case lastCoachModified: return row.getLastCoachModified(); } } int propPos = col - AssessmentToolConstants.USER_PROPS_OFFSET; @@ -172,7 +174,9 @@ public class IdentityListCourseNodeTableModel extends DefaultFlexiTableDataModel certificate("table.header.certificate"), recertification("table.header.recertification"), initialLaunchDate("table.header.initialLaunchDate"), - lastScoreUpdate("table.header.lastScoreDate"), + lastModified("table.header.lastScoreDate"), + lastUserModified("table.header.lastUserModificationDate"), + lastCoachModified("table.header.lastCoachModificationDate"), numOfAssessmentDocs("table.header.num.assessmentDocs"); private final String i18nKey; diff --git a/src/main/java/org/olat/course/certificate/manager/CertificatePhantomWorker.java b/src/main/java/org/olat/course/certificate/manager/CertificatePhantomWorker.java index be9c456ca394ce932434f06cf8dfc9a217d71b03..cd1981cdbd1e2c092c182c6ea986f280c0596292 100644 --- a/src/main/java/org/olat/course/certificate/manager/CertificatePhantomWorker.java +++ b/src/main/java/org/olat/course/certificate/manager/CertificatePhantomWorker.java @@ -45,6 +45,7 @@ import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; +import org.olat.core.util.i18n.I18nManager; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.certificate.CertificateTemplate; import org.olat.repository.RepositoryEntry; @@ -148,6 +149,7 @@ public class CertificatePhantomWorker { fillCertificationInfos(context); fillAssessmentInfos(context); fillMetaInfos(context); + context.put("formatter", new DateFormatter()); return context; } @@ -278,6 +280,21 @@ public class CertificatePhantomWorker { log.info("PhantomJS help is available if exit value = 0: " + worker.getExitValue()); return worker.getExitValue() == 0; } + + public static class DateFormatter { + + public String formatDate(Date date, String language) { + Locale locale = I18nManager.getInstance().getLocaleOrDefault(language); + Formatter formatter = Formatter.getInstance(locale); + return formatter.formatDate(date); + } + + public String formatDateLong(Date date, String language) { + Locale locale = I18nManager.getInstance().getLocaleOrDefault(language); + Formatter formatter = Formatter.getInstance(locale); + return formatter.formatDateLong(date); + } + } private static class ProcessWorker extends Thread { diff --git a/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java b/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java index 44c2f7e8f001149f26d6a1a86ac14106bbb81374..1ae56fc5e9c43a2a158328873c4e4b79f843d3f9 100644 --- a/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java +++ b/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java @@ -874,7 +874,7 @@ public class CertificatesManagerImpl implements CertificatesManager, MessageList Float score = workUnit.getScore(); String lang = identity.getUser().getPreferences().getLanguage(); - Locale locale = I18nManager.getInstance().getLocaleOrDefault(lang); + Locale locale = i18nManager.getLocaleOrDefault(lang); Boolean passed = workUnit.getPassed(); Date dateCertification = certificate.getCreationDate(); Date dateFirstCertification = getDateFirstCertification(identity, resource.getKey()); diff --git a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java index a82259ee52be5dc96ea17944ed28fea0f284a852..b9f6f16c34dfbba06075c59915b0707d6951c45d 100644 --- a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java +++ b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java @@ -233,7 +233,14 @@ public class CertificateAndEfficiencyStatementController extends BasicController private void populateAssessedIdentityInfos(UserRequest ureq, RepositoryEntry courseRepo, BusinessGroup group, boolean links) { if(efficiencyStatement != null) { mainVC.contextPut("courseTitle", StringHelper.escapeHtml(efficiencyStatement.getCourseTitle())); - mainVC.contextPut("date", StringHelper.formatLocaleDateTime(efficiencyStatement.getLastUpdated(), ureq.getLocale())); + + long lastModified; + if(efficiencyStatement.getLastUserModified() > 0) { + lastModified = efficiencyStatement.getLastUserModified(); + } else { + lastModified = efficiencyStatement.getLastUpdated(); + } + mainVC.contextPut("date", StringHelper.formatLocaleDateTime(lastModified, getLocale())); } else if(courseRepo != null) { mainVC.contextPut("courseTitle", StringHelper.escapeHtml(courseRepo.getDisplayname())); } diff --git a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java index a0e94eb7d2f309b4ceea2d49f2e61fdc1c1652e8..d3770934a1a67fde00600b48c7145dc528972cca 100644 --- a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java +++ b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java @@ -56,6 +56,7 @@ import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; +import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.GenericEventListener; @@ -246,6 +247,9 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo resourceKeyToStatments.put(resourceKey, wrapper); statments.add(wrapper); } else { + if(!StringHelper.containsNonWhitespace(wrapper.getDisplayName())) { + wrapper.setDisplayName(certificate.getCourseTitle()); + } wrapper.setResourceKey(resourceKey); } if(resourceKey != null && wrapper.getResourceKey() == null) { @@ -254,6 +258,13 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo wrapper.setCertificate(certificate); } + for(CertificateAndEfficiencyStatement statment:statments) { + if(!StringHelper.containsNonWhitespace(statment.getDisplayName()) && statment.getResourceKey() != null) { + String displayName = repositoryManager.lookupDisplayNameByResourceKey(statment.getResourceKey()); + statment.setDisplayName(displayName); + } + } + tableModel.setObjects(statments); } diff --git a/src/main/java/org/olat/course/condition/AttributeEasyRowAdderController.java b/src/main/java/org/olat/course/condition/AttributeEasyRowAdderController.java index e7ec04dd46b6734dbee4aaea24a1a0b8d980f4b2..4a163237d75b060f0251e672e7a051d439748e43 100644 --- a/src/main/java/org/olat/course/condition/AttributeEasyRowAdderController.java +++ b/src/main/java/org/olat/course/condition/AttributeEasyRowAdderController.java @@ -64,7 +64,7 @@ import org.springframework.beans.factory.annotation.Autowired; * A subform that implement the shibboleth easy mode config rows. * <P> * Initial Date: 23.10.2006 <br> - * + * * @author Lars Eberle (<a href="http://www.bps-system.de/">BPS Bildungsportal Sachsen GmbH</a>) * @author Florian Gnägi (<a href="http://www.frentix.com/">frentix GmbH</a>) */ @@ -96,13 +96,13 @@ public class AttributeEasyRowAdderController extends FormBasicController { private int rowCreationCounter = 0; // private boolean isinit = false; - + @Autowired private ShibbolethModule shibbolethModule; /** * Constructor for a shibboleth attribute rule creator form. - * + * * @param ureq * @param wControl * @param parentForm @@ -113,7 +113,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { setTranslator(Util.createPackageTranslator(ShibbolethModule.class, ureq.getLocale(), getTranslator())); attributeTranslator = shibbolethModule.getAttributeTranslator(); attrKeys = getShibAttributes(); - preselectedAttribute = shibbolethModule.getPreselectedAttributeKey(ShibbolethModule.CONF_OLATUSERMAPPING_INSTITUTIONALNAME); + preselectedAttribute = shibbolethModule.getPreselectedAttributeKey(shibbolethModule.getShibbolethAttributeName(UserConstants.INSTITUTIONALNAME)); preselectedAttributeValue = ureq.getIdentity().getUser().getProperty(UserConstants.INSTITUTIONALNAME, getLocale()); operatorKeys = OperatorManager.getRegisteredOperatorKeys(shibbolethModule.getOperatorKeys()); this.init(); @@ -121,7 +121,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Constructor for a log attribute rule creator form. - * + * * @param ureq * @param wControl * @param parentForm @@ -262,7 +262,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal helper to get the current row count - * + * * @return */ private int getRowCount() { @@ -275,7 +275,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Method to get a list of extended conditions represented in this form - * + * * @return */ public List<ExtendedCondition> getAttributeConditions() { @@ -307,7 +307,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Method to initialize this form with the given extended conditions - * + * * @param cond */ public void setAttributeConditions(final List<ExtendedCondition> cond) { @@ -339,7 +339,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal method to add a new row at the given position - * + * * @param i */ private void addRowAt(final int rowPos) { @@ -437,7 +437,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal method to remove the row at the given position. - * + * * @param clickPos The row to be removed */ private void removeRowAt(final int clickPos) { @@ -475,7 +475,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal method to update a row's value element. This can be a text input box or a selection drop down depending on the shibboleth module configuration and the selected attribute. The method * will set the given value as the users selected / inputed value - * + * * @param attribute The attribute key. Must not be NULL * @param row the row ID * @param value The value that should be selected / used in the text input field. Can be NULL. @@ -558,13 +558,13 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Internal helper to create a sting array that contains all shibboleth attributes that can be selected in the drop down - * - * @return String[] - will never returh null + * + * @return String[] - will never return null */ private String[] getShibAttributes() { - if (shibbolethModule.isEnableShibbolethLogins()) { + if (shibbolethModule.isEnableShibbolethCourseEasyConfig()) { final AttributeTranslator attTrans = getAttributeTranslator(); - final Set<String> attributes = attTrans.getTranslateableAttributes(); + Set<String> attributes = attTrans.getTranslateableAttributes(); final String[] outNames = new String[attributes.size()]; int i = 0; for (final String attribute : attributes) { @@ -578,7 +578,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Checks if this form produces an error - * + * * @return true: has an error; false: is valid */ public boolean hasError() { @@ -592,7 +592,7 @@ public class AttributeEasyRowAdderController extends FormBasicController { /** * Get the form item that forms this subform - * + * * @return */ public FormItem getFormItem() { diff --git a/src/main/java/org/olat/course/condition/ConditionConfigEasyController.java b/src/main/java/org/olat/course/condition/ConditionConfigEasyController.java index f1c76f67da5726bdb4d55c39529ab4fb287d123b..5182125d613f8bd3981b5382be36ea388e2d70d6 100644 --- a/src/main/java/org/olat/course/condition/ConditionConfigEasyController.java +++ b/src/main/java/org/olat/course/condition/ConditionConfigEasyController.java @@ -286,7 +286,7 @@ public class ConditionConfigEasyController extends FormBasicController implement } // 6) attribute switch - if (shibbolethModule.isEnableShibbolethLogins()) { + if (shibbolethModule.isEnableShibbolethCourseEasyConfig()) { if (attributeSwitch.getSelectedKeys().size() == 1) { List<ExtendedCondition> le = attribteRowAdderSubform.getAttributeConditions(); @@ -558,7 +558,7 @@ public class ConditionConfigEasyController extends FormBasicController implement } } - if (shibbolethModule.isEnableShibbolethLogins()) { + if (shibbolethModule.isEnableShibbolethCourseEasyConfig()) { retVal=validateAttibuteFields()&&retVal; } // @@ -725,10 +725,10 @@ public class ConditionConfigEasyController extends FormBasicController implement addEasyGroupAreaChoosers(formLayout); addAssessmentSwitch(formLayout); // - if(shibbolethModule.isEnableShibbolethLogins()){ + if(shibbolethModule.isEnableShibbolethCourseEasyConfig()) { addAttributeSwitch(formLayout, ureq); } - flc.contextPut("shibbolethEnabled", new Boolean(shibbolethModule.isEnableShibbolethLogins())); + flc.contextPut("shibbolethEnabled", new Boolean(shibbolethModule.isEnableShibbolethCourseEasyConfig())); addAssessmentMode(formLayout); addApplyRulesForTutorsToo(formLayout); @@ -837,7 +837,7 @@ public class ConditionConfigEasyController extends FormBasicController implement final Set<FormItem> dependenciesAttributeSwitch = new HashSet<FormItem>(); // only add when initialized. is null when shibboleth module is not enabled - if (shibbolethModule.isEnableShibbolethLogins()) { + if (shibbolethModule.isEnableShibbolethCourseEasyConfig()) { dependenciesAttributeSwitch.add(attributeBconnector); } @@ -879,7 +879,7 @@ public class ConditionConfigEasyController extends FormBasicController implement } }); - if (shibbolethModule.isEnableShibbolethLogins()) { + if (shibbolethModule.isEnableShibbolethCourseEasyConfig()) { FormItemDependencyRule hideClearAttibuteSwitchDeps = RulesFactory.createCustomRule(attributeSwitch, null, dependenciesAttributeSwitch, formLayout); hideClearAttibuteSwitchDeps.setDependencyRuleApplayable(new DependencyRuleApplayable() { @@ -922,7 +922,7 @@ public class ConditionConfigEasyController extends FormBasicController implement groupSwitch.clearError(); groupSubContainer.setVisible(false); - if (shibbolethModule.isEnableShibbolethLogins()) { + if (shibbolethModule.isEnableShibbolethCourseEasyConfig()) { attributeSwitch.clearError(); } easyGroupList.setFocus(false); @@ -1056,7 +1056,7 @@ public class ConditionConfigEasyController extends FormBasicController implement switchesOnly.add(groupSwitch); switchesOnly.add(assessmentSwitch); switchesOnly.add(applyRulesForCoach); - if (shibbolethModule.isEnableShibbolethLogins()) { + if (shibbolethModule.isEnableShibbolethCourseEasyConfig()) { switchesOnly.add(attributeSwitch); } @@ -1071,7 +1071,7 @@ public class ConditionConfigEasyController extends FormBasicController implement assessmentMode.setEnabled(true); //default is a checked disabled apply rules for coach - if (shibbolethModule.isEnableShibbolethLogins()) { + if (shibbolethModule.isEnableShibbolethCourseEasyConfig()) { attributeSwitch.setEnabled(true); } if(!firedDuringInit){ diff --git a/src/main/java/org/olat/course/db/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/db/_i18n/LocalStrings_pt_BR.properties index dbcc428ef1c72d995b9ebe1cefbaa747236abadf..86f01b35e21f78eb56c7f69794a27214679fff99 100644 --- a/src/main/java/org/olat/course/db/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/db/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Fri Jun 23 15:10:28 CEST 2017 +#Tue Sep 19 20:29:07 CEST 2017 command.new_db=Criar novo banco de dados customDb.category=Nome customDb.create=Criar diff --git a/src/main/java/org/olat/course/db/_spring/coursedbContext.xml b/src/main/java/org/olat/course/db/_spring/coursedbContext.xml index 6733896f7440456af9f6a1811e5cfa94cd582326..d029724eb790ba0ec92ffdcb0dce3e58a8eafe4d 100644 --- a/src/main/java/org/olat/course/db/_spring/coursedbContext.xml +++ b/src/main/java/org/olat/course/db/_spring/coursedbContext.xml @@ -7,8 +7,6 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - - <context:component-scan base-package="org.olat.course.db.impl" /> <bean id="courseDbWebService" class="org.olat.course.db.restapi.CourseDbWebService" /> diff --git a/src/main/java/org/olat/course/editor/_content/nodeedit.html b/src/main/java/org/olat/course/editor/_content/nodeedit.html index c353c21238043b3b2657c5e9ef6357c1da6ecf59..4e10bae34247577732189cb3907b79d4e38598a3 100644 --- a/src/main/java/org/olat/course/editor/_content/nodeedit.html +++ b/src/main/java/org/olat/course/editor/_content/nodeedit.html @@ -14,14 +14,14 @@ <div class="o_block"> $r.translate("nodeEdit.extLink"): <div class="o_copy_code o_nowrap"> - <a href="javascript:;" id="o_extlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"></i></a> - ${extLink} + <a href="javascript:;" id="o_extlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"> </i></a> + <input type="text" value="$extLink" onclick="this.select()"/> </div> </div> <div class="o_block"> $r.translate("nodeEdit.intLink"): <div class="o_copy_code o_nowrap"> - ${intLink} + <input type="text" value="$intLink" onclick="this.select()"/> </div> </div> #o_togglebox_end() diff --git a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties index 90c8fb87135087d131e50645f8d28ff903a82fc5..189b9908f8acc928b4e0ec4ffd33846e189137da 100644 --- a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties @@ -479,7 +479,7 @@ publish.step.title.messages=Hinweise publish.step.update.title=Hintergrund Aktualisierung publish.title=Publizieren der \u00C4nderungen von Kursbausteinen publish.update.description=W\u00E4hrend der Publikation m\u00FCssen die folgenden Hintergrundprozesse ausgef\u00FChrt werden um die Datenkonsistenz sicherzustellen. Dieser Prozess kann einige Zeit dauern. Bitte warten Sie mit der Fertigstellung der Publikation bis Sie eine entsprechende R\u00FCckmeldung erhalten haben. -publish.update.nothing=Es gibt keine die eine Aktualisierung brauchte. +publish.update.nothing=Es gibt keine Kursbausteine, die aktualisiert wurden. publish.withwarnings=Warnung publish.wizard.title=Publizieren published.latest=Der Kurs wurde zuletzt am {0} publiziert. diff --git a/src/main/java/org/olat/course/highscore/manager/HighScoreManager.java b/src/main/java/org/olat/course/highscore/manager/HighScoreManager.java index 5e790b6963e5bece6ecdde48a102ced589e2db0a..c88f89c156c4b18a4457be3ee10521b3160e923a 100644 --- a/src/main/java/org/olat/course/highscore/manager/HighScoreManager.java +++ b/src/main/java/org/olat/course/highscore/manager/HighScoreManager.java @@ -32,6 +32,7 @@ import org.olat.course.highscore.model.HighScoreRankingResults; import org.olat.course.highscore.ui.HighScoreTableEntry; import org.olat.modules.assessment.AssessmentEntry; import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** @@ -44,6 +45,9 @@ public class HighScoreManager { private static final OLog log = Tracing.createLoggerFor(HighScoreManager.class); + @Autowired + private UserManager userManager; + /** * Sort rank by score, then by id and last alphabetically, * determine rank of each member dependent on score, @@ -52,7 +56,7 @@ public class HighScoreManager { public HighScoreRankingResults sortRankByScore (List<AssessmentEntry> assessEntries, List<HighScoreTableEntry> allMembers, List<HighScoreTableEntry> ownIdMembers, List<List<HighScoreTableEntry>> allPodium, List<Integer> ownIdIndices, - int tableSize, Identity ownIdentity, UserManager userManager){ + int tableSize, Identity ownIdentity){ HighScoreTableEntry ownTableEntry = null; @@ -118,10 +122,17 @@ public class HighScoreManager { double min = Math.floor(Arrays.stream(scores).min().getAsDouble()); double range = max - min; // use original scores if range is too small else convert results to fit histogram - if (range <= 20) { + if (range <= 20 && range <0) { classwidth = 1; return new HighScoreRankingResults(scores, classwidth, min); } else { + if(lowerBorder == null) { + lowerBorder = 0f; + } + if(upperBorder == null) { + upperBorder = (float)max; + } + // decrease amount of possible classes to avoid overlapping of large numbers(condition) on x-axis boolean largeNumbers = range > 100d || max >= 1000d; int maxnumberofclasses = largeNumbers ? 12 : 20; diff --git a/src/main/java/org/olat/course/highscore/ui/HighScoreRunController.java b/src/main/java/org/olat/course/highscore/ui/HighScoreRunController.java index 0838e0f6ea468e7c63b3764afa4d4742258bb9c6..937d6717e3ca5d0db7b53b13530a0d23f3aae2c1 100644 --- a/src/main/java/org/olat/course/highscore/ui/HighScoreRunController.java +++ b/src/main/java/org/olat/course/highscore/ui/HighScoreRunController.java @@ -182,7 +182,7 @@ public class HighScoreRunController extends FormBasicController{ // compute ranking and order highscoreDataModel = highScoreManager.sortRankByScore(assessEntries, allMembers, ownIdMembers, - allPodium, ownIdIndices, tableSize, ownIdentity, userManager); + allPodium, ownIdIndices, tableSize, ownIdentity); allScores = highscoreDataModel.getScores(); diff --git a/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_en.properties index 988c2930ecb909434426ad58108638dae9659107..eaa0ee3fe12e7fd8d3f32df5cb9171344c3c636e 100644 --- a/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/highscore/ui/_i18n/LocalStrings_en.properties @@ -1,38 +1,39 @@ -#Mon Aug 15 11:26:04 CET 2016 -highscore.error.noselection=Please activate at least one of the available display options -highscore.table.header1=Rank -highscore.table.header2=Score -highscore.table.header3=Name -graph.axis.points=Points -graph.axis.percent=Percent +#Mon Jul 17 21:15:58 CEST 2017 +controller.title=HighScore Settings of your Course Element +datestart.toearly=Please choose a starting date in the future. +example.date=(Example\: 06/26/2016 10\:28) graph.axis.absolute=Absolute -highscore.title=Highscore +graph.axis.percent=Percent +graph.axis.points=Points +highscore.all=all +highscore.anonymize=Anonymize user names +highscore.anonymous=Anonymous +highscore.bestonly=show top users +highscore.datestart=Starting Date (optional) highscore.description=Create a HighScore for this Course Element. Define whether to display the "Podium", the "Histogram" and/or the "Listing". -controller.title=HighScore Settings of your Course Element -pane.tab.highscore=HighScore -highscore.position=Congratulations title -highscore.position.congratulation=Congratulations -highscore.position.yourposition=You are on position {0}! -highscore.position.inrelation={0} participants have performed below your score! -highscore.podium=Podium +highscore.emptycheck=This Textfield must not be empty\! +highscore.error.noselection=Please activate at least one of the available display options +highscore.further=more highscore.histogram=Histogram highscore.listing=Top results listing +highscore.podium=Podium +highscore.position=Congratulations title +highscore.position.congratulation=Congratulations +highscore.position.inrelation={0} participants have performed below your score\! +highscore.position.yourposition=You are on position {0}\! highscore.runtime=Runtime highscore.show=Show Highscore -highscore.all=all -highscore.bestonly=show top users -highscore.void= +highscore.table.header1=Rank +highscore.table.header2=Score +highscore.table.header3=Name highscore.tablesize=Number of top users -highscore.anonymous=Anonymous -highscore.anonymize=Anonymize user names -highscore.emptycheck=This Textfield must not be empty! -integerelement.toosmall=Your entry is too small, please verify that your entry is between 1 and 100000! -integerelement.toobig=Your entry is too large, please verify that your entry is between 1 and 100000! -integerelement.noint=Your input is not a number, please verify that your entry is between 1 and 100000! -highscore.datestart=Starting Date (optional) -datestart.toearly=Please choose a starting date in the future. -example.date=(Example: 06/26/2016 10:28) -valid.date=This Date format is not valid. -highscore.further=more +highscore.title=Highscore highscore.total=total highscore.unavail=not occupied +highscore.void= +integerelement.noint=Your input is not a number, please verify that your entry is between 1 and 100000\! +integerelement.toobig=Your entry is too large, please verify that your entry is between 1 and 100000\! +integerelement.toosmall=Your entry is too small, please verify that your entry is between 1 and 100000\! +option.show=Show +pane.tab.highscore=HighScore +valid.date=This Date format is not valid. diff --git a/src/main/java/org/olat/course/nodes/AssessableCourseNode.java b/src/main/java/org/olat/course/nodes/AssessableCourseNode.java index 96b40f918ec3871c26001549f1c06870bb65327d..cc9b95237d11ff763aec20a31268088fad021183 100644 --- a/src/main/java/org/olat/course/nodes/AssessableCourseNode.java +++ b/src/main/java/org/olat/course/nodes/AssessableCourseNode.java @@ -1,4 +1,5 @@ /** + * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> @@ -38,6 +39,7 @@ import org.olat.course.run.scoring.AssessmentEvaluation; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; /** @@ -183,7 +185,7 @@ public interface AssessableCourseNode extends CourseNode { * @param userCourseEnvironment * @param coachingIdentity */ - public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, boolean incrementAttempts); + public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, boolean incrementAttempts, Role doneBy); /** * Updates the user comment for this node and this user. This comment is visible to the user. * @param userComment @@ -214,14 +216,23 @@ public interface AssessableCourseNode extends CourseNode { * Increments the users attempts for this node and this user + 1. * @param userCourseEnvironment */ - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment); + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role doneBy); /** * Updates the users attempts for this node and this user. * @param userAttempts * @param userCourseEnvironment * @param coachingIdentity */ - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity); + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role doneBy); + + /** + * + * @param userCourseEnvironment The user course environment of the assessed identity + * @param identity The identity which do the action + * @param doneBy The role of the identity which do the action + */ + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role doneBy); + /** * Updates the coach comment for this node and this user. This comment is not visible to the user. * @param coachComment @@ -234,5 +245,4 @@ public interface AssessableCourseNode extends CourseNode { */ public boolean hasStatusConfigured(); - } diff --git a/src/main/java/org/olat/course/nodes/BCCourseNode.java b/src/main/java/org/olat/course/nodes/BCCourseNode.java index 771e66834509e76cb917fd118ca8103a4d917610..8ecc7c80ffea374de4bd24727f2f34b8231bdef7 100644 --- a/src/main/java/org/olat/course/nodes/BCCourseNode.java +++ b/src/main/java/org/olat/course/nodes/BCCourseNode.java @@ -246,6 +246,16 @@ public class BCCourseNode extends AbstractAccessableCourseNode { FileUtils.copyDirContentsToDir(fFolderNodeData, fFolderNodeDir, true, "import course node"); } + @Override + public CourseNode createInstanceForCopy(boolean isNewTitle, ICourse course, Identity author) { + CourseNode node = super.createInstanceForCopy(isNewTitle, course, author); + if(node.getModuleConfiguration().getBooleanSafe(BCCourseNodeEditController.CONFIG_AUTO_FOLDER)){ + File fFolderNodeDir = new File(FolderConfig.getCanonicalRoot() + getFoldernodePathRelToFolderBase(course.getCourseEnvironment(), node)); + fFolderNodeDir.mkdirs(); + } + return node; + } + /** * @see org.olat.course.nodes.GenericCourseNode#calcAccessAndVisibility(org.olat.course.condition.interpreter.ConditionInterpreter, * org.olat.course.run.userview.NodeEvaluation) diff --git a/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java b/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java index 94be6c47481b7f3a74b74b4f16dea63b070aa606..834bfa711e3b8f8baba498f1cdb0408f94d9f055 100644 --- a/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java +++ b/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java @@ -61,6 +61,7 @@ import org.olat.ims.lti.LTIManager; import org.olat.ims.lti.ui.LTIResultDetailsController; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import org.olat.resource.OLATResource; @@ -126,7 +127,6 @@ public class BasicLTICourseNode extends AbstractAccessableCourseNode implements UserCourseEnvironment userCourseEnv, NodeEvaluation ne, String nodecmd) { updateModuleConfigDefaults(false); - ModuleConfiguration config = getModuleConfiguration(); Controller runCtrl; if(userCourseEnv.isCourseReadOnly()) { Translator trans = Util.createPackageTranslator(BasicLTICourseNode.class, ureq.getLocale()); @@ -136,11 +136,7 @@ public class BasicLTICourseNode extends AbstractAccessableCourseNode implements } else { Roles roles = ureq.getUserSession().getRoles(); if (roles.isGuestOnly()) { - boolean assessable = config.getBooleanSafe(BasicLTICourseNode.CONFIG_KEY_HAS_SCORE_FIELD, false); - boolean sendName = config.getBooleanSafe(LTIConfigForm.CONFIG_KEY_SENDNAME, false); - boolean sendEmail = config.getBooleanSafe(LTIConfigForm.CONFIG_KEY_SENDEMAIL, false); - boolean customValues = StringHelper.containsNonWhitespace(config.getStringValue(LTIConfigForm.CONFIG_KEY_CUSTOM)); - if(assessable || sendName || sendEmail || customValues) { + if(isGuestAllowed()) { Translator trans = Util.createPackageTranslator(BasicLTICourseNode.class, ureq.getLocale()); String title = trans.translate("guestnoaccess.title"); String message = trans.translate("guestnoaccess.message"); @@ -155,6 +151,15 @@ public class BasicLTICourseNode extends AbstractAccessableCourseNode implements Controller ctrl = TitledWrapperHelper.getWrapper(ureq, wControl, runCtrl, this, "o_lti_icon"); return new NodeRunConstructionResult(ctrl); } + + public boolean isGuestAllowed() { + ModuleConfiguration config = getModuleConfiguration(); + boolean assessable = config.getBooleanSafe(BasicLTICourseNode.CONFIG_KEY_HAS_SCORE_FIELD, false); + boolean sendName = config.getBooleanSafe(LTIConfigForm.CONFIG_KEY_SENDNAME, false); + boolean sendEmail = config.getBooleanSafe(LTIConfigForm.CONFIG_KEY_SENDEMAIL, false); + boolean customValues = StringHelper.containsNonWhitespace(config.getStringValue(LTIConfigForm.CONFIG_KEY_CUSTOM)); + return !assessable && !sendName && !sendEmail && !customValues; + } /** * @see org.olat.course.nodes.GenericCourseNode#createPreviewController(org.olat.core.gui.UserRequest, @@ -431,11 +436,11 @@ public class BasicLTICourseNode extends AbstractAccessableCourseNode implements @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts, by); } @Override @@ -466,20 +471,27 @@ public class BasicLTICourseNode extends AbstractAccessableCourseNode implements } @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.incrementNodeAttempts(this, mySelf, userCourseEnvironment); + am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by); } @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { if (userAttempts != null) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts); + am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts, by); } } + + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) { + AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by); + } @Override public void updateUserCoachComment(String coachComment, UserCourseEnvironment userCourseEnvironment) { diff --git a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java index 1b9dfde7da6e7c24f597a61f70f6fe51e6cee419..b703c36ee03ce9b7baaca193463ec1c8ca227f61 100644 --- a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java +++ b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java @@ -77,6 +77,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; /** @@ -396,10 +397,10 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements */ @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts, by); } /** @@ -456,7 +457,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements * org.olat.core.id.Identity) */ @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { throw new OLATRuntimeException(CheckListCourseNode.class, "Attempts variable can't be updated in ST nodes", null); } @@ -464,9 +465,16 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment) */ @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { throw new OLATRuntimeException(CheckListCourseNode.class, "Attempts variable can't be updated in ST nodes", null); } + + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) { + AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by); + } /** * @see org.olat.course.nodes.AssessableCourseNode#getDetailsEditController(org.olat.core.gui.UserRequest, @@ -588,22 +596,25 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements * @param userCourseEnv * @param assessedIdentity */ - public void updateScoreEvaluation(Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity) { + public void updateScoreEvaluation(Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity, Role by) { ModuleConfiguration config = getModuleConfiguration(); Boolean sum = (Boolean)config.get(CheckListCourseNode.CONFIG_KEY_PASSED_SUM_CHECKBOX); Float cutValue = (Float)config.get(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE); Float maxScore = (Float)config.get(MSCourseNode.CONFIG_KEY_SCORE_MAX); Boolean manualCorrection = (Boolean)config.get(CheckListCourseNode.CONFIG_KEY_PASSED_MANUAL_CORRECTION); if(cutValue != null) { - doUpdateAssessment(cutValue, maxScore, identity, assessedUserCourseEnv, assessedIdentity); + doUpdateAssessment(cutValue, maxScore, identity, assessedUserCourseEnv, assessedIdentity, by); } else if(sum != null && sum.booleanValue()) { - doUpdateAssessmentBySum(identity, assessedUserCourseEnv, assessedIdentity); + doUpdateAssessmentBySum(identity, assessedUserCourseEnv, assessedIdentity, by); } else if(manualCorrection != null && manualCorrection.booleanValue()) { - doUpdateManualAssessment(maxScore, identity, assessedUserCourseEnv, assessedIdentity); + doUpdateManualAssessment(maxScore, identity, assessedUserCourseEnv, assessedIdentity, by); + } else { + AssessmentManager am = assessedUserCourseEnv.getCourseEnvironment().getAssessmentManager(); + am.updateLastModifications(this, assessedIdentity, assessedUserCourseEnv, by); } } - private void doUpdateAssessment(Float cutValue, Float maxScore, Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity) { + private void doUpdateAssessment(Float cutValue, Float maxScore, Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity, Role by) { OLATResourceable courseOres = OresHelper .createOLATResourceableInstance("CourseModule", assessedUserCourseEnv.getCourseEnvironment().getCourseResourceableId()); @@ -621,10 +632,10 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), passed); AssessmentManager am = assessedUserCourseEnv.getCourseEnvironment().getAssessmentManager(); - am.saveScoreEvaluation(this, identity, assessedIdentity, sceval, assessedUserCourseEnv, false); + am.saveScoreEvaluation(this, identity, assessedIdentity, sceval, assessedUserCourseEnv, false, by); } - private void doUpdateAssessmentBySum(Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity) { + private void doUpdateAssessmentBySum(Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity, Role by) { OLATResourceable courseOres = OresHelper .createOLATResourceableInstance("CourseModule", assessedUserCourseEnv.getCourseEnvironment().getCourseResourceableId()); @@ -651,10 +662,10 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements ScoreEvaluation sceval = new ScoreEvaluation(score, new Boolean(passed)); AssessmentManager am = assessedUserCourseEnv.getCourseEnvironment().getAssessmentManager(); - am.saveScoreEvaluation(this, identity, assessedIdentity, sceval, assessedUserCourseEnv, false); + am.saveScoreEvaluation(this, identity, assessedIdentity, sceval, assessedUserCourseEnv, false, by); } - private void doUpdateManualAssessment(Float maxScore, Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity) { + private void doUpdateManualAssessment(Float maxScore, Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity, Role by) { OLATResourceable courseOres = OresHelper .createOLATResourceableInstance("CourseModule", assessedUserCourseEnv.getCourseEnvironment().getCourseResourceableId()); @@ -667,7 +678,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements AssessmentManager am = assessedUserCourseEnv.getCourseEnvironment().getAssessmentManager(); ScoreEvaluation currentEval = getUserScoreEvaluation(am.getAssessmentEntry(this, assessedIdentity)); ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), currentEval.getPassed()); - am.saveScoreEvaluation(this, identity, assessedIdentity, sceval, assessedUserCourseEnv, false); + am.saveScoreEvaluation(this, identity, assessedIdentity, sceval, assessedUserCourseEnv, false, by); } @Override @@ -812,7 +823,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements ScoreEvaluation scoreEval = new ScoreEvaluation(updatedScore, updatedPassed); IdentityEnvironment identityEnv = new IdentityEnvironment(assessedIdentity, null); UserCourseEnvironment uce = new UserCourseEnvironmentImpl(identityEnv, course.getCourseEnvironment()); - am.saveScoreEvaluation(this, coachIdentity, assessedIdentity, scoreEval, uce, false); + am.saveScoreEvaluation(this, coachIdentity, assessedIdentity, scoreEval, uce, false, Role.coach); } } diff --git a/src/main/java/org/olat/course/nodes/GTACourseNode.java b/src/main/java/org/olat/course/nodes/GTACourseNode.java index e1a4ccbe208f01ea78c812dbce894b51bc4d8b3b..5213e08b5eebc738960dbc1e00f9f53f86ee57af 100644 --- a/src/main/java/org/olat/course/nodes/GTACourseNode.java +++ b/src/main/java/org/olat/course/nodes/GTACourseNode.java @@ -91,6 +91,7 @@ import org.olat.group.BusinessGroup; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import org.olat.user.UserManager; @@ -126,6 +127,7 @@ public class GTACourseNode extends AbstractAccessableCourseNode implements Persi public static final String GTASK_REVISION_PERIOD = "grouptask.revision.period"; public static final String GTASK_SAMPLE_SOLUTION = "grouptask.solution"; public static final String GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER = "grouptask.solution.visible.after"; + public static final String GTASK_SAMPLE_SOLUTION_VISIBLE_ALL = "grouptask.solution.visible.all"; public static final String GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER_RELATIVE = "grouptask.solution.visible.after.relative"; public static final String GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER_RELATIVE_TO = "grouptask.solution.visible.after.relative.to"; public static final String GTASK_GRADING = "grouptask.grading"; @@ -152,6 +154,8 @@ public class GTACourseNode extends AbstractAccessableCourseNode implements Persi public static final String GTASK_SUBMISSION_TEXT = "grouptask.submission.text"; public static final String GTASK_SUBMISSION_MAIL_CONFIRMATION = "grouptask.submission.mail.confirmation"; + public static final String GTASK_MAX_REVISED_DOCS = "grouptask.max.revised.docs"; + public static final String GTASK_SOLUTIONS = "grouptask.solutions"; @@ -629,7 +633,7 @@ public class GTACourseNode extends AbstractAccessableCourseNode implements Persi } } - private void archiveNodeData(ICourse course, BusinessGroup businessGroup, TaskList taskList, String dirName, ZipOutputStream exportStream) { + public void archiveNodeData(ICourse course, BusinessGroup businessGroup, TaskList taskList, String dirName, ZipOutputStream exportStream) { ModuleConfiguration config = getModuleConfiguration(); GTAManager gtaManager = CoreSpringFactory.getImpl(GTAManager.class); @@ -949,10 +953,10 @@ public class GTACourseNode extends AbstractAccessableCourseNode implements Persi @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnv, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager(); Identity assessedIdentity = userCourseEnv.getIdentityEnvironment().getIdentity(); - am.saveScoreEvaluation(this, coachingIdentity, assessedIdentity, new ScoreEvaluation(scoreEvaluation), userCourseEnv, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, assessedIdentity, new ScoreEvaluation(scoreEvaluation), userCourseEnv, incrementAttempts, by); } @Override @@ -983,20 +987,27 @@ public class GTACourseNode extends AbstractAccessableCourseNode implements Persi } @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnv) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnv, Role by) { AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager(); Identity assessedIdentity = userCourseEnv.getIdentityEnvironment().getIdentity(); - am.incrementNodeAttempts(this, assessedIdentity, userCourseEnv); + am.updateLastModifications(this, assessedIdentity, userCourseEnv, by); } @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnv, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnv, Identity coachingIdentity, Role by) { if (userAttempts != null) { AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager(); Identity assessedIdentity = userCourseEnv.getIdentityEnvironment().getIdentity(); - am.saveNodeAttempts(this, coachingIdentity, assessedIdentity, userAttempts); + am.saveNodeAttempts(this, coachingIdentity, assessedIdentity, userAttempts, by); } } + + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) { + AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by); + } @Override public void updateUserCoachComment(String coachComment, UserCourseEnvironment userCourseEnv) { diff --git a/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java b/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java index 52f880d66bdd534002f411e0af0f8ccf81ae13dc..fee88a137f4e0510d79143d9b2f20b02ae0085fb 100644 --- a/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java +++ b/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java @@ -77,6 +77,7 @@ import org.olat.ims.qti21.manager.AssessmentTestSessionDAO; import org.olat.ims.qti21.manager.archive.QTI21ArchiveFormat; import org.olat.ims.qti21.model.QTI21StatisticSearchParams; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.modules.iq.IQManager; import org.olat.modules.iq.IQSecurityCallback; import org.olat.repository.RepositoryEntry; @@ -310,9 +311,19 @@ public class IQSELFCourseNode extends AbstractAccessableCourseNode implements Se public void importNode(File importDirectory, ICourse course, Identity owner, Locale locale, boolean withReferences) { RepositoryEntryImportExport rie = new RepositoryEntryImportExport(importDirectory, getIdent()); if(withReferences && rie.anyExportedPropertiesAvailable()) { - RepositoryHandler handler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(TestFileResource.TYPE_NAME); - RepositoryEntry re = handler.importResource(owner, rie.getInitialAuthor(), rie.getDisplayName(), - rie.getDescription(), false, locale, rie.importGetExportedFile(), null); + File file = rie.importGetExportedFile(); + RepositoryHandler handlerQTI21 = RepositoryHandlerFactory.getInstance().getRepositoryHandler(ImsQTI21Resource.TYPE_NAME); + + RepositoryEntry re; + if(handlerQTI21.acceptImport(file, "repo.zip").isValid()) { + re = handlerQTI21.importResource(owner, rie.getInitialAuthor(), rie.getDisplayName(), + rie.getDescription(), false, locale, rie.importGetExportedFile(), null); + getModuleConfiguration().set(IQEditController.CONFIG_KEY_TYPE_QTI, IQEditController.CONFIG_VALUE_QTI21); + } else { + RepositoryHandler handler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(TestFileResource.TYPE_NAME); + re = handler.importResource(owner, rie.getInitialAuthor(), rie.getDisplayName(), + rie.getDescription(), false, locale, file, null); + } IQEditController.setIQReference(re, getModuleConfiguration()); } else { IQEditController.removeIQReference(getModuleConfiguration()); @@ -393,10 +404,10 @@ public class IQSELFCourseNode extends AbstractAccessableCourseNode implements Se * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment) */ @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.incrementNodeAttempts(this, mySelf, userCourseEnvironment); + am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by); } } diff --git a/src/main/java/org/olat/course/nodes/IQSURVCourseNode.java b/src/main/java/org/olat/course/nodes/IQSURVCourseNode.java index 2b1d272d404c08d020e92e14dfcdcaa7908532a7..f8bba28e13e59c963f02bdfdddb8741478ec1b45 100644 --- a/src/main/java/org/olat/course/nodes/IQSURVCourseNode.java +++ b/src/main/java/org/olat/course/nodes/IQSURVCourseNode.java @@ -83,6 +83,7 @@ import org.olat.ims.qti21.ui.statistics.QTI21StatisticResourceResult; import org.olat.ims.qti21.ui.statistics.QTI21StatisticsSecurityCallback; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.modules.iq.IQSecurityCallback; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryImportExport; @@ -375,6 +376,7 @@ public class IQSURVCourseNode extends AbstractAccessableCourseNode implements QT * from previous node configuration version, set default to maintain * previous behaviour */ + @Override public void updateModuleConfigDefaults(boolean isNewNode) { ModuleConfiguration config = getModuleConfiguration(); if (isNewNode) { @@ -400,6 +402,7 @@ public class IQSURVCourseNode extends AbstractAccessableCourseNode implements QT /** * @see org.olat.course.nodes.AssessableCourseNode#hasAttemptsConfigured() */ + @Override public boolean hasAttemptsConfigured() { return true; } @@ -409,21 +412,21 @@ public class IQSURVCourseNode extends AbstractAccessableCourseNode implements QT * org.olat.course.run.userview.UserCourseEnvironment, * org.olat.core.id.Identity) */ - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { if (userAttempts != null) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts); + am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts, by); } } /** * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment) */ - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.incrementNodeAttempts(this, mySelf, userCourseEnvironment); + am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by); } } diff --git a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java index 2b7a9cd933e61b5e2e57e775f537304a38b86c37..727b2f00c64218b65daecf9abf171a1df4e5d954 100644 --- a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java +++ b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java @@ -1,4 +1,5 @@ /** + * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> @@ -119,6 +120,7 @@ import org.olat.ims.qti21.ui.statistics.QTI21StatisticsToolController; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.modules.iq.IQSecurityCallback; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryImportExport; @@ -210,7 +212,7 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe return new NodeRunConstructionResult(ctrl); } - private boolean isGuestAllowedForQTI21(RepositoryEntry testEntry) { + public boolean isGuestAllowedForQTI21(RepositoryEntry testEntry) { OLATResource ores = testEntry.getOlatResource(); if(ImsQTI21Resource.TYPE_NAME.equals(ores.getResourceableTypeName())) { QTI21DeliveryOptions options = CoreSpringFactory.getImpl(QTI21Service.class).getDeliveryOptions(testEntry); @@ -251,13 +253,8 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe if(ImsQTI21Resource.TYPE_NAME.equals(qtiTestEntry.getOlatResource().getResourceableTypeName())) { tools.add(new QTI21StatisticsToolController(ureq, wControl, stackPanel, courseEnv, options, this)); if(!coachCourseEnv.isCourseReadOnly()) { - RepositoryEntry courseEntry = courseEnv.getCourseGroupManager().getCourseEntry(); QTI21Service qtiService = CoreSpringFactory.getImpl(QTI21Service.class); - boolean isRunningSessions = qtiService - .isRunningAssessmentTestSession(courseEntry, getIdent(), qtiTestEntry); - if(isRunningSessions) { - tools.add(new QTI21RetrieveTestsToolController(ureq, wControl, courseEnv, options, this)); - } + tools.add(new QTI21RetrieveTestsToolController(ureq, wControl, courseEnv, options, this)); if(options.isAdmin()) { tools.add(new QTI21ResetToolController(ureq, wControl, courseEnv, options, this)); } @@ -273,13 +270,8 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe } else { tools.add(new QTI12StatisticsToolController(ureq, wControl, stackPanel, courseEnv, options, this)); - if(!coachCourseEnv.isCourseReadOnly() && options.getGroup() == null && options.getIdentities() != null && options.getIdentities().size() > 0) { - for(Identity assessedIdentity:options.getIdentities()) { - if(isQTI12TestRunning(assessedIdentity, courseEnv)) { - tools.add(new QTI12PullTestsToolController(ureq, wControl, courseEnv, options, this)); - break; - } - } + if(!coachCourseEnv.isCourseReadOnly()) { + tools.add(new QTI12PullTestsToolController(ureq, wControl, courseEnv, options, this)); } tools.add(new QTI12ExportResultsReportController(ureq, wControl, courseEnv, options, this)); } @@ -533,11 +525,11 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe */ @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); try { - am.saveScoreEvaluation(this, coachingIdentity, mySelf, scoreEvaluation, userCourseEnvironment, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, mySelf, scoreEvaluation, userCourseEnvironment, incrementAttempts, by); } catch(DBRuntimeException ex) { throw new KnownIssueException("DBRuntimeException - Row was updated or deleted...", 3570, ex); } @@ -763,6 +755,8 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe if(handlerQTI21.acceptImport(file, "repo.zip").isValid()) { re = handlerQTI21.importResource(owner, rie.getInitialAuthor(), rie.getDisplayName(), rie.getDescription(), false, locale, rie.importGetExportedFile(), null); + + getModuleConfiguration().set(IQEditController.CONFIG_KEY_TYPE_QTI, IQEditController.CONFIG_VALUE_QTI21); } else { RepositoryHandler handlerQTI = RepositoryHandlerFactory.getInstance().getRepositoryHandler(TestFileResource.TYPE_NAME); re = handlerQTI.importResource(owner, rie.getInitialAuthor(), rie.getDisplayName(), @@ -800,11 +794,11 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe * org.olat.core.id.Identity) */ @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { if (userAttempts != null) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts); + am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts, by); } } @@ -812,10 +806,17 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment) */ @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.incrementNodeAttempts(this, mySelf, userCourseEnvironment); + am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by); + } + + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) { + AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by); } /** diff --git a/src/main/java/org/olat/course/nodes/InfoCourseNode.java b/src/main/java/org/olat/course/nodes/InfoCourseNode.java index b166086cbe814796802bd32c3a11e905b7b74ea2..c32b40ad660dfe1b615baa9ac09d728b952cb3a6 100644 --- a/src/main/java/org/olat/course/nodes/InfoCourseNode.java +++ b/src/main/java/org/olat/course/nodes/InfoCourseNode.java @@ -23,8 +23,8 @@ package org.olat.course.nodes; import java.util.ArrayList; import java.util.List; -import org.olat.commons.info.manager.InfoMessageFrontendManager; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.commons.services.notifications.SubscriptionContext; diff --git a/src/main/java/org/olat/course/nodes/MSCourseNode.java b/src/main/java/org/olat/course/nodes/MSCourseNode.java index 1ae833a55b7fe787f3063474b7bea28d94ed8214..97a74ca364e46bc53eee3c0bf1ed39464ce40970 100644 --- a/src/main/java/org/olat/course/nodes/MSCourseNode.java +++ b/src/main/java/org/olat/course/nodes/MSCourseNode.java @@ -66,6 +66,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.properties.Property; import org.olat.repository.RepositoryEntry; import org.olat.resource.OLATResource; @@ -413,10 +414,10 @@ public class MSCourseNode extends AbstractAccessableCourseNode implements Persis */ @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts, by); } /** @@ -474,7 +475,7 @@ public class MSCourseNode extends AbstractAccessableCourseNode implements Persis * org.olat.core.id.Identity) */ @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { throw new OLATRuntimeException(MSCourseNode.class, "Attempts variable can't be updated in MS nodes", null); } @@ -482,9 +483,16 @@ public class MSCourseNode extends AbstractAccessableCourseNode implements Persis * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment) */ @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { throw new OLATRuntimeException(MSCourseNode.class, "Attempts variable can't be updated in MS nodes", null); } + + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) { + AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by); + } /** * @see org.olat.course.nodes.AssessableCourseNode#getDetailsEditController(org.olat.core.gui.UserRequest, diff --git a/src/main/java/org/olat/course/nodes/MembersCourseNode.java b/src/main/java/org/olat/course/nodes/MembersCourseNode.java index b6e1cd71fadbe1ac044cd28a5dadc32bb90d65bd..38fe64d061023aa83d872a2810461daaa4505217 100644 --- a/src/main/java/org/olat/course/nodes/MembersCourseNode.java +++ b/src/main/java/org/olat/course/nodes/MembersCourseNode.java @@ -34,7 +34,6 @@ import org.olat.course.ICourse; import org.olat.course.editor.CourseEditorEnv; import org.olat.course.editor.NodeEditController; import org.olat.course.editor.StatusDescription; -import org.olat.course.editor.formfragments.MembersSelectorFormFragment; import org.olat.course.nodes.info.InfoCourseNodeEditController; import org.olat.course.nodes.members.MembersCourseNodeEditController; import org.olat.course.nodes.members.MembersCourseNodeRunController; @@ -42,9 +41,7 @@ import org.olat.course.nodes.members.MembersPeekViewController; import org.olat.course.run.navigation.NodeRunConstructionResult; import org.olat.course.run.userview.NodeEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; -import org.olat.modules.IModuleConfiguration; import org.olat.modules.ModuleConfiguration; -import org.olat.modules.ModuleProperty; import org.olat.repository.RepositoryEntry; @@ -66,28 +63,29 @@ public class MembersCourseNode extends AbstractAccessableCourseNode { //Config keys public static final String CONFIG_KEY_SHOWOWNER = "showOwner"; - private static final String CONFIG_KEY_SHOWCOACHES = "showCoaches"; - private static final String CONFIG_KEY_SHOWPARTICIPANTS = "showParticpants"; + public static final String CONFIG_KEY_SHOWCOACHES = "showCoaches"; + public static final String CONFIG_KEY_SHOWPARTICIPANTS = "showParticpants"; + + public static final String CONFIG_KEY_COACHES_ALL = "members_CoachesAll"; + public static final String CONFIG_KEY_PARTICIPANTS_ALL = "members_ParticipantsAll"; - public static final String CONFIG_KEY_EMAIL_FUNCTION = "emailFunction"; public static final String CONFIG_KEY_DOWNLOAD_FUNCTION = "downloadFunction"; public static final String EMAIL_FUNCTION_ALL = "all"; public static final String EMAIL_FUNCTION_COACH_ADMIN = "coachAndAdmin"; - - public static final ModuleProperty<Boolean> CONFIG_KEY_COACHES_ALL = new ModuleProperty<Boolean>(MembersSelectorFormFragment.CONFIG_KEY_COACHES_ALL){}; - public static final ModuleProperty<Boolean> CONFIG_KEY_COACHES_COURSE = new ModuleProperty<Boolean>(MembersSelectorFormFragment.CONFIG_KEY_COACHES_COURSE, false){}; - public static final ModuleProperty<String> CONFIG_KEY_COACHES_GROUP = new ModuleProperty<String>(MembersSelectorFormFragment.CONFIG_KEY_COACHES_GROUP){}; - public static final ModuleProperty<List<Long>> CONFIG_KEY_COACHES_GROUP_ID = new ModuleProperty<List<Long>>(MembersSelectorFormFragment.CONFIG_KEY_COACHES_GROUP_ID){}; - public static final ModuleProperty<String> CONFIG_KEY_COACHES_AREA = new ModuleProperty<String>(MembersSelectorFormFragment.CONFIG_KEY_COACHES_AREA){}; - public static final ModuleProperty<List<Long>> CONFIG_KEY_COACHES_AREA_IDS = new ModuleProperty<List<Long>>(MembersSelectorFormFragment.CONFIG_KEY_COACHES_AREA_IDS){}; - public static final ModuleProperty<Boolean> CONFIG_KEY_PARTICIPANTS_ALL = new ModuleProperty<Boolean>(MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_ALL){}; - public static final ModuleProperty<Boolean> CONFIG_KEY_PARTICIPANTS_COURSE = new ModuleProperty<Boolean>(MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_COURSE){}; - public static final ModuleProperty<String> CONFIG_KEY_PARTICIPANTS_GROUP = new ModuleProperty<String>(MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_GROUP){}; - public static final ModuleProperty<List<Long>> CONFIG_KEY_PARTICIPANTS_GROUP_ID = new ModuleProperty<List<Long>>(MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_GROUP_ID){}; - public static final ModuleProperty<String> CONFIG_KEY_PARTICIPANTS_AREA = new ModuleProperty<String>(MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_AREA){}; - public static final ModuleProperty<List<Long>> CONFIG_KEY_PARTICIPANTS_AREA_ID = new ModuleProperty<List<Long>>(MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_AREA_ID){}; + public static final String CONFIG_KEY_COACHES_COURSE = "members_CourseCoaches"; + public static final String CONFIG_KEY_COACHES_GROUP = "members_GroupCoaches"; + public static final String CONFIG_KEY_COACHES_GROUP_ID = "members_GroupCoachesIds"; + public static final String CONFIG_KEY_COACHES_AREA = "members_AreaCoaches"; + public static final String CONFIG_KEY_COACHES_AREA_IDS = "members_AreaCoachesIds"; + + public static final String CONFIG_KEY_PARTICIPANTS_COURSE = "members_CourseParticipants"; + public static final String CONFIG_KEY_PARTICIPANTS_GROUP = "members_GroupParticipants"; + public static final String CONFIG_KEY_PARTICIPANTS_GROUP_ID = "members_GroupParticipantsIds"; + public static final String CONFIG_KEY_PARTICIPANTS_AREA = "members_AreaParticipants"; + public static final String CONFIG_KEY_PARTICIPANTS_AREA_ID = "members_AreaParticipantsIds"; + public MembersCourseNode() { super(TYPE); @@ -147,29 +145,13 @@ public class MembersCourseNode extends AbstractAccessableCourseNode { @Override public Controller createPeekViewRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, NodeEvaluation ne) { - return new MembersPeekViewController(ureq, wControl, userCourseEnv, this.getModuleConfiguration()); - - //TODO check if this is the desired -// updateModuleConfigDefaults(false); -// -// // Use normal view as peekview -// Controller controller; -// Roles roles = ureq.getUserSession().getRoles(); -// if (roles.isGuestOnly()) { -// Translator trans = Util.createPackageTranslator(CourseNode.class, ureq.getLocale()); -// String title = trans.translate("guestnoaccess.title"); -// String message = trans.translate("guestnoaccess.message"); -// controller = MessageUIFactory.createInfoMessage(ureq, wControl, title, message); -// } else { -// controller = new MembersCourseNodeRunController(ureq, wControl, userCourseEnv, this.getModuleConfiguration()); -// } -// return controller; + updateModuleConfigDefaults(false); + return new MembersPeekViewController(ureq, wControl, userCourseEnv, getModuleConfiguration()); } @Override public void updateModuleConfigDefaults(boolean isNewNode) { ModuleConfiguration config = getModuleConfiguration(); - IModuleConfiguration membersFrag = IModuleConfiguration.fragment("members", config); int version = config.getConfigurationVersion(); if(isNewNode){ config.setBooleanEntry(CONFIG_KEY_SHOWOWNER, false); @@ -194,11 +176,11 @@ public class MembersCourseNode extends AbstractAccessableCourseNode { } if(version < 4) { if(config.getBooleanEntry(CONFIG_KEY_SHOWCOACHES)) { - membersFrag.set(CONFIG_KEY_COACHES_ALL, true); + config.set(CONFIG_KEY_COACHES_ALL, true); config.remove(CONFIG_KEY_SHOWCOACHES); } if(config.getBooleanEntry(CONFIG_KEY_SHOWPARTICIPANTS)) { - membersFrag.set(CONFIG_KEY_PARTICIPANTS_ALL, true); + config.set(CONFIG_KEY_PARTICIPANTS_ALL, true); config.remove(CONFIG_KEY_SHOWPARTICIPANTS); } config.setConfigurationVersion(4); diff --git a/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java b/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java index 9ed76d2b34050a7d9dda6842e7b45a13b22916d7..b3886893015cab8e6a7db928279dc300b8fa6d26 100644 --- a/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java +++ b/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java @@ -63,6 +63,7 @@ import org.olat.course.run.userview.NodeEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.modules.portfolio.handler.BinderTemplateResource; import org.olat.modules.portfolio.ui.PortfolioAssessmentDetailsController; import org.olat.portfolio.EPTemplateMapResource; @@ -462,10 +463,10 @@ public class PortfolioCourseNode extends AbstractAccessableCourseNode implements @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts, by); } @Override @@ -496,21 +497,28 @@ public class PortfolioCourseNode extends AbstractAccessableCourseNode implements } @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.incrementNodeAttempts(this, mySelf, userCourseEnvironment); + am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by); } @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { if (userAttempts != null) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts); + am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts, by); } } + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) { + AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by); + } + @Override public void updateUserCoachComment(String coachComment, UserCourseEnvironment userCourseEnvironment) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); diff --git a/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java b/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java index c97c9589e4fccbbd165a8aa091478065da0f0373..80fb43e1c22d771fd765e73ccc68de9f51643b23 100644 --- a/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java +++ b/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java @@ -113,6 +113,7 @@ import org.olat.group.model.BusinessGroupReference; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.properties.Property; import org.olat.repository.RepositoryEntry; import org.olat.resource.OLATResource; @@ -623,10 +624,10 @@ public class ProjectBrokerCourseNode extends GenericCourseNode implements Persis */ @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts, by); } /** @@ -687,11 +688,11 @@ public class ProjectBrokerCourseNode extends GenericCourseNode implements Persis * org.olat.core.id.Identity) */ @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { if (userAttempts != null) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts); + am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts, by); } } @@ -699,10 +700,17 @@ public class ProjectBrokerCourseNode extends GenericCourseNode implements Persis * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment) */ @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.incrementNodeAttempts(this, mySelf, userCourseEnvironment); + am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by); + } + + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) { + AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by); } /** @@ -943,7 +951,7 @@ public class ProjectBrokerCourseNode extends GenericCourseNode implements Persis String projectBrokerTableExport = ProjectBrokerExportGenerator.createCourseResultsOverviewTable(this, course, locale); String tableExportFileName = ExportUtil.createFileNameWithTimeStamp(getShortTitle() + "-projectbroker_overview", "xls"); exportStream.putNextEntry(new ZipEntry(exportDirName + "/" + tableExportFileName)); - IOUtils.write(projectBrokerTableExport, exportStream); + IOUtils.write(projectBrokerTableExport, exportStream, "UTF-8"); exportStream.closeEntry(); } catch (IOException e) { log.error("", e); diff --git a/src/main/java/org/olat/course/nodes/STCourseNode.java b/src/main/java/org/olat/course/nodes/STCourseNode.java index 8b04afdd3d75ed4d711af09f33eb42df47329845..331a215f7eec5ba6c019154b0984006c97ebf54c 100644 --- a/src/main/java/org/olat/course/nodes/STCourseNode.java +++ b/src/main/java/org/olat/course/nodes/STCourseNode.java @@ -81,6 +81,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.tree.CourseInternalLinkTreeModel; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import org.olat.util.logging.activity.LoggingResourceable; @@ -546,7 +547,7 @@ public class STCourseNode extends AbstractAccessableCourseNode implements Calcul */ @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { throw new OLATRuntimeException(STCourseNode.class, "Score variable can't be updated in ST nodes", null); } @@ -593,7 +594,7 @@ public class STCourseNode extends AbstractAccessableCourseNode implements Calcul * org.olat.core.id.Identity) */ @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { throw new OLATRuntimeException(STCourseNode.class, "Attempts variable can't be updated in ST nodes", null); } @@ -601,10 +602,15 @@ public class STCourseNode extends AbstractAccessableCourseNode implements Calcul * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment) */ @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { throw new OLATRuntimeException(STCourseNode.class, "Attempts variable can't be updated in ST nodes", null); } + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role doneBy) { + //do nothing + } + /** * @see org.olat.course.nodes.AssessableCourseNode#getDetailsEditController(org.olat.core.gui.UserRequest, * org.olat.core.gui.control.WindowControl, diff --git a/src/main/java/org/olat/course/nodes/ScormCourseNode.java b/src/main/java/org/olat/course/nodes/ScormCourseNode.java index 23fda397e0089c4c78a08bf29a8750ca8b1e4004..ba6840066a3b01eb436bcc3d8a5c348589cbcbea 100644 --- a/src/main/java/org/olat/course/nodes/ScormCourseNode.java +++ b/src/main/java/org/olat/course/nodes/ScormCourseNode.java @@ -65,6 +65,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.fileresource.types.ScormCPFileResource; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.modules.scorm.ScormMainManager; import org.olat.modules.scorm.ScormPackageConfig; import org.olat.modules.scorm.archiver.ScormExportManager; @@ -489,10 +490,10 @@ public class ScormCourseNode extends AbstractAccessableCourseNode implements Per */ @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, mySelf, new ScoreEvaluation(scoreEvaluation), userCourseEnvironment, incrementAttempts, by); } /** @@ -591,11 +592,11 @@ public class ScormCourseNode extends AbstractAccessableCourseNode implements Per * org.olat.core.id.Identity) */ @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { if (userAttempts != null) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts); + am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts, by); } } @@ -603,10 +604,17 @@ public class ScormCourseNode extends AbstractAccessableCourseNode implements Per * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment) */ @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.incrementNodeAttempts(this, mySelf, userCourseEnvironment); + am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by); + } + + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) { + AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by); } /** diff --git a/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java b/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java index 5e9a0957567daed1ff49a388298835857d8b1c20..f2332b4da5f26f10804388bd33fba9c4b92dbf6c 100644 --- a/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java +++ b/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java @@ -26,6 +26,7 @@ package org.olat.course.nodes; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.assessment.Role; /** * @@ -56,6 +57,6 @@ public interface SelfAssessableCourseNode extends CourseNode { * Increments the users attempts for this node and this user + 1. * @param userCourseEnvironment */ - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment); + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by); } diff --git a/src/main/java/org/olat/course/nodes/TACourseNode.java b/src/main/java/org/olat/course/nodes/TACourseNode.java index b84f5a0fe4c81b2b79abd277632c6ccb585843d3..9219eae6a9e93b72a6c902d62d001ee1d4f4bffe 100644 --- a/src/main/java/org/olat/course/nodes/TACourseNode.java +++ b/src/main/java/org/olat/course/nodes/TACourseNode.java @@ -97,6 +97,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.properties.Property; import org.olat.repository.RepositoryEntry; import org.olat.resource.OLATResource; @@ -669,11 +670,11 @@ public class TACourseNode extends GenericCourseNode implements PersistentAssessa */ @Override public void updateUserScoreEvaluation(ScoreEvaluation scoreEval, UserCourseEnvironment userCourseEnvironment, - Identity coachingIdentity, boolean incrementAttempts) { + Identity coachingIdentity, boolean incrementAttempts, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); ScoreEvaluation newScoreEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(), scoreEval.getAssessmentStatus(), scoreEval.getUserVisible(), null, null); - am.saveScoreEvaluation(this, coachingIdentity, mySelf, newScoreEval, userCourseEnvironment, incrementAttempts); + am.saveScoreEvaluation(this, coachingIdentity, mySelf, newScoreEval, userCourseEnvironment, incrementAttempts, by); } /** @@ -726,11 +727,11 @@ public class TACourseNode extends GenericCourseNode implements PersistentAssessa * org.olat.core.id.Identity) */ @Override - public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) { + public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) { if (userAttempts != null) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts); + am.saveNodeAttempts(this, coachingIdentity, mySelf, userAttempts, by); } } @@ -738,10 +739,17 @@ public class TACourseNode extends GenericCourseNode implements PersistentAssessa * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment) */ @Override - public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) { + public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity(); - am.incrementNodeAttempts(this, mySelf, userCourseEnvironment); + am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by); + } + + @Override + public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) { + AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by); } /** diff --git a/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java b/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java index 9f216eaa9f290de0547f3b44b2f3405e162e04c5..1f70305942157562131820139941213ad8c5e6e1 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java +++ b/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java @@ -39,6 +39,7 @@ import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.ims.lti.ui.OutcomeMapper; +import org.olat.modules.assessment.Role; import org.olat.resource.OLATResource; import org.olat.util.logging.activity.LoggingResourceable; @@ -101,7 +102,7 @@ public class CourseNodeOutcomeMapper extends OutcomeMapper { ScoreEvaluation eval = new ScoreEvaluation(scaledScore, passed); UserCourseEnvironment userCourseEnv = getUserCourseEnvironment(course); - ltiNode.updateUserScoreEvaluation(eval, userCourseEnv, assessedId, false); + ltiNode.updateUserScoreEvaluation(eval, userCourseEnv, assessedId, false, Role.user); } return super.doUpdateResult(score); @@ -116,7 +117,7 @@ public class CourseNodeOutcomeMapper extends OutcomeMapper { Identity assessedId = getIdentity(); ScoreEvaluation eval = new ScoreEvaluation(0.0f, false); UserCourseEnvironment userCourseEnv = getUserCourseEnvironment(course); - ltiNode.updateUserScoreEvaluation(eval, userCourseEnv, assessedId, false); + ltiNode.updateUserScoreEvaluation(eval, userCourseEnv, assessedId, false, Role.user); } return super.doDeleteResult(); diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIConfigForm.java b/src/main/java/org/olat/course/nodes/basiclti/LTIConfigForm.java index 4924c2f4dbfaf89f14f5e5dbea1fd0fd32443485..4b2c6894e9f1dcc576ff561fbe1d5aaa3c5ebc04 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/LTIConfigForm.java +++ b/src/main/java/org/olat/course/nodes/basiclti/LTIConfigForm.java @@ -246,17 +246,21 @@ public class LTIConfigForm extends FormBasicController { protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("form.title"); setFormContextHelp("Other#_lti_config"); + formLayout.setElementCssClass("o_sel_lti_config_form"); thost = uifactory.addTextElement("host", "LTConfigForm.url", 255, fullURI, formLayout); + thost.setElementCssClass("o_sel_lti_config_title"); thost.setExampleKey("LTConfigForm.url.example", null); thost.setDisplaySize(64); thost.setMandatory(true); tkey = uifactory.addTextElement ("key","LTConfigForm.key", 255, key, formLayout); + tkey.setElementCssClass("o_sel_lti_config_key"); tkey.setExampleKey ("LTConfigForm.key.example", null); tkey.setMandatory(true); tpass = uifactory.addTextElement ("pass","LTConfigForm.pass", 255, pass, formLayout); + tpass.setElementCssClass("o_sel_lti_config_pass"); tpass.setExampleKey("LTConfigForm.pass.example", null); tpass.setMandatory(true); @@ -315,6 +319,7 @@ public class LTIConfigForm extends FormBasicController { String[] assessableKeys = new String[]{ "on" }; String[] assessableValues = new String[]{ "" }; isAssessableEl = uifactory.addCheckboxesHorizontal("isassessable", "assessable.label", formLayout, assessableKeys, assessableValues); + isAssessableEl.setElementCssClass("o_sel_lti_config_assessable"); isAssessableEl.addActionListener(FormEvent.ONCHANGE); if(isAssessable) { isAssessableEl.select("on", true); @@ -323,12 +328,14 @@ public class LTIConfigForm extends FormBasicController { Float scaleValue = config.getFloatEntry(BasicLTICourseNode.CONFIG_KEY_SCALEVALUE); String scaleFactor = scaleValue == null ? "1.0" : scaleValue.toString(); scaleFactorEl = uifactory.addTextElement("scale", "scaleFactor", 10, scaleFactor, formLayout); + scaleFactorEl.setElementCssClass("o_sel_lti_config_scale"); scaleFactorEl.setDisplaySize(3); scaleFactorEl.setVisible(isAssessable); Float cutValue = config.getFloatEntry(BasicLTICourseNode.CONFIG_KEY_PASSED_CUT_VALUE); String cut = cutValue == null ? "" : cutValue.toString(); cutValueEl = uifactory.addTextElement("cutvalue", "cutvalue.label", 10, cut, formLayout); + cutValueEl.setElementCssClass("o_sel_lti_config_cutval"); cutValueEl.setDisplaySize(3); cutValueEl.setVisible(isAssessable); diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java b/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java index cc9bb39db9fcd28fd083df64ffe157c9def349e0..911c792b9f3aca14f96b74f57758e96f28a9fae1 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java +++ b/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java @@ -68,6 +68,7 @@ import org.olat.ims.lti.LTIManager; import org.olat.ims.lti.ui.PostDataMapper; import org.olat.ims.lti.ui.TalkBackMapper; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.properties.Property; import org.olat.resource.OLATResource; @@ -394,7 +395,7 @@ public class LTIRunController extends BasicController { @Override public void event(UserRequest ureq, Component source, Event event) { if(source == startButton) { - courseNode.incrementUserAttempts(userCourseEnv); + courseNode.incrementUserAttempts(userCourseEnv, Role.user); openBasicLTIContent(ureq); } else if (source == acceptLink) { storeDataExchangeAcceptance(); diff --git a/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_fr.properties index 2721ad74d41dd9e06dfd7e00cfb4b00412d8c6bb..b08b932438d70e93ba62a8d90eee6cfe12da06a3 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Wed Mar 08 11:25:40 CET 2017 +#Thu Jul 06 21:30:10 CEST 2017 LTConfigForm.invalidurl=Indiquez une URL valable, svp. LTConfigForm.key=Cl\u00E9 LTConfigForm.key.example=Exemple\: jisc.ac.uk @@ -27,6 +27,10 @@ display.config.free.userprops=Utilisateur display.config.height=$org.olat.core.gui.control.generic.iframe\:height.label display.config.sendEmail=Transmettre l'adresse e-mail au fournisseur display.config.sendName=Transmettre le nom au fournisseur +display.config.skipAcceptLaunchPage=Supprimer l'agr\u00E9ment sur les donn\u00E9es personnelles transmises +display.config.skipAcceptLaunchPageConfirm=Des donn\u00E9es personelles de l'utilisateurs seront transmises \u00E0 un serveur tier. Si cette option est activ\u00E9e, les utilisateurs n'auront pas la possibilit\u00E9 d'accepter ou de refuser la transmission de ces donn\u00E9es. Souhaitez-vous activer cette option? +display.config.skipAcceptLaunchPageWarning=Certaines donn\u00E9es personnelles des utilisateurs seront transmises \u00E0 un serveur tier. Si cette option est activ\u00E9e, les utilisateurs n'ont plus la possibilit\u00E9 d'accepter ou de refuser la transmission de ces donn\u00E9es. +display.config.skipLaunchPage=D\u00E9marrer automatiquement le contenu display.config.width=Largeur d'affichage display.config.window=Affichage display.config.window.fullScreen=Montrer le module seul, masquer le LMS diff --git a/src/main/java/org/olat/course/nodes/card2brain/Card2BrainConfigController.java b/src/main/java/org/olat/course/nodes/card2brain/Card2BrainConfigController.java index d1e906f1035199ede0bf303afa4ca1cc41a555ce..bb6b93a7c7a5665602c0613cee8634f20759463e 100644 --- a/src/main/java/org/olat/course/nodes/card2brain/Card2BrainConfigController.java +++ b/src/main/java/org/olat/course/nodes/card2brain/Card2BrainConfigController.java @@ -148,7 +148,7 @@ public class Card2BrainConfigController extends FormBasicController { protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = super.validateFormLogic(ureq); - allOk &= validateFlashcardAlias(parseAlias(flashcardAliasEl.getValue())); + allOk &= validateFlashcardAlias(card2BrainManager.parseAlias(flashcardAliasEl.getValue())); allOk &= validateLogin(); // Show the preview button only when the configuration is valid. @@ -232,7 +232,7 @@ public class Card2BrainConfigController extends FormBasicController { } protected ModuleConfiguration getUpdatedConfig() { - config.set(Card2BrainCourseNode.CONFIG_FLASHCARD_ALIAS, parseAlias(flashcardAliasEl.getValue())); + config.set(Card2BrainCourseNode.CONFIG_FLASHCARD_ALIAS, card2BrainManager.parseAlias(flashcardAliasEl.getValue())); if (isPrivateLoginActivated()) { config.set(Card2BrainCourseNode.CONFIG_ENABLE_PRIVATE_LOGIN, Boolean.toString(true)); config.set(Card2BrainCourseNode.CONFIG_PRIVATE_KEY, privateKeyEl.getValue()); @@ -264,18 +264,4 @@ public class Card2BrainConfigController extends FormBasicController { return isPrivateLoginActivated; } - /** - * Parse the alias of the set of flashcards.<br> - * Remove the unnecessary part if someone inserts the whole weblink from the - * card2brain website e.g. - * https://card2brain.ch/box/20170420_02_chemie_und_werkstoffe. - * - * @param alias - * the original alias value - * @return the parsed String - */ - private String parseAlias(String alias) { - return alias.replace("https://card2brain.ch/box/", ""); - } - } diff --git a/src/main/java/org/olat/course/nodes/card2brain/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/card2brain/_i18n/LocalStrings_fr.properties new file mode 100644 index 0000000000000000000000000000000000000000..c45207e9fb4127bbee090eb707b65cf6aa004663 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/card2brain/_i18n/LocalStrings_fr.properties @@ -0,0 +1,21 @@ +#Thu Jul 06 21:12:35 CEST 2017 +condition.accessibility.title=Acc\u00E8s +edit.FlashcardHelpText=L'alias se trouve parmi les d\u00E9tails de l'indice de la carte sur card2brain . L'alias est la derni\u00E8re partie du lien internet, par exemple 20170419_das_kleine_garten_abc. +edit.KeyHelpText=La cl\u00E9 de l'API se trouve dans les configuration sur le site de card2brain. +edit.SecretHelpText=Le secret de l'API se trouve dans les configuration sur le site de card2brain. +edit.access.enablePrivateLogin=Employer l'authentification d'un compte priv\u00E9 +edit.access.privateKey=API Key +edit.access.privateSecret=API Secret +edit.flashcard.alias=Alias de la carte d'apprentissage +edit.preview=Aper\u00E7u +edit.title=Configurer la carte d'apprentissage +edit.warning.aliasCheckFailed=L'alias n'a pas pu \u00EAtre v\u00E9rifi\u00E9. Existe-t-il une carte d'apprentissage avec cet alias? +edit.warning.bothLoginDisabled=Les deux m\u00E9thodes d'authentification ont \u00E9t\u00E9 d\u00E9sactiv\u00E9es. Contactez l'administrateur s'il vous pla\u00EEt. +edit.warning.bothLoginDisabled.short=Les deux m\u00E9thodes d'authentifications ont \u00E9t\u00E9 d\u00E9sactiv\u00E9es. +edit.warning.enterpriseLoginDisabled=Cette carte d'apprentissage a \u00E9t\u00E9 configur\u00E9 avec un compte d'entreprise, mais l'authentification pour ce compte a \u00E9t\u00E9 d\u00E9sactiv\u00E9 entre temps par l'administrateur. +edit.warning.enterpriseLoginDisabled.short=L'authentification pour le compte d'entreprise a \u00E9t\u00E9 d\u00E9sactiv\u00E9. +edit.warning.privateLoginDisabled=Ces cartes d'apprentissages ont \u00E9t\u00E9 configur\u00E9 avec un compte priv\u00E9. Le compte priv\u00E9 a \u00E9t\u00E9 d\u00E9sactiv\u00E9 entre temps par l'administrateur. Sauv\u00E9 la configuration une nouvelle fois pour que le compte d'entreprise soit pris en compte. +edit.warning.privateLoginDisabled.short=Le compte priv\u00E9 a \u00E9t\u00E9 d\u00E9sactiv\u00E9. +link.text=Carte d'apprentissages card2brain +pane.tab.accessibility=Acc\u00E8s +pane.tab.vcconfig=Cartes d'apprentissage diff --git a/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityCheckListController.java b/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityCheckListController.java index fa630349f8ccef208d520e2f7c09431ecbc70c8e..21c13f09fb739240c4e8fa55b6c7d43ff1dc7779 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityCheckListController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityCheckListController.java @@ -53,6 +53,7 @@ import org.olat.course.nodes.cl.model.DBCheck; import org.olat.course.nodes.cl.model.DBCheckbox; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.springframework.beans.factory.annotation.Autowired; /** @@ -284,7 +285,7 @@ public class AssessedIdentityCheckListController extends FormBasicController { } checkboxManager.check(courseOres, courseNode.getIdent(), batchElements); - courseNode.updateScoreEvaluation(getIdentity(), assessedUserCourseEnv, assessedIdentity); + courseNode.updateScoreEvaluation(getIdentity(), assessedUserCourseEnv, assessedIdentity, Role.coach); } private void doUpdateCheck(CheckboxWrapper wrapper, boolean check) { diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java index db6a2dd96d378c5b13b1750f3b7d603531722456..c2a03d1090886de02b31c03761bbb612a8d96671 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java @@ -89,6 +89,7 @@ import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupMembership; import org.olat.group.BusinessGroupService; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryService; @@ -587,7 +588,7 @@ public class CheckListAssessmentController extends FormBasicController implement List<Identity> assessedIdentities = securityManager.loadIdentityByKeys(assessedIdentityToUpdate); for(Identity assessedIdentity:assessedIdentities) { UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course); - courseNode.updateScoreEvaluation(getIdentity(), assessedUserCourseEnv, assessedIdentity); + courseNode.updateScoreEvaluation(getIdentity(), assessedUserCourseEnv, assessedIdentity, Role.coach); } } diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java index 0859355a9947deb12c6639cd51cdb5b7af1c21cb..951a2bfd56a3bfa1d7c72358405ff7be33f4aaac 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java @@ -68,6 +68,7 @@ import org.olat.course.nodes.ms.DocumentsMapper; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.util.logging.activity.LoggingResourceable; import org.springframework.beans.factory.annotation.Autowired; @@ -324,7 +325,7 @@ public class CheckListRunController extends FormBasicController implements Contr //make sure all results is on the database before calculating some scores //manager commit already DBFactory.getInstance().commit(); - courseNode.updateScoreEvaluation(getIdentity(), userCourseEnv, getIdentity()); + courseNode.updateScoreEvaluation(getIdentity(), userCourseEnv, getIdentity(), Role.user); Checkbox checkbox = wrapper.getCheckbox(); logUpdateCheck(checkbox.getCheckboxId(), checkbox.getTitle()); diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java index 940cf1297817f80ea662d19804f70c4cc9f1d55a..6464e8061583d80e844001cda6aa46a58d1f9d16 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java @@ -67,6 +67,7 @@ import org.olat.course.nodes.cl.model.CheckboxList; import org.olat.course.nodes.cl.ui.CheckboxAssessmentDataModel.Cols; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -385,7 +386,7 @@ public class CheckboxAssessmentController extends FormBasicController { List<Identity> assessedIdentities = securityManager.loadIdentityByKeys(assessedIdentityToUpdate); for(Identity assessedIdentity:assessedIdentities) { UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course); - courseNode.updateScoreEvaluation(getIdentity(), assessedUserCourseEnv, assessedIdentity); + courseNode.updateScoreEvaluation(getIdentity(), assessedUserCourseEnv, assessedIdentity, Role.coach); } } diff --git a/src/main/java/org/olat/course/nodes/co/COConfigForm.java b/src/main/java/org/olat/course/nodes/co/COConfigForm.java index b7db6fb229984292f31bee608b9caeb466a4e5d5..12a65e42c18a01831ee71ceff188547f89c0c555 100755 --- a/src/main/java/org/olat/course/nodes/co/COConfigForm.java +++ b/src/main/java/org/olat/course/nodes/co/COConfigForm.java @@ -33,22 +33,16 @@ import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.SelectionElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; -import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; -import org.olat.core.gui.components.form.flexible.impl.IFormFragmentController; -import org.olat.core.gui.components.form.flexible.impl.IFormFragmentHost; import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit; 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.translator.Translator; import org.olat.core.util.StringHelper; -import org.olat.core.util.Util; import org.olat.core.util.mail.MailHelper; -import org.olat.course.editor.formfragments.MembersSelectorFormFragment; +import org.olat.course.nodes.members.ui.group.MembersSelectorFormFragment; import org.olat.course.run.userview.UserCourseEnvironment; -import org.olat.modules.IModuleConfiguration; import org.olat.modules.ModuleConfiguration; /** @@ -58,76 +52,89 @@ import org.olat.modules.ModuleConfiguration; * @author Felix Jost * @author Dirk Furrer */ -public class COConfigForm extends FormBasicController { +public class COConfigForm extends MembersSelectorFormFragment { private SelectionElement wantEmail; - private TextElement teArElEmailToAdresses; - private SelectionElement wantOwners; - + private TextElement teArElEmailToAdresses; private TextElement teElSubject; private TextElement teArElBody; - - // -- -// private SelectionElement wantCoaches; -// private SingleSelection coachesChoice; -// private FormLink chooseGroupCoachesLink; -// private GroupSelectionController groupChooseCoaches; -// private StaticTextElement easyGroupCoachSelectionList; -// private FormLink chooseAreasCoachesLink; -// private AreaSelectionController areaChooseCoaches; -// private StaticTextElement easyAreaCoachSelectionList; - - // -- -// private SelectionElement wantParticipants; -// private SingleSelection participantsChoice; -// private FormLink chooseGroupParticipantsLink; -// private GroupSelectionController groupChooseParticipants; -// private StaticTextElement easyGroupParticipantsSelectionList; -// private FormLink chooseAreasParticipantsLink; -// private AreaSelectionController areaChooseParticipants; -// private StaticTextElement easyAreaParticipantsSelectionList; - // -- - - private final MembersSelectorFormFragment membersFragment; private FormItemContainer recipentsContainer; - private FormSubmit subm; - -// private CloseableModalController cmc; - - private List<String> eList; - private ModuleConfiguration config; -// private CourseEditorEnv cev; - -// @Autowired -// private BGAreaManager areaManager; -// @Autowired -// private BusinessGroupService businessGroupService; + private FormSubmit submitButton; + private List<String> eList; /** * Form constructor * * @param name The form name * @param config The module configuration - * @param withCancel true: cancel button is rendered, false: no cancel button */ - protected COConfigForm(UserRequest ureq, WindowControl wControl, ModuleConfiguration config, UserCourseEnvironment uce) { - super(ureq, wControl); - this.config = config; -// this.cev = uce.getCourseEditorEnv(); - - membersFragment = new MembersSelectorFormFragment(uce.getCourseEditorEnv()); - registerFormFragment(membersFragment); // register with parent for proper lifecycle handling - initForm(ureq); - validateFormLogic(ureq); + protected COConfigForm(UserRequest ureq, WindowControl wControl, + ModuleConfiguration config, UserCourseEnvironment uce) { + super(ureq, wControl, uce.getCourseEditorEnv(), config); + } + + @Override + protected String getConfigKeyCoachesGroup() { + return COEditController.CONFIG_KEY_EMAILTOCOACHES_GROUP; + } + + @Override + protected String getConfigKeyCoachesGroupIds() { + return COEditController.CONFIG_KEY_EMAILTOCOACHES_GROUP_ID; + } + + @Override + protected String getConfigKeyCoachesArea() { + return COEditController.CONFIG_KEY_EMAILTOCOACHES_AREA; + } + + @Override + protected String getConfigKeyCoachesAreaIds() { + return COEditController.CONFIG_KEY_EMAILTOCOACHES_AREA_IDS; + } + + @Override + protected String getConfigKeyCoachesCourse() { + return COEditController.CONFIG_KEY_EMAILTOCOACHES_COURSE; + } + + @Override + protected String getConfigKeyCoachesAll() { + return COEditController.CONFIG_KEY_EMAILTOCOACHES_ALL; + } + + @Override + protected String getConfigKeyParticipantsGroup() { + return COEditController.CONFIG_KEY_EMAILTOPARTICIPANTS_GROUP; + } + + @Override + protected String getConfigKeyParticipantsArea() { + return COEditController.CONFIG_KEY_EMAILTOPARTICIPANTS_AREA; + } + + @Override + protected String getConfigKeyParticipantsGroupIds() { + return COEditController.CONFIG_KEY_EMAILTOPARTICIPANTS_GROUP_ID; + } + + @Override + protected String getConfigKeyParticipantsAreaIds() { + return COEditController.CONFIG_KEY_EMAILTOPARTICIPANTS_AREA_ID; + } + + @Override + protected String getConfigKeyParticipantsCourse() { + return COEditController.CONFIG_KEY_EMAILTOPARTICIPANTS_COURSE; } @Override - public void storeFormData(UserRequest ureq) { - membersFragment.storeConfiguration(ureq, IModuleConfiguration.fragment("emailTo", "", config)); + protected String getConfigKeyParticipantsAll() { + return COEditController.CONFIG_KEY_EMAILTOPARTICIPANTS_ALL; } /** @@ -137,7 +144,7 @@ public class COConfigForm extends FormBasicController { protected boolean validateFormLogic(UserRequest ureq) { boolean isOK = true; - if (!membersFragment.sendToCoaches() && !membersFragment.sendToPartips() && !wantEmail.isSelected(0) && !sendToOwners()) { + if (!sendToCoaches() && !sendToPartips() && !wantEmail.isSelected(0) && !sendToOwners()) { recipentsContainer.setErrorKey("no.recipents.specified", null); isOK = false; } @@ -174,13 +181,8 @@ public class COConfigForm extends FormBasicController { } } - return isOK - & membersFragment.validateFormLogic(ureq) - & super.validateFormLogic(ureq); + return isOK & super.validateFormLogic(ureq); } - - - /** * @return the message subject @@ -207,53 +209,23 @@ public class COConfigForm extends FormBasicController { return wantOwners.isSelected(0); } - @Override - protected void formOK(UserRequest ureq) { - fireEvent (ureq, Event.DONE_EVENT); - } - - @Override - public IFormFragmentHost getFragmentHostInterface() { - return new IFormFragmentHost() { - final Translator parent = COConfigForm.this.getTranslator(); - final Translator delegate = Util.createPackageTranslator(MembersSelectorFormFragment.class, parent.getLocale(), parent); - final IFormFragmentController adapter = IFormFragmentController.fragmentControllerAdapter(COConfigForm.this, canSubmit -> { - subm.setEnabled(canSubmit); - }); - - @Override - public Translator getFragmentTranslator() { - return delegate; - } - - @Override - public IFormFragmentController getFragmentController() { - return adapter; - } - }; - } - @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { Boolean ownerSelection = config.getBooleanSafe(COEditController.CONFIG_KEY_EMAILTOOWNERS); -// Boolean coacheSelection = config.getBooleanSafe(COEditController.CONFIG_KEY_EMAILTOCOACHES_ALL) || config.getBooleanSafe(COEditController.CONFIG_KEY_EMAILTOCOACHES_COURSE) || config.get(COEditController.CONFIG_KEY_EMAILTOCOACHES_GROUP) != null || config.get(COEditController.CONFIG_KEY_EMAILTOCOACHES_AREA) != null; - setFormTitle("header", null); setFormContextHelp("Administration and Organisation#_mail"); //for displaying error message in case neither group stuff nor email is selected - recipentsContainer = FormLayoutContainer.createHorizontalFormLayout( - "recipents", getTranslator() - ); - formLayout.add(recipentsContainer); + recipentsContainer = FormLayoutContainer.createHorizontalFormLayout("recipents", getTranslator()); + formLayout.add(recipentsContainer); wantEmail = uifactory.addCheckboxesHorizontal("wantEmail", "message.want.email", formLayout, new String[]{"xx"}, new String[]{null}); wantEmail.addActionListener(FormEvent.ONCLICK); // External recipients - eList = (List<String>) config.get(COEditController.CONFIG_KEY_EMAILTOADRESSES); + eList = config.getList(COEditController.CONFIG_KEY_EMAILTOADRESSES, String.class); String emailToAdresses = ""; if (eList != null) { emailToAdresses = StringHelper.formatIdentitesAsEmailToString(eList, "\n"); @@ -271,8 +243,7 @@ public class COConfigForm extends FormBasicController { wantOwners.addActionListener(FormEvent.ONCLICK); // include existing fragment - IModuleConfiguration emailToFrag = IModuleConfiguration.fragment("emailTo", "", config); - membersFragment.initFormFragment(ureq, this, this, emailToFrag); + super.initForm(formLayout, listener, ureq); //subject String mS = (String) config.get(COEditController.CONFIG_KEY_MSUBJECT_DEFAULT); @@ -284,14 +255,13 @@ public class COConfigForm extends FormBasicController { String mBody = (mB != null) ? mB : ""; teArElBody = uifactory.addRichTextElementForStringDataMinimalistic("mBody", "message.body", mBody, 8, 60, formLayout, getWindowControl()); - subm = uifactory.addFormSubmitButton("save", formLayout); - - + submitButton = uifactory.addFormSubmitButton("save", formLayout); update(); } - private void update () { - membersFragment.refreshContents(); + @Override + protected void update() { + super.update(); teArElEmailToAdresses.setVisible(wantEmail.isSelected(0)); teArElEmailToAdresses.clearError(); @@ -306,23 +276,28 @@ public class COConfigForm extends FormBasicController { @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { - /*boolean processed = */this.membersFragment.processFormEvent(ureq, source, event); - + super.formInnerEvent(ureq, source, event); update(); } @Override protected void event(UserRequest ureq, Controller source, Event event) { - subm.setEnabled(true); - + submitButton.setEnabled(true); // the parent takes care of dealing with fragments super.event(ureq, source, event); - } @Override - protected void doDispose() { - membersFragment.dispose(); + protected void setFormCanSubmit(boolean enable) { + submitButton.setEnabled(enable); + } + + @Override + protected void storeConfiguration(ModuleConfiguration config) { + super.storeConfiguration(config); + config.setBooleanEntry(COEditController.CONFIG_KEY_EMAILTOOWNERS, sendToOwners()); + config.set(COEditController.CONFIG_KEY_EMAILTOADRESSES, getEmailList()); + config.set(COEditController.CONFIG_KEY_MSUBJECT_DEFAULT, getMSubject()); + config.set(COEditController.CONFIG_KEY_MBODY_DEFAULT, getMBody()); } - } \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/co/COEditController.java b/src/main/java/org/olat/course/nodes/co/COEditController.java index 549c22741698ef34e74202cc019a8899b65a1249..ddd43b22e0998f521d72da251f28d88d7379c6b1 100755 --- a/src/main/java/org/olat/course/nodes/co/COEditController.java +++ b/src/main/java/org/olat/course/nodes/co/COEditController.java @@ -27,7 +27,6 @@ package org.olat.course.nodes.co; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.panel.Panel; import org.olat.core.gui.components.tabbedpane.TabbedPane; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Controller; @@ -40,7 +39,6 @@ import org.olat.course.assessment.AssessmentHelper; import org.olat.course.condition.Condition; import org.olat.course.condition.ConditionEditController; import org.olat.course.editor.NodeEditController; -import org.olat.course.editor.formfragments.MembersSelectorFormFragment; import org.olat.course.nodes.COCourseNode; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; @@ -66,29 +64,29 @@ public class COEditController extends ActivateableTabbableDefaultController impl public static final String CONFIG_KEY_EMAILTOGROUPS = "emailToGroups"; /** config key: to email addresses to be extracted from specified learn areas */ - public static final String CONFIG_KEY_EMAILTOCOACHES_AREA = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_COACHES_AREA; + public static final String CONFIG_KEY_EMAILTOCOACHES_AREA = "emailTo" + "AreaCoaches"; /** config key: to email addresses to be extracted from specified learn areas */ - public static final String CONFIG_KEY_EMAILTOCOACHES_AREA_IDS = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_COACHES_AREA_IDS; + public static final String CONFIG_KEY_EMAILTOCOACHES_AREA_IDS = "emailTo" + "AreaCoachesIds"; /** config key: keys of the course participants list */ - public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_ALL = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_ALL; + public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_ALL = "emailTo" + "ParticipantsAll"; /** config key: keys of the group participants list */ - public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_GROUP_ID = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_GROUP_ID; + public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_GROUP_ID = "emailTo" + "GroupParticipantsIds"; /** config key: email goes to group participants */ - public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_GROUP = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_GROUP; - public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_AREA_ID = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_AREA_ID; + public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_GROUP = "emailTo" + "GroupParticipants"; + public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_AREA_ID = "emailTo" + "AreaParticipantsIds"; /** config key: email goes to group participants */ - public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_AREA = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_AREA; + public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_AREA = "emailTo" + "AreaParticipants"; /** config key: email goes to course participants */ - public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_COURSE = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_PARTICIPANTS_COURSE; + public static final String CONFIG_KEY_EMAILTOPARTICIPANTS_COURSE = "emailTo" + "CourseParticipants"; /** config key: email goes to group coaches */ - public static final String CONFIG_KEY_EMAILTOCOACHES_GROUP = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_COACHES_GROUP; + public static final String CONFIG_KEY_EMAILTOCOACHES_GROUP = "emailTo" + "GroupCoaches"; /** config key: key of the group coaches list */ - public static final String CONFIG_KEY_EMAILTOCOACHES_GROUP_ID = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_COACHES_GROUP_ID; + public static final String CONFIG_KEY_EMAILTOCOACHES_GROUP_ID = "emailTo" + "GroupCoachesIds"; /** config key: key of the course coaches list */ - public static final String CONFIG_KEY_EMAILTOCOACHES_ALL = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_COACHES_ALL; + public static final String CONFIG_KEY_EMAILTOCOACHES_ALL = "emailTo" + "CoachesAll"; /** config key: email goes to course coaches */ - public static final String CONFIG_KEY_EMAILTOCOACHES_COURSE = "emailTo" + MembersSelectorFormFragment.CONFIG_KEY_COACHES_COURSE; + public static final String CONFIG_KEY_EMAILTOCOACHES_COURSE = "emailTo" + "CourseCoaches"; /** config key: email goes to course owners */ public static final String CONFIG_KEY_EMAILTOOWNERS = "emailToOwners"; /** config key: email goes to email address */ @@ -98,9 +96,7 @@ public class COEditController extends ActivateableTabbableDefaultController impl /** config key: default body text */ public static final String CONFIG_KEY_MBODY_DEFAULT = "mBodyDefault"; - private ModuleConfiguration moduleConfiguration; private final VelocityContainer myContent; - private Panel main; private COConfigForm configForm; private COCourseNode courseNode; private ConditionEditController accessibilityCondContr; @@ -116,16 +112,12 @@ public class COEditController extends ActivateableTabbableDefaultController impl */ public COEditController(ModuleConfiguration config, UserRequest ureq, WindowControl wControl, COCourseNode coCourseNode, ICourse course, UserCourseEnvironment euce) { super(ureq,wControl); - this.moduleConfiguration = config; this.courseNode = coCourseNode; - - main = new Panel("coeditpanel"); - + myContent = createVelocityContainer("edit"); configForm = new COConfigForm(ureq, wControl, config, euce); configForm.addControllerListener(this); - myContent.put("configForm", configForm.getInitialComponent()); // not needed: setInitialComponent(myContent); @@ -134,8 +126,6 @@ public class COEditController extends ActivateableTabbableDefaultController impl accessibilityCondContr = new ConditionEditController(ureq, getWindowControl(), euce, accessCondition, AssessmentHelper.getAssessableNodes(course.getEditorTreeModel(), coCourseNode)); listenTo(accessibilityCondContr); - - main.setContent(myContent); } /** @@ -160,32 +150,8 @@ public class COEditController extends ActivateableTabbableDefaultController impl } } else if (source == configForm) { // those must be links - if (event == Event.CANCELLED_EVENT) { - return; - } else if (event == Event.DONE_EVENT) { - this.configForm.storeFormData(ureq); - -// moduleConfiguration.set(CONFIG_KEY_EMAILTOCOACHES_GROUP, configForm.getEmailGroupCoaches()); -// moduleConfiguration.set(CONFIG_KEY_EMAILTOCOACHES_AREA, configForm.getEmailCoachesAreas()); -// moduleConfiguration.set(CONFIG_KEY_EMAILTOCOACHES_GROUP_ID, configForm.getEmailGroupCoachesIds()); -// moduleConfiguration.set(CONFIG_KEY_EMAILTOCOACHES_AREA_IDS, configForm.getEmailCoachesAreaIds()); -// moduleConfiguration.setBooleanEntry(CONFIG_KEY_EMAILTOCOACHES_ALL, configForm.sendToCoachesAll()); -// moduleConfiguration.setBooleanEntry(CONFIG_KEY_EMAILTOCOACHES_COURSE, configForm.sendToCoachesCourse()); - -// moduleConfiguration.set(CONFIG_KEY_EMAILTOPARTICIPANTS_GROUP, configForm.getEmailGroupParticipants()); -// moduleConfiguration.set(CONFIG_KEY_EMAILTOPARTICIPANTS_GROUP_ID, configForm.getEmailGroupParticipantsIds()); -// moduleConfiguration.set(CONFIG_KEY_EMAILTOPARTICIPANTS_AREA, configForm.getEmailParticipantsAreas()); -// moduleConfiguration.set(CONFIG_KEY_EMAILTOPARTICIPANTS_AREA_ID, configForm.getEmailParticipantsAreaIds()); -// moduleConfiguration.setBooleanEntry(CONFIG_KEY_EMAILTOPARTICIPANTS_COURSE, configForm.sendToParticipantsCourse()); -// moduleConfiguration.setBooleanEntry(CONFIG_KEY_EMAILTOPARTICIPANTS_ALL, configForm.sendToParticipantsAll()); - - moduleConfiguration.setBooleanEntry(CONFIG_KEY_EMAILTOOWNERS, configForm.sendToOwners()); - moduleConfiguration.set(CONFIG_KEY_EMAILTOADRESSES, configForm.getEmailList()); - moduleConfiguration.set(CONFIG_KEY_MSUBJECT_DEFAULT, configForm.getMSubject()); - moduleConfiguration.set(CONFIG_KEY_MBODY_DEFAULT, configForm.getMBody()); - + if (event == Event.DONE_EVENT) { fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); - return; } } } diff --git a/src/main/java/org/olat/course/nodes/en/ENRunController.java b/src/main/java/org/olat/course/nodes/en/ENRunController.java index e27501393b8992dece36d71073bbdfb9de03e6a1..661e52ec47ff9c79239cfd8c3da638f4bc46ae15 100644 --- a/src/main/java/org/olat/course/nodes/en/ENRunController.java +++ b/src/main/java/org/olat/course/nodes/en/ENRunController.java @@ -79,14 +79,14 @@ import org.springframework.beans.factory.annotation.Autowired; * @author Felix Jost, gnaegi */ public class ENRunController extends BasicController implements GenericEventListener { - + private static final OLog log = Tracing.createLoggerFor(ENRunController.class); private static final String CMD_VISIT_CARD = "cmd.visit.card"; private static final String CMD_ENROLL_IN_GROUP = "cmd.enroll.in.group"; private static final String CMD_ENROLLED_CANCEL = "cmd.enrolled.cancel"; - - + + private ModuleConfiguration moduleConfig; private List<Long> enrollableGroupKeys; private List<Long> enrollableAreaKeys; @@ -109,10 +109,10 @@ public class ENRunController extends BasicController implements GenericEventList private boolean cancelEnrollEnabled; private int maxEnrollCount; - + //registered in event bus private List<Long> registeredGroupKeys; - + /** * @param moduleConfiguration * @param ureq @@ -123,7 +123,7 @@ public class ENRunController extends BasicController implements GenericEventList public ENRunController(ModuleConfiguration moduleConfiguration, UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, ENCourseNode enNode) { super(ureq, wControl); - + this.moduleConfig = moduleConfiguration; this.enNode = enNode; this.userCourseEnv = userCourseEnv; @@ -158,7 +158,7 @@ public class ENRunController extends BasicController implements GenericEventList Stats stats = groupListModel.getStats(); tableCtr = createTableController(ureq, stats.isSomeGroupWaitingListEnabled()); tableCtr.setTableDataModel(groupListModel); - + doEnrollView(stats); // push title and learning objectives, only visible on intro page @@ -170,9 +170,9 @@ public class ENRunController extends BasicController implements GenericEventList if (learningObj != null) { Component learningObjectives = ObjectivesHelper.createLearningObjectivesComponent(learningObj, ureq); enrollVC.put("learningObjectives", learningObjectives); - enrollVC.contextPut("hasObjectives", learningObj); // dummy value, just an exists operator + enrollVC.contextPut("hasObjectives", learningObj); // dummy value, just an exists operator } - + putInitialPanel (enrollVC); } @@ -188,7 +188,7 @@ public class ENRunController extends BasicController implements GenericEventList * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) */ @Override - public void event(UserRequest ureq, Controller source, Event event) { + public void event(UserRequest ureq, Controller source, Event event) { String cmd = event.getCommand(); if (source == tableCtr) { if (cmd.equals(Table.COMMANDLINK_ROWACTION_CLICKED)) { @@ -197,15 +197,15 @@ public class ENRunController extends BasicController implements GenericEventList int rowid = te.getRowId(); EnrollmentRow row = groupListModel.getObject(rowid); Long choosenGroupKey = row.getKey(); - + if (actionid.equals(CMD_ENROLL_IN_GROUP)) { BusinessGroup choosenGroup = businessGroupService.loadBusinessGroup(choosenGroupKey); addLoggingResourceable(LoggingResourceable.wrap(choosenGroup)); - + if(log.isDebug()) { log.debug("CMD_ENROLL_IN_GROUP ureq.getComponentID()=" + ureq.getComponentID() + " ureq.getComponentTimestamp()=" + ureq.getComponentTimestamp()); } - + EnrollStatus enrollStatus = enrollmentManager.doEnroll(ureq.getIdentity(), ureq.getUserSession().getRoles(), choosenGroup, enNode, coursePropertyManager, getWindowControl(), getTranslator(), enrollableGroupKeys, enrollableAreaKeys, courseGroupManager); if (enrollStatus.isEnrolled() || enrollStatus.isInWaitingList() ) { @@ -226,7 +226,7 @@ public class ENRunController extends BasicController implements GenericEventList } else if (actionid.equals(CMD_ENROLLED_CANCEL)) { BusinessGroup choosenGroup = businessGroupService.loadBusinessGroup(choosenGroupKey); addLoggingResourceable(LoggingResourceable.wrap(choosenGroup)); - + List<String> roles = businessGroupService .getIdentityRolesInBusinessGroup(getIdentity(), choosenGroup); if (roles.contains(GroupRoles.waiting.name())) { @@ -234,7 +234,7 @@ public class ENRunController extends BasicController implements GenericEventList } else if(roles.contains(GroupRoles.participant.name())) { enrollmentManager.doCancelEnrollment(ureq.getIdentity(), choosenGroup, enNode, coursePropertyManager, getWindowControl(), getTranslator()); } - + // fire event to indicate runmaincontroller that the menuview is to update fireEvent(ureq, new BusinessGroupModifiedEvent(BusinessGroupModifiedEvent.IDENTITY_REMOVED_EVENT, choosenGroup, getIdentity())); // events are already fired BusinessGroupManager level :: BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_REMOVED_EVENT, group, ureq.getIdentity()); @@ -242,7 +242,7 @@ public class ENRunController extends BasicController implements GenericEventList doEnrollView(updateModel()); } else if(CMD_VISIT_CARD.equals(actionid)) { List<String> roles = businessGroupService.getIdentityRolesInBusinessGroup(getIdentity(), row); - + String businessPath; if(roles.contains(GroupRoles.coach.name()) || roles.contains(GroupRoles.participant.name())) { businessPath = "[BusinessGroup:" + choosenGroupKey + "]"; @@ -259,14 +259,14 @@ public class ENRunController extends BasicController implements GenericEventList public void event(Event event) { if (event instanceof OLATResourceableJustBeforeDeletedEvent) { dispose(); - } - } + } + } private void doEnrollView(Stats stats) { //num. of groups where the user is participant or in the waiting list int numOfParticipatingGroups = stats.getParticipantingGroupNames().size(); int numOfWaitingGroups = stats.getWaitingGroupNames().size(); - + enrollVC.contextPut("multiEnroll", (maxEnrollCount > 1 && numOfParticipatingGroups + numOfWaitingGroups < maxEnrollCount)); if(numOfParticipatingGroups > 0 || numOfWaitingGroups > 0){ String[] hintNumbers = new String[]{ @@ -277,32 +277,32 @@ public class ENRunController extends BasicController implements GenericEventList } else { enrollVC.contextPut("multipleHint", translate("multiple.select.hint", String.valueOf(maxEnrollCount))); } - + if (numOfParticipatingGroups > 0) { enrollVC.contextPut("isEnrolledView", Boolean.TRUE); List<String> groupnames = new ArrayList<String>(numOfParticipatingGroups); for(String groupName: stats.getParticipantingGroupNames()){ groupnames.add(StringHelper.escapeHtml(groupName)); } - enrollVC.contextPut("groupNames", groupnames); + enrollVC.contextPut("groupNames", groupnames); } else { enrollVC.contextPut("isEnrolledView", Boolean.FALSE); - } - + } + if (numOfWaitingGroups > 0){ enrollVC.contextPut("isInWaitingList", Boolean.TRUE); List<String> waitingListNames = new ArrayList<String>(numOfWaitingGroups); for(String groupName:stats.getWaitingGroupNames()){ waitingListNames.add(StringHelper.escapeHtml(groupName)); } - enrollVC.contextPut("waitingListNames", waitingListNames); + enrollVC.contextPut("waitingListNames", waitingListNames); } else { enrollVC.contextPut("isInWaitingList", Boolean.FALSE); } // 3. Add group list to view enrollVC.put("grouplisttable", tableCtr.getInitialComponent()); } - + private Stats updateModel() { List<EnrollmentRow> enrollmentRows = enrollmentManager.getEnrollments(getIdentity(), enrollableGroupKeys, enrollableAreaKeys, 256); groupListModel = new EnrollmentTableModelWithMaxSize(enrollmentRows, getTranslator(), getIdentity(), cancelEnrollEnabled, maxEnrollCount); @@ -314,16 +314,44 @@ public class ENRunController extends BasicController implements GenericEventList private TableController createTableController(UserRequest ureq, boolean hasAnyWaitingList) { TableGuiConfiguration tableConfig = new TableGuiConfiguration(); tableConfig.setTableEmptyMessage(translate("grouplist.no.groups")); - + removeAsListenerAndDispose(tableCtr); tableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator()); listenTo(tableCtr); - + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("grouplist.table.name", 0, CMD_VISIT_CARD, getLocale())); DefaultColumnDescriptor descCd = new DefaultColumnDescriptor("grouplist.table.desc", 1, null, getLocale()); descCd.setEscapeHtml(EscapeMode.antisamy); tableCtr.addColumnDescriptor(descCd); - tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("grouplist.table.partipiciant", 2, null, getLocale())); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("grouplist.table.partipiciant", 2, null, getLocale()) { + @Override + public int compareTo(int rowa, int rowb) { + Object a = table.getTableDataModel().getValueAt(rowa, dataColumn); + Object b = table.getTableDataModel().getValueAt(rowb, dataColumn); + if (a == null || b == null) { + boolean bb = (b == null); + return (a == null) ? (bb ? 0: -1) : (bb ? 1: 0); + } + try { + Integer la, lb; + if (a instanceof String) { + String sa = (String) a; + la = Integer.parseInt(sa.substring(0, sa.indexOf("/"))); + } else { + la = (Integer) a; + } + if (b instanceof String) { + String sb = (String) b; + lb = Integer.parseInt(sb.substring(0, sb.indexOf("/"))); + } else { + lb = (Integer) b; + } + return la.compareTo(lb); + } catch (NumberFormatException e) { + return super.compareTo(rowa, rowb); + } + } + }); tableCtr.addColumnDescriptor(hasAnyWaitingList, new DefaultColumnDescriptor("grouplist.table.waitingList", 3, null, getLocale())); DefaultColumnDescriptor stateColdEsc = new DefaultColumnDescriptor("grouplist.table.state", 4, null, getLocale()); stateColdEsc.setEscapeHtml(EscapeMode.none); @@ -340,14 +368,14 @@ public class ENRunController extends BasicController implements GenericEventList } /** - * + * * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) */ @Override protected void doDispose() { deregisterGroupChangedEvents(); } - + /* * Add as listener to BusinessGroups so we are being notified about changes. */ @@ -358,7 +386,7 @@ public class ENRunController extends BasicController implements GenericEventList CoordinatorManager.getInstance().getCoordinator().getEventBus().registerFor(this, identity, ores); } } - + private void deregisterGroupChangedEvents() { if(registeredGroupKeys != null) { for (Long groupKey:registeredGroupKeys) { diff --git a/src/main/java/org/olat/course/nodes/gta/GTAManager.java b/src/main/java/org/olat/course/nodes/gta/GTAManager.java index 0cc0f38448a4cda96ca5d8e0e363e57b0b3181e1..eebc0e9c90591dc9da9d7e1b3de8805363d343b6 100644 --- a/src/main/java/org/olat/course/nodes/gta/GTAManager.java +++ b/src/main/java/org/olat/course/nodes/gta/GTAManager.java @@ -28,6 +28,7 @@ import org.olat.core.commons.services.notifications.SubscriptionContext; import org.olat.core.id.Identity; import org.olat.core.util.vfs.VFSContainer; import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.model.DueDate; import org.olat.course.nodes.gta.model.Membership; import org.olat.course.nodes.gta.model.Solution; import org.olat.course.nodes.gta.model.TaskDefinition; @@ -35,6 +36,7 @@ import org.olat.course.nodes.gta.ui.events.SubmitEvent; import org.olat.course.run.environment.CourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupRef; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryRef; @@ -129,7 +131,6 @@ public interface GTAManager { public void removeSolution(Solution removedSolution, CourseEnvironment courseEnv, GTACourseNode cNode); - /** * Create a subscription context. * @param courseEnv The course environment @@ -252,19 +253,27 @@ public interface GTAManager { public Membership getMembership(IdentityRef identity, RepositoryEntryRef entry, GTACourseNode cNode); + public Task getTask(TaskRef task); + + public TaskDueDate getDueDatesTask(TaskRef task); + public Task getTask(IdentityRef identity, TaskList taskList); public Task getTask(BusinessGroupRef businessGroup, TaskList taskList); public Task createTask(String taskName, TaskList taskList, TaskProcess status, BusinessGroup assessedGroup, Identity assessedIdentity, GTACourseNode cNode); - public Task nextStep(Task task, GTACourseNode cNode); + public Task createAndPersistTask(String taskName, TaskList taskList, TaskProcess status, BusinessGroup assessedGroup, Identity assessedIdentity, GTACourseNode cNode); + + public Task nextStep(Task task, GTACourseNode cNode, Role by); public List<Task> getTasks(TaskList taskList, GTACourseNode gtaNode); public List<TaskLight> getTasksLight(RepositoryEntryRef entry, GTACourseNode gtaNode); + + public List<TaskRevisionDate> getTaskRevisions(Task task); /** @@ -289,15 +298,60 @@ public interface GTAManager { public AssignmentResponse assignTaskAutomatically(TaskList taskList, Identity assessedIdentity, CourseEnvironment courseEnv, GTACourseNode cNode); + public boolean isDueDateEnabled(GTACourseNode cNode); + + public DueDate getAssignmentDueDate(TaskRef task, IdentityRef assessedIdentity, BusinessGroup assessedGroup, + GTACourseNode gtaNode, RepositoryEntry courseEntry, boolean withIndividualDueDate); + + public DueDate getSubmissionDueDate(TaskRef assignedTask, IdentityRef assessedIdentity, BusinessGroup assessedGroup, + GTACourseNode cNode, RepositoryEntry courseEntry, boolean withIndividualDueDate); + + public DueDate getSolutionDueDate(TaskRef assignedTask, IdentityRef assessedIdentity, BusinessGroup assessedGroup, + GTACourseNode cNode, RepositoryEntry courseEntry, boolean withIndividualDueDate); + + /** + * Calculated a reference date relative to the specified parameters + * + * @param numOfDays + * @param relativeTo + * @param assignedTask + * @param entry + * @return + */ + public DueDate getReferenceDate(int numOfDays, String relativeTo, TaskRef assignedTask, + IdentityRef assessedIdentity, BusinessGroup assessedGroup, RepositoryEntry entry); + public TaskProcess firstStep(GTACourseNode cNode); public TaskProcess previousStep(TaskProcess currentStep, GTACourseNode cNode); public TaskProcess nextStep(TaskProcess currentStep, GTACourseNode cNode); + + public Task collectTask(Task task, GTACourseNode cNode, int numOfDocs); + + /** + * Task is reviewed and accepted. + * @param task + * @param cNode + * @return + */ + public Task reviewedTask(Task task, GTACourseNode cNode); + + public Task updateTask(Task task, TaskProcess newStatus, GTACourseNode cNode, Role by); + + public TaskDueDate updateTaskDueDate(TaskDueDate taskDueDate); + + public Task submitTask(Task task, GTACourseNode cNode, int numOfDocs, Role by); + + public Task submitRevisions(Task task, GTACourseNode cNode, int numOfDocs, Role by); + + public Task updateTask(Task task, TaskProcess newStatus, int iteration, GTACourseNode cNode, Role by); + + public Task allowResetTask(Task task, Identity allower, GTACourseNode cNode); - public Task updateTask(Task task, TaskProcess newStatus, GTACourseNode cNode); + public Task resetTask(Task task, GTACourseNode cNode, CourseEnvironment courseEnv); - public Task updateTask(Task task, TaskProcess newStatus, int iteration, GTACourseNode cNode); + public Task resetTaskRefused(Task task, GTACourseNode cNode); public void log(String step, String operation, Task assignedTask, Identity actor, Identity assessedIdentity, BusinessGroup assessedGroup, CourseEnvironment courseEnv, GTACourseNode cNode); diff --git a/src/main/java/org/olat/course/nodes/gta/Task.java b/src/main/java/org/olat/course/nodes/gta/Task.java index 25452d58da19eba8af1f1ae76793867d15de8973..e29fe4c5552a4d9fecc00b65249a073be0fcdf7c 100644 --- a/src/main/java/org/olat/course/nodes/gta/Task.java +++ b/src/main/java/org/olat/course/nodes/gta/Task.java @@ -30,25 +30,23 @@ import org.olat.group.BusinessGroup; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public interface Task { +public interface Task extends TaskRef { - public Long getKey(); + public Date getSubmissionDate(); - public Date getCreationDate(); + public Date getSubmissionRevisionsDate(); - public Date getLastModified(); + public Date getCollectionDate(); - public TaskProcess getTaskStatus(); + public Date getAcceptationDate(); - /** - * Iteration of the revision / correction process. Start with 1. - * @return - */ - public int getRevisionLoop(); + public Date getSolutionDate(); - public String getTaskName(); + public Date getGraduationDate(); - public Date getAssignmentDate(); + public Date getAllowResetDate(); + + public Identity getAllowResetIdentity(); public TaskList getTaskList(); diff --git a/src/main/java/org/olat/course/nodes/gta/TaskDueDate.java b/src/main/java/org/olat/course/nodes/gta/TaskDueDate.java new file mode 100644 index 0000000000000000000000000000000000000000..73cef249d9d6ccf4287c7cfb5ad0bf65a8a678a3 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/TaskDueDate.java @@ -0,0 +1,41 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta; + +import java.util.Date; + +/** + * + * + * Initial date: 4 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface TaskDueDate extends Task { + + public void setAssignmentDueDate(Date assignmentDueDate); + + public void setSubmissionDueDate(Date submissionDueDate); + + public void setRevisionsDueDate(Date revisionsDueDate); + + public void setSolutionDueDate(Date solutionDueDate); + +} diff --git a/src/main/java/org/olat/course/nodes/gta/TaskLight.java b/src/main/java/org/olat/course/nodes/gta/TaskLight.java index 9e6d48af3b54738addb8ec6a80a14922deaa63f8..dbd0c94e656c877c630da6976416502d08095d44 100644 --- a/src/main/java/org/olat/course/nodes/gta/TaskLight.java +++ b/src/main/java/org/olat/course/nodes/gta/TaskLight.java @@ -27,7 +27,7 @@ import java.util.Date; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public interface TaskLight { +public interface TaskLight extends TaskRef { public Long getKey(); @@ -47,6 +47,18 @@ public interface TaskLight { public Date getAssignmentDate(); + public Date getSubmissionDate(); + + public Integer getSubmissionNumOfDocs(); + + public Date getSubmissionRevisionsDate(); + + public Integer getSubmissionRevisionsNumOfDocs(); + + public Date getCollectionDate(); + + public Integer getCollectionNumOfDocs(); + public Long getIdentityKey(); public Long getBusinessGroupKey(); diff --git a/src/main/java/org/olat/course/nodes/gta/TaskRef.java b/src/main/java/org/olat/course/nodes/gta/TaskRef.java new file mode 100644 index 0000000000000000000000000000000000000000..c2009da64101f0889befec3027460b0278aad12b --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/TaskRef.java @@ -0,0 +1,59 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta; + +import java.util.Date; + +/** + * Common interface for Task and TaskLight + * + * Initial date: 3 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface TaskRef { + + public Long getKey(); + + public Date getCreationDate(); + + public Date getLastModified(); + + public TaskProcess getTaskStatus(); + + /** + * Iteration of the revision / correction process. Start with 1. + * @return + */ + public int getRevisionLoop(); + + public String getTaskName(); + + public Date getAssignmentDate(); + + public Date getAssignmentDueDate(); + + public Date getSubmissionDueDate(); + + public Date getRevisionsDueDate(); + + public Date getSolutionDueDate(); + +} diff --git a/src/main/java/org/olat/course/nodes/gta/TaskRevisionDate.java b/src/main/java/org/olat/course/nodes/gta/TaskRevisionDate.java new file mode 100644 index 0000000000000000000000000000000000000000..ce6f0a406485fc3bbeba4e6f2212e38fcc169c33 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/TaskRevisionDate.java @@ -0,0 +1,42 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta; + +import java.util.Date; + +/** + * + * Initial date: 7 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface TaskRevisionDate { + + public Long getKey(); + + public TaskProcess getTaskStatus(); + + public int getRevisionLoop(); + + public Date getDate(); + + public Task getTask(); + +} diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java index 358700f7922402b58c44c8b6e764094dfeb43fe8..d5ec967011298193ffed8b3c51387ca877a72599 100644 --- a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java +++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java @@ -24,6 +24,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -41,35 +42,49 @@ import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl; import org.olat.core.commons.persistence.DB; +import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.commons.services.notifications.PublisherData; import org.olat.core.commons.services.notifications.SubscriptionContext; import org.olat.core.id.Identity; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; +import org.olat.core.util.FileUtils; import org.olat.core.util.StringHelper; import org.olat.core.util.io.SystemFilenameFilter; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSManager; import org.olat.core.util.xml.XStreamHelper; +import org.olat.course.CourseFactory; +import org.olat.course.ICourse; +import org.olat.course.assessment.AssessmentHelper; +import org.olat.course.assessment.manager.UserCourseInformationsManager; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.AssignmentResponse; import org.olat.course.nodes.gta.AssignmentResponse.Status; import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.GTARelativeToDates; import org.olat.course.nodes.gta.GTAType; import org.olat.course.nodes.gta.Task; +import org.olat.course.nodes.gta.TaskDueDate; import org.olat.course.nodes.gta.TaskLight; import org.olat.course.nodes.gta.TaskList; import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.TaskRef; +import org.olat.course.nodes.gta.TaskRevisionDate; +import org.olat.course.nodes.gta.model.DueDate; import org.olat.course.nodes.gta.model.Membership; import org.olat.course.nodes.gta.model.Solution; import org.olat.course.nodes.gta.model.SolutionList; import org.olat.course.nodes.gta.model.TaskDefinition; import org.olat.course.nodes.gta.model.TaskDefinitionList; +import org.olat.course.nodes.gta.model.TaskDueDateImpl; import org.olat.course.nodes.gta.model.TaskImpl; import org.olat.course.nodes.gta.model.TaskListImpl; +import org.olat.course.nodes.gta.model.TaskRevisionDateImpl; import org.olat.course.nodes.gta.ui.events.SubmitEvent; import org.olat.course.run.environment.CourseEnvironment; +import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupRef; import org.olat.group.BusinessGroupService; @@ -79,10 +94,13 @@ import org.olat.group.manager.BusinessGroupRelationDAO; import org.olat.group.model.BusinessGroupRefImpl; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentService; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryRef; +import org.olat.repository.RepositoryService; import org.olat.repository.manager.RepositoryEntryRelationDAO; +import org.olat.repository.model.RepositoryEntryLifecycle; import org.olat.resource.OLATResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -109,11 +127,17 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { @Autowired private AssessmentService assessmentService; @Autowired + private RepositoryService repositoryService; + @Autowired private BusinessGroupService businessGroupService; @Autowired + private NotificationsManager notificationsManager; + @Autowired private BusinessGroupRelationDAO businessGroupRelationDao; @Autowired private RepositoryEntryRelationDAO repositoryEntryRelationDao; + @Autowired + private UserCourseInformationsManager userCourseInformationsManager; /** * Get the task folder path relative to the folder root for a specific node. @@ -809,6 +833,25 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { .getResultList(); } + @Override + public Task getTask(TaskRef task) { + String q = "select task from gtatask task where task.key=:taskKey"; + List<Task> tasks = dbInstance.getCurrentEntityManager().createQuery(q, Task.class) + .setParameter("taskKey", task.getKey()) + .getResultList(); + + return tasks.isEmpty() ? null : tasks.get(0); + } + + @Override + public TaskDueDate getDueDatesTask(TaskRef task) { + List<TaskDueDate> tasks = dbInstance.getCurrentEntityManager() + .createNamedQuery("dueDateTaskByTask", TaskDueDate.class) + .setParameter("taskKey", task.getKey()) + .getResultList(); + return tasks.isEmpty() ? null : tasks.get(0); + } + @Override public Task getTask(IdentityRef identity, TaskList taskList) { String q = "select task from gtatask task where task.taskList.key=:taskListKey and task.identity.key=:identityKey"; @@ -830,6 +873,17 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { return tasks.isEmpty() ? null : tasks.get(0); } + + @Override + public List<TaskRevisionDate> getTaskRevisions(Task task) { + if(task == null || task.getKey() == null) return Collections.emptyList(); + + String q = "select taskrev from gtataskrevisiondate taskrev where taskrev.task.key=:taskKey"; + return dbInstance.getCurrentEntityManager() + .createQuery(q, TaskRevisionDate.class) + .setParameter("taskKey", task.getKey()) + .getResultList(); + } @Override public AssignmentResponse assignTaskAutomatically(TaskList taskList, BusinessGroup assessedGroup, CourseEnvironment courseEnv, GTACourseNode cNode) { @@ -874,7 +928,7 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { task.setAssignmentDate(new Date()); dbInstance.getCurrentEntityManager().persist(task); dbInstance.commit(); - syncAssessmentEntry((TaskImpl)currentTask, cNode); + syncAssessmentEntry((TaskImpl)currentTask, cNode, Role.user); response = new AssignmentResponse(task, Status.ok); } } else { @@ -882,7 +936,7 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { ((TaskImpl)currentTask).setTaskStatus(TaskProcess.submit); } currentTask = dbInstance.getCurrentEntityManager().merge(currentTask); - syncAssessmentEntry((TaskImpl)currentTask, cNode); + syncAssessmentEntry((TaskImpl)currentTask, cNode, Role.user); response = new AssignmentResponse(currentTask, Status.ok); } @@ -1005,6 +1059,7 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { TaskImpl task = createTask(taskName, reloadedTasks, nextStep, businessGroup, identity, cNode); task.setAssignmentDate(new Date()); dbInstance.getCurrentEntityManager().persist(task); + syncAssessmentEntry(task, cNode, Role.user); response = new AssignmentResponse(task, Status.ok); } dbInstance.commit(); @@ -1012,14 +1067,25 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { if(currentTask.getTaskStatus() == TaskProcess.assignment) { TaskProcess nextStep = nextStep(currentTask.getTaskStatus(), cNode); ((TaskImpl)currentTask).setTaskStatus(nextStep); + if(taskFile != null) { + ((TaskImpl)currentTask).setTaskName(taskFile.getName()); + } } currentTask = dbInstance.getCurrentEntityManager().merge(currentTask); - syncAssessmentEntry((TaskImpl)currentTask, cNode); + syncAssessmentEntry((TaskImpl)currentTask, cNode, Role.user); response = new AssignmentResponse(currentTask, Status.ok); } return response; } + @Override + public Task createAndPersistTask(String taskName, TaskList taskList, TaskProcess status, + BusinessGroup assessedGroup, Identity assessedIdentity, GTACourseNode cNode) { + Task task = createTask(taskName, taskList, status, assessedGroup, assessedIdentity, cNode); + dbInstance.getCurrentEntityManager().persist(task); + return task; + } + @Override public TaskImpl createTask(String taskName, TaskList taskList, TaskProcess status, BusinessGroup assessedGroup, Identity assessedIdentity, GTACourseNode cNode) { TaskImpl task = new TaskImpl(); @@ -1031,6 +1097,10 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { task.setTaskStatus(status);//assignment is ok -> go to submit step task.setRevisionLoop(0); + if(status == TaskProcess.graded) { + task.setGraduationDate(new Date()); + } + if(GTAType.group.name().equals(cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) { task.setBusinessGroup(assessedGroup); } else { @@ -1038,9 +1108,169 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { } return task; } + + public TaskRevisionDate createAndPersistTaskRevisionDate(Task task, int revisionLoop, TaskProcess status) { + TaskRevisionDateImpl rev = new TaskRevisionDateImpl(); + rev.setCreationDate(new Date()); + rev.setDate(rev.getCreationDate()); + rev.setRevisionLoop(revisionLoop); + rev.setStatus(status.name()); + rev.setTask(task); + dbInstance.getCurrentEntityManager().persist(rev); + return rev; + } + + @Override + public boolean isDueDateEnabled(GTACourseNode cNode) { + if(cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_RELATIVE_DATES, false) + || cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_RELATIVE_DATES, false) + || cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_RELATIVE_DATES, false) + || cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD, false)) { + return true; + } else if(cNode.getModuleConfiguration().getDateValue(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE) != null + || cNode.getModuleConfiguration().getDateValue(GTACourseNode.GTASK_SUBMIT_DEADLINE) != null + || cNode.getModuleConfiguration().getDateValue(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER) != null) { + return true; + } + return false; + } + + @Override + public DueDate getAssignmentDueDate(TaskRef assignedTask, IdentityRef assessedIdentity, BusinessGroup assessedGroup, + GTACourseNode cNode, RepositoryEntry courseEntry, boolean withIndividualDueDate) { + DueDate assignmentDueDate = null; + Date dueDate = cNode.getModuleConfiguration().getDateValue(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE); + boolean relativeDate = cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_RELATIVE_DATES); + if((relativeDate || dueDate != null) && withIndividualDueDate && assignedTask != null && assignedTask.getAssignmentDueDate() != null) { + assignmentDueDate = new DueDate(false, assignedTask.getAssignmentDueDate()); + } else if(relativeDate) { + int numOfDays = cNode.getModuleConfiguration().getIntegerSafe(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE_RELATIVE, -1); + String relativeTo = cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE_RELATIVE_TO); + if(numOfDays >= 0 && StringHelper.containsNonWhitespace(relativeTo)) { + assignmentDueDate = getReferenceDate(numOfDays, relativeTo, assignedTask, assessedIdentity, assessedGroup, courseEntry); + } + } else if(dueDate != null) { + assignmentDueDate = new DueDate(false, dueDate); + } + return assignmentDueDate; + } + + @Override + public DueDate getSubmissionDueDate(TaskRef assignedTask, IdentityRef assessedIdentity, BusinessGroup assessedGroup, + GTACourseNode cNode, RepositoryEntry courseEntry, boolean withIndividualDueDate) { + DueDate submissionDueDate = null; + Date dueDate = cNode.getModuleConfiguration().getDateValue(GTACourseNode.GTASK_SUBMIT_DEADLINE); + boolean relativeDate = cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_RELATIVE_DATES); + if((relativeDate || dueDate != null) && withIndividualDueDate && assignedTask != null && assignedTask.getSubmissionDueDate() != null) { + submissionDueDate = new DueDate(false, assignedTask.getSubmissionDueDate()); + } else if(relativeDate) { + int numOfDays = cNode.getModuleConfiguration().getIntegerSafe(GTACourseNode.GTASK_SUBMIT_DEADLINE_RELATIVE, -1); + String relativeTo = cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_SUBMIT_DEADLINE_RELATIVE_TO); + if(numOfDays >= 0 && StringHelper.containsNonWhitespace(relativeTo)) { + submissionDueDate = getReferenceDate(numOfDays, relativeTo, assignedTask, assessedIdentity, assessedGroup, courseEntry); + } + } else if(dueDate != null) { + submissionDueDate = new DueDate(false, dueDate); + } + return submissionDueDate; + } + + @Override + public DueDate getSolutionDueDate(TaskRef assignedTask, IdentityRef assessedIdentity, BusinessGroup assessedGroup, + GTACourseNode cNode, RepositoryEntry courseEntry, boolean withIndividualDueDate) { + DueDate solutionDueDate = null; + boolean relativeDate = cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_RELATIVE_DATES); + Date dueDate = cNode.getModuleConfiguration().getDateValue(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER); + if((relativeDate || dueDate != null) && withIndividualDueDate && assignedTask != null && assignedTask.getSolutionDueDate() != null) { + solutionDueDate = new DueDate(false, assignedTask.getSolutionDueDate()); + } else if(relativeDate) { + int numOfDays = cNode.getModuleConfiguration().getIntegerSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER_RELATIVE, -1); + String relativeTo = cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER_RELATIVE_TO); + if(numOfDays >= 0 && StringHelper.containsNonWhitespace(relativeTo)) { + solutionDueDate = getReferenceDate(numOfDays, relativeTo, assignedTask, assessedIdentity, assessedGroup, courseEntry); + } + } else if(dueDate != null) { + solutionDueDate = new DueDate(false, dueDate); + } + return solutionDueDate; + } + @Override - public Task nextStep(Task task, GTACourseNode cNode) { + public DueDate getReferenceDate(int numOfDays, String relativeTo, TaskRef assignedTask, + IdentityRef assessedIdentity, BusinessGroup assessedGroup, RepositoryEntry courseEntry) { + DueDate dueDate = null; + if(numOfDays >= 0 && StringHelper.containsNonWhitespace(relativeTo)) { + GTARelativeToDates rel = GTARelativeToDates.valueOf(relativeTo); + Date referenceDate = null; + String messageKey = null; + String messageArg = null; + switch(rel) { + case courseStart: { + RepositoryEntryLifecycle lifecycle = courseEntry.getLifecycle(); + if(lifecycle != null && lifecycle.getValidFrom() != null) { + referenceDate = lifecycle.getValidFrom(); + } + break; + } + case courseLaunch: { + if(assessedIdentity != null) { + referenceDate = userCourseInformationsManager + .getInitialLaunchDate(courseEntry, assessedIdentity); + } else { + referenceDate = userCourseInformationsManager + .getInitialParticipantLaunchDate(courseEntry, assessedGroup); + } + break; + } + case enrollment: { + if(assessedIdentity != null) { + referenceDate = repositoryService + .getEnrollmentDate(courseEntry, assessedIdentity); + } else { + referenceDate = getEnrollmentDate(assessedGroup); + } + break; + } + case assignment: { + if(assignedTask != null) { + referenceDate = assignedTask.getAssignmentDate(); + } else { + messageKey = "relative.to.assignment.message"; + messageArg = Integer.toString(numOfDays); + } + break; + } + } + + if(referenceDate != null) { + Calendar cal = Calendar.getInstance(); + cal.setTime(referenceDate); + cal.add(Calendar.DATE, numOfDays); + dueDate = new DueDate(true, cal.getTime()); + } else if(messageKey != null) { + dueDate = new DueDate(true, messageKey, messageArg); + } + } + return dueDate; + } + + protected Date getEnrollmentDate(BusinessGroup businessGroup) { + StringBuilder sb = new StringBuilder(); + sb.append("select min(membership.creationDate) from businessgroup as bgroup ") + .append(" inner join bgroup.baseGroup as baseGroup") + .append(" inner join baseGroup.members as membership on (membership.role ='").append(GroupRoles.participant.name()).append("')") + .append(" where bgroup.key=:businessGroupKey"); + + List<Date> dates = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Date.class) + .setParameter("businessGroupKey", businessGroup.getKey()) + .getResultList(); + return dates.isEmpty() ? null : dates.get(0); + } + + @Override + public Task nextStep(Task task, GTACourseNode cNode, Role by) { TaskImpl taskImpl = (TaskImpl)task; TaskProcess currentStep = taskImpl.getTaskStatus(); //cascade through the possible steps @@ -1048,7 +1278,7 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { taskImpl.setTaskStatus(nextStep); TaskImpl mergedTask = dbInstance.getCurrentEntityManager().merge(taskImpl); dbInstance.commit();//make the thing definitiv - syncAssessmentEntry(mergedTask, cNode); + syncAssessmentEntry(mergedTask, cNode, by); return mergedTask; } @@ -1199,21 +1429,134 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { } @Override - public Task updateTask(Task task, TaskProcess newStatus, GTACourseNode cNode) { + public Task collectTask(Task task, GTACourseNode cNode, int numOfDocs) { + TaskProcess review = nextStep(TaskProcess.submit, cNode); + TaskImpl taskImpl = (TaskImpl)task; + taskImpl.setCollectionDate(new Date()); + taskImpl.setCollectionNumOfDocs(numOfDocs); + return updateTask(task, review, cNode, Role.coach); + } + + @Override + public Task submitTask(Task task, GTACourseNode cNode, int numOfDocs, Role by) { + TaskProcess review = nextStep(TaskProcess.submit, cNode); + TaskImpl taskImpl = (TaskImpl)task; + taskImpl.setSubmissionDate(new Date()); + taskImpl.setSubmissionNumOfDocs(numOfDocs); + return updateTask(task, review, cNode, by); + } + + @Override + public Task allowResetTask(Task task, Identity allower, GTACourseNode cNode) { + TaskImpl taskImpl = (TaskImpl)task; + taskImpl.setAllowResetDate(new Date()); + taskImpl.setAllowResetIdentity(allower); + return updateTask(task, task.getTaskStatus(), cNode, Role.coach); + } + + @Override + public Task resetTask(Task task, GTACourseNode cNode, CourseEnvironment courseEnv) { + TaskImpl taskImpl = (TaskImpl)task; + taskImpl.setTaskName(null); + taskImpl.setAllowResetDate(null); + Task updatedTask = updateTask(task, TaskProcess.assignment, cNode, Role.user); + + File submissionDir = null; + if(updatedTask.getBusinessGroup() != null) { + submissionDir = getSubmitDirectory(courseEnv, cNode, updatedTask.getBusinessGroup()); + } else if(updatedTask.getIdentity() != null) { + submissionDir = getSubmitDirectory(courseEnv, cNode, updatedTask.getIdentity()); + } + if(submissionDir != null) { + FileUtils.deleteDirsAndFiles(submissionDir, true, false); + } + return updatedTask; + } + + @Override + public Task resetTaskRefused(Task task, GTACourseNode cNode) { + TaskImpl taskImpl = (TaskImpl)task; + taskImpl.setAllowResetDate(null); + taskImpl.setAllowResetIdentity(null); + return updateTask(task, task.getTaskStatus(), cNode, Role.user); + } + + @Override + public Task submitRevisions(Task task, GTACourseNode cNode, int numOfDocs, Role by) { + TaskImpl taskImpl = (TaskImpl)task; + taskImpl.setSubmissionRevisionsDate(new Date()); + taskImpl.setSubmissionRevisionsNumOfDocs(numOfDocs); + //log the date + createAndPersistTaskRevisionDate(taskImpl, taskImpl.getRevisionLoop(), TaskProcess.correction); + return updateTask(taskImpl, TaskProcess.correction, cNode, by); + } + + @Override + public Task reviewedTask(Task task, GTACourseNode cNode) { + TaskProcess solution = nextStep(TaskProcess.correction, cNode); + TaskImpl taskImpl = (TaskImpl)task; + taskImpl.setAcceptationDate(new Date()); + return updateTask(taskImpl, solution, cNode, Role.coach); + } + + @Override + public Task updateTask(Task task, TaskProcess newStatus, GTACourseNode cNode, Role by) { TaskImpl taskImpl = (TaskImpl)task; taskImpl.setTaskStatus(newStatus); + syncDates(taskImpl, newStatus); taskImpl = dbInstance.getCurrentEntityManager().merge(taskImpl); - syncAssessmentEntry(taskImpl, cNode); + syncAssessmentEntry(taskImpl, cNode, by); + + //update + OLATResource resource = taskImpl.getTaskList().getEntry().getOlatResource(); + notificationsManager.markPublisherNews(getSubscriptionContext(resource, cNode), null, false); + return taskImpl; } + + private void syncDates(TaskImpl taskImpl, TaskProcess newStatus) { + //solution date + if(newStatus == TaskProcess.solution || newStatus == TaskProcess.grading || newStatus == TaskProcess.graded) { + if(taskImpl.getSolutionDate() == null) { + taskImpl.setSolutionDate(new Date()); + } + } else { + taskImpl.setSolutionDate(null); + } + + //graduation date + if(newStatus == TaskProcess.graded) { + if(taskImpl.getGraduationDate() == null) { + taskImpl.setGraduationDate(new Date()); + } + } else { + taskImpl.setGraduationDate(null); + } + + //check submission date because of reopen + if(newStatus == TaskProcess.assignment || newStatus == TaskProcess.submit) { + if(taskImpl.getSubmissionDate() != null) { + taskImpl.setSubmissionDate(null); + taskImpl.setSubmissionNumOfDocs(null); + } + } + } + + @Override + public TaskDueDate updateTaskDueDate(TaskDueDate taskDueDate) { + ((TaskDueDateImpl)taskDueDate).setLastModified(new Date()); + return dbInstance.getCurrentEntityManager().merge(taskDueDate); + } @Override - public Task updateTask(Task task, TaskProcess newStatus, int iteration, GTACourseNode cNode) { + public Task updateTask(Task task, TaskProcess newStatus, int iteration, GTACourseNode cNode, Role by) { TaskImpl taskImpl = (TaskImpl)task; taskImpl.setTaskStatus(newStatus); taskImpl.setRevisionLoop(iteration); taskImpl = dbInstance.getCurrentEntityManager().merge(taskImpl); - syncAssessmentEntry(taskImpl, cNode); + //log date + createAndPersistTaskRevisionDate(taskImpl, iteration, newStatus); + syncAssessmentEntry(taskImpl, cNode, by); return taskImpl; } @@ -1235,7 +1578,7 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { return assessmentStatus; } - private void syncAssessmentEntry(TaskImpl taskImpl, GTACourseNode cNode) { + private void syncAssessmentEntry(TaskImpl taskImpl, GTACourseNode cNode, Role by) { if(taskImpl == null || taskImpl.getTaskStatus() == null || cNode == null) return; RepositoryEntry courseRepoEntry = taskImpl.getTaskList().getEntry(); @@ -1244,8 +1587,14 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { //update whole group assessmentService.updateAssessmentEntries(taskImpl.getBusinessGroup(), courseRepoEntry, cNode.getIdent(), null, assessmentStatus); } else { - assessmentService.updateAssessmentEntry(taskImpl.getIdentity(), courseRepoEntry, cNode.getIdent(), null, assessmentStatus); - } + Identity assessedIdentity = taskImpl.getIdentity(); + assessmentService.updateAssessmentEntry(assessedIdentity, courseRepoEntry, cNode.getIdent(), null, assessmentStatus); + dbInstance.commit(); + + ICourse course = CourseFactory.loadCourse(courseRepoEntry); + UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course); + cNode.updateLastModifications(userCourseEnv, taskImpl.getIdentity(), by); + } } private TaskList loadForUpdate(TaskList tasks) { diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java b/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java index ec1faaead33a97857c3bb67dae3dda84a827b983..e3d5d7db0d41e19cfbb386c87e54d501c7c19722 100644 --- a/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java +++ b/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java @@ -38,24 +38,35 @@ import org.olat.core.commons.services.notifications.model.SubscriptionListItem; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.id.context.BusinessControlFactory; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.io.SystemFileFilter; +import org.olat.core.util.io.SystemFilenameFilter; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.course.CourseFactory; import org.olat.course.ICourse; +import org.olat.course.assessment.AssessmentHelper; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; import org.olat.course.nodes.gta.GTAType; import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskList; +import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.TaskRevisionDate; +import org.olat.course.nodes.gta.model.DueDate; import org.olat.course.nodes.gta.model.Membership; import org.olat.course.nodes.gta.ui.GTARunController; import org.olat.course.run.environment.CourseEnvironment; +import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.group.model.SearchBusinessGroupParams; +import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; +import org.olat.modules.assessment.manager.AssessmentEntryDAO; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; import org.olat.user.UserManager; @@ -73,32 +84,50 @@ class GTANotifications { private final List<SubscriptionListItem> items = new ArrayList<>(); private TaskList taskList; + private String header; private String displayName; + private GTACourseNode gtaNode; + private CourseEnvironment courseEnv; private Calendar cal = Calendar.getInstance(); private final Translator translator; + private final Formatter formatter; private final GTAManager gtaManager; private final UserManager userManager; private final RepositoryService repositoryService; private final BusinessGroupService businessGroupService; + private final AssessmentEntryDAO courseNodeAssessmentDao; public GTANotifications(Subscriber subscriber, Locale locale, Date compareDate, RepositoryService repositoryService, GTAManager gtaManager, - BusinessGroupService businessGroupService, UserManager userManager) { + BusinessGroupService businessGroupService, UserManager userManager, + AssessmentEntryDAO courseNodeAssessmentDao) { this.gtaManager = gtaManager; this.userManager = userManager; this.repositoryService = repositoryService; this.businessGroupService = businessGroupService; + this.courseNodeAssessmentDao = courseNodeAssessmentDao; this.subscriber = subscriber; this.compareDate = compareDate; + formatter = Formatter.getInstance(locale); translator = Util.createPackageTranslator(GTARunController.class, locale); } public String getDisplayName() { return displayName; } + + public String getNotifificationHeader() { + if(StringHelper.containsNonWhitespace(header)) { + return header; + } + if(GTAType.group.name().equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) { + return translator.translate("notifications.group.header", new String[]{ displayName }); + } + return translator.translate("notifications.individual.header", new String[]{ displayName }); + } public List<SubscriptionListItem> getItems() { Publisher p = subscriber.getPublisher(); @@ -110,39 +139,28 @@ class GTANotifications { } if(entry != null && node instanceof GTACourseNode) { + gtaNode = (GTACourseNode)node; displayName = entry.getDisplayname(); - - GTACourseNode gtaNode = (GTACourseNode)node; + courseEnv = course.getCourseEnvironment(); taskList = gtaManager.getTaskList(entry, gtaNode); if(GTAType.group.name().equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) { - createBusinessGroupsSubscriptionInfo(subscriber.getIdentity(), course.getCourseEnvironment(), gtaNode); + createBusinessGroupsSubscriptionInfo(subscriber.getIdentity()); } else { - createIndividualSubscriptionInfo(subscriber.getIdentity(), course.getCourseEnvironment(), gtaNode); - } - - //copy solutions - if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)) { - File solutionDirectory = gtaManager.getSolutionsDirectory(course.getCourseEnvironment(), gtaNode); - VFSContainer solutionContainer = gtaManager.getSolutionsContainer(course.getCourseEnvironment(), gtaNode); - File[] solutions = solutionDirectory.listFiles(SystemFileFilter.FILES_ONLY); - for(File solution:solutions) { - String author = getAuthor(solution, solutionContainer); - appendSubscriptionItem("notifications.solution", new String[] { solution.getName(), author }, solution); - } + createIndividualSubscriptionInfo(subscriber.getIdentity()); } } return items; } - private void createIndividualSubscriptionInfo(Identity subscriberIdentity, CourseEnvironment ce, GTACourseNode gtaNode) { - RepositoryEntry entry = ce.getCourseGroupManager().getCourseEntry(); + private void createIndividualSubscriptionInfo(Identity subscriberIdentity) { + RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry(); List<String> roles = repositoryService.getRoles(subscriberIdentity, entry); boolean owner = roles.contains(GroupRoles.owner.name()); boolean coach = roles.contains(GroupRoles.coach.name()); - if(owner|| coach) { + if(owner || coach) { Set<Identity> duplicateKiller = new HashSet<>(); List<Identity> assessableIdentities = new ArrayList<>(); @@ -175,137 +193,577 @@ class GTANotifications { } for(Identity assessedIdentity: assessableIdentities) { - createIndividualSubscriptionInfo(assessedIdentity, ce, gtaNode, true); + createIndividualSubscriptionInfo(assessedIdentity, true); } - } - - if(roles.contains(GroupRoles.participant.name())) { - createIndividualSubscriptionInfo(subscriberIdentity, ce, gtaNode, false); - } - } - private void createIndividualSubscriptionInfo(Identity assessedIdentity, CourseEnvironment ce, GTACourseNode gtaNode, boolean coach) { - String fullName = userManager.getUserDisplayName(assessedIdentity); - if(coach && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SUBMIT)) { - File submitDirectory = gtaManager.getSubmitDirectory(ce, gtaNode, assessedIdentity); - File[] solutions = submitDirectory.listFiles(SystemFileFilter.FILES_ONLY); - for(File solution:solutions) { - appendSubscriptionItem("notifications.submission.individual", new String[] { solution.getName(), fullName }, solution); + createCoachSolutionItems(); + } else { + Task task = gtaManager.getTask(subscriberIdentity, taskList); + if(task != null) { + header = translator.translate("notifications.individual.header.task", new String[]{ getTaskName(task), displayName }); } } - if(!coach && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION)) { - File correctionDirectory = gtaManager.getCorrectionDirectory(ce, gtaNode, assessedIdentity); - VFSContainer correctionContainer = gtaManager.getCorrectionContainer(ce, gtaNode, assessedIdentity); - File[] corrections = correctionDirectory.listFiles(SystemFileFilter.FILES_ONLY); - for(File correction:corrections) { - String author = getAuthor(correction, correctionContainer); - appendSubscriptionItem("notifications.correction", new String[] { correction.getName(), author }, correction); + if(roles.contains(GroupRoles.participant.name())) { + createIndividualSubscriptionInfo(subscriberIdentity, false); + Task task = gtaManager.getTask(subscriberIdentity, taskList); + if(isSolutionVisible(subscriberIdentity, null, task)) { + createParticipantSolutionItems(task, subscriberIdentity, null); + } + if(task != null && task.getTaskStatus() == TaskProcess.graded) { + createAssessmentItem(task, subscriberIdentity, false); } } + } + + private void createIndividualSubscriptionInfo(Identity assessedIdentity, boolean coach) { + Task task = gtaManager.getTask(assessedIdentity, taskList); - if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) { - Task task = gtaManager.getTask(assessedIdentity, taskList); - if(task != null) { - int currentIteration = task.getRevisionLoop(); - for(int i=1; i<=currentIteration; i++) { - //revision - - if(coach) { - //revision - File revisionDirectory = gtaManager.getRevisedDocumentsDirectory(ce, gtaNode, i, assessedIdentity); - File[] revisions = revisionDirectory.listFiles(SystemFileFilter.FILES_ONLY); - for(File revision:revisions) { - appendSubscriptionItem("notifications.revision.individual", new String[] { revision.getName(), fullName }, revision); - } - } else { - //corrections - File correctionDirectory = gtaManager.getRevisedDocumentsCorrectionsDirectory(ce, gtaNode, i, assessedIdentity); - VFSContainer correctionContainer = gtaManager.getRevisedDocumentsCorrectionsContainer(ce, gtaNode, i, assessedIdentity); - File[] corrections = correctionDirectory.listFiles(SystemFileFilter.FILES_ONLY); - for(File correction:corrections) { - String author = getAuthor(correction, correctionContainer); - appendSubscriptionItem("notifications.correction", new String[] { correction.getName(), author }, correction); - } + if(coach && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SUBMIT)) { + task = checkSubmitStep(assessedIdentity, null, task); + //show after the step submit, if submission date after compare date + if(task != null && notInStep(task, TaskProcess.assignment, TaskProcess.submit) + && task.getSubmissionDate() != null && task.getSubmissionDate().after(compareDate)) { + + Date submissionDate = task.getSubmissionDate(); + String fullName = userManager.getUserDisplayName(assessedIdentity); + File submitDirectory = gtaManager.getSubmitDirectory(courseEnv, gtaNode, assessedIdentity); + File[] submissions = submitDirectory.listFiles(SystemFileFilter.FILES_ONLY); + if(submissions.length == 0) { + String[] params = new String[] { + getTaskName(task), // {0} + displayName, // {1} + fullName // {2} + }; + appendSubscriptionItem("notifications.submission.individual", params, assessedIdentity, submissionDate, coach); + } else { + for(File submission:submissions) { + String[] params = new String[] { + getTaskName(task), // {0} + displayName, // {1} + submission.getName(), // {2} + fullName // {3} + }; + appendSubscriptionItemForFile("notifications.submission.individual.doc", params, assessedIdentity, + "[submit:0]", submission, submissionDate, coach); } } } } + + createReviewAndRevisionsItems(task, assessedIdentity, null, coach); + createAcceptedItem(task, assessedIdentity, null, coach); } - private void createBusinessGroupsSubscriptionInfo(Identity subscriberIdentity, CourseEnvironment ce, GTACourseNode gtaNode) { - RepositoryEntry entry = ce.getCourseGroupManager().getCourseEntry(); + private void createBusinessGroupsSubscriptionInfo(Identity subscriberIdentity) { + RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry(); Membership membership = gtaManager.getMembership(subscriberIdentity, entry, gtaNode); boolean owner = repositoryService.hasRole(subscriberIdentity, entry, GroupRoles.owner.name()); if(owner) { List<BusinessGroup> groups = gtaManager.getBusinessGroups(gtaNode); for(BusinessGroup group:groups) { - createBusinessGroupsSubscriptionItems(group, ce, gtaNode, true); + createBusinessGroupsSubscriptionItems(group, true); } - } else if(membership.isCoach() ) { + createCoachSolutionItems(); + } else if(membership.isCoach()) { List<BusinessGroup> groups = gtaManager.getCoachedBusinessGroups(subscriberIdentity, gtaNode); for(BusinessGroup group:groups) { - createBusinessGroupsSubscriptionItems(group, ce, gtaNode, true); + createBusinessGroupsSubscriptionItems(group, true); } + createCoachSolutionItems(); } if(membership.isParticipant()) { List<BusinessGroup> groups = gtaManager.getParticipatingBusinessGroups(subscriberIdentity, gtaNode); + if(groups.size() == 1 && !owner && !membership.isCoach()) { + Task task = gtaManager.getTask(groups.get(0), taskList); + if(task != null) { + header = translator.translate("notifications.group.header.task", new String[]{ getTaskName(task), displayName }); + } + } + for(BusinessGroup group:groups) { - createBusinessGroupsSubscriptionItems(group, ce, gtaNode, false); + createBusinessGroupsSubscriptionItems(group, false); + Task task = gtaManager.getTask(group, taskList); + if(createParticipantSolutionItems(task, null, group)) { + break; + } } } } - private void createBusinessGroupsSubscriptionItems(BusinessGroup group, CourseEnvironment ce, GTACourseNode gtaNode, boolean coach) { + private void createBusinessGroupsSubscriptionItems(BusinessGroup group, boolean coach) { + Task task = gtaManager.getTask(group, taskList); + if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SUBMIT)) { - File submitDirectory = gtaManager.getSubmitDirectory(ce, gtaNode, group); - VFSContainer submitContainer = gtaManager.getSubmitContainer(ce, gtaNode, group); - File[] documents = submitDirectory.listFiles(SystemFileFilter.FILES_ONLY); - for(File document:documents) { - String author = getAuthor(document, submitContainer); - appendSubscriptionItem("notifications.submission.group", new String[] { document.getName(), group.getName(), author }, document); + task = checkSubmitStep(null, group, task); + if(task != null && notInStep(task, TaskProcess.assignment, TaskProcess.submit) + && (task.getSubmissionDate() == null || task.getSubmissionDate().after(compareDate))) { + File submitDirectory = gtaManager.getSubmitDirectory(courseEnv, gtaNode, group); + VFSContainer submitContainer = gtaManager.getSubmitContainer(courseEnv, gtaNode, group); + + Date submissionDate = task.getSubmissionDate(); + File[] submisssions = submitDirectory.listFiles(SystemFileFilter.FILES_ONLY); + if(submisssions.length == 0) { + String[] params = new String[] { + getTaskName(task), + displayName, + group.getName() + }; + appendSubscriptionItem("notifications.submission.group", params, group, submissionDate, coach); + } else { + + for(File submission:submisssions) { + String author = getAuthor(submission, submitContainer); + String[] params = new String[] { + getTaskName(task), // {0} + displayName, // {1} + submission.getName(), // {2} + author, // {3} + group.getName() // {3} + }; + appendSubscriptionItemForFile("notifications.submission.group.doc", params, group, + "[submit:0]", submission, submissionDate, coach); + } + } } } + + createReviewAndRevisionsItems(task, null, group, coach); + createAcceptedItem(task, null, group, coach); + } + + private void createReviewAndRevisionsItems(Task task, Identity assessedIdentity, BusinessGroup group, boolean coach) { + if(task == null) return; + String name; + if(group != null) { + name = group.getName(); + } else { + name = userManager.getUserDisplayName(assessedIdentity); + } + + boolean sendNotificationDueDate = true; + List<TaskRevisionDate> taskRevisions = gtaManager.getTaskRevisions(task); if(!coach && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION)) { - File correctionDirectory = gtaManager.getCorrectionDirectory(ce, gtaNode, group); - VFSContainer correctionContainer = gtaManager.getCorrectionContainer(ce, gtaNode, group); - File[] corrections = correctionDirectory.listFiles(SystemFileFilter.FILES_ONLY); - for(File correction:corrections) { - String author = getAuthor(correction, correctionContainer); - appendSubscriptionItem("notifications.correction", new String[] { correction.getName(), author }, correction); + //check task revision 1 + if(task != null && notInStep(task, TaskProcess.assignment, TaskProcess.submit, TaskProcess.review) + && checkRevisionLoop(TaskProcess.revision, 1, taskRevisions)) { + File correctionDirectory; + VFSContainer correctionContainer; + if(group != null) { + correctionDirectory = gtaManager.getCorrectionDirectory(courseEnv, gtaNode, group); + correctionContainer = gtaManager.getCorrectionContainer(courseEnv, gtaNode, group); + } else { + correctionDirectory = gtaManager.getCorrectionDirectory(courseEnv, gtaNode, assessedIdentity); + correctionContainer = gtaManager.getCorrectionContainer(courseEnv, gtaNode, assessedIdentity); + } + + Date correctionDate = getRevisionLoopDate(TaskProcess.revision, 1, taskRevisions); + if(sendNotificationDueDate) { + if(task.getRevisionsDueDate() != null) { + String[] params = new String[] { + getTaskName(task), + displayName, + formatter.formatDateAndTime(task.getRevisionsDueDate()) + }; + appendSubscriptionItem("notifications.correction.duedate", params, assessedIdentity, correctionDate, coach); + } else { + String[] params = new String[] { + getTaskName(task), + displayName + }; + appendSubscriptionItem("notifications.correction", params, assessedIdentity, correctionDate, coach); + } + sendNotificationDueDate = false; + } + + File[] corrections = correctionDirectory.listFiles(SystemFileFilter.FILES_ONLY); + for(File correction:corrections) { + String author = getAuthor(correction, correctionContainer); + String[] params = new String[] { + getTaskName(task), + displayName, + correction.getName(), + author + }; + appendSubscriptionItemForFile("notifications.correction.doc", params, assessedIdentity, + "[correction:0]", correction, correctionDate, coach); + } } } if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) { - Task task = gtaManager.getTask(group, taskList); - if(task != null) { + task = checkRevisionStep(assessedIdentity, null, task); + if(task != null && notInStep(task, TaskProcess.assignment, TaskProcess.submit, TaskProcess.review)) { int currentIteration = task.getRevisionLoop(); for(int i=1; i<=currentIteration; i++) { - //revision - File revisionDirectory = gtaManager.getRevisedDocumentsDirectory(ce, gtaNode, i, group); - VFSContainer revisionContainer = gtaManager.getRevisedDocumentsContainer(ce, gtaNode, i, group); + + if(coach) { + // revision of the students + if(checkRevisionLoop(TaskProcess.correction, i, taskRevisions)) { + File revisionDirectory; + VFSContainer revisionContainer; + if(group != null) { + revisionDirectory = gtaManager.getRevisedDocumentsDirectory(courseEnv, gtaNode, i, group); + revisionContainer = gtaManager.getRevisedDocumentsContainer(courseEnv, gtaNode, i, group); + } else { + revisionDirectory = gtaManager.getRevisedDocumentsDirectory(courseEnv, gtaNode, i, assessedIdentity); + revisionContainer = gtaManager.getRevisedDocumentsContainer(courseEnv, gtaNode, i, assessedIdentity); + } - File[] revisions = revisionDirectory.listFiles(SystemFileFilter.FILES_ONLY); - for(File revision:revisions) { - String author = getAuthor(revision, revisionContainer); - appendSubscriptionItem("notifications.revision.group", new String[] { revision.getName(), group.getName(), author }, revision); - } - //corrections - if(!coach) { - File correctionDirectory = gtaManager.getRevisedDocumentsCorrectionsDirectory(ce, gtaNode, i, group); - VFSContainer correctionContainer = gtaManager.getRevisedDocumentsCorrectionsContainer(ce, gtaNode, i, group); + Date revisionDate = getRevisionLoopDate(TaskProcess.correction, i, taskRevisions); + File[] revisions = revisionDirectory.listFiles(SystemFileFilter.FILES_ONLY); + if(revisions.length == 0) { + String[] params = new String[] { + getTaskName(task), + displayName, + name + }; + if(group != null) { + appendSubscriptionItem("notifications.revision.group", params, group, revisionDate, coach); + } else { + appendSubscriptionItem("notifications.revision.individual", params, assessedIdentity, revisionDate, coach); + } + } else { + for(File revision:revisions) { + String author = getAuthor(revision, revisionContainer); + String[] params = new String[] { + getTaskName(task), + displayName, + revision.getName(), + name, + author + }; + if(group != null) { + appendSubscriptionItemForFile("notifications.revision.group.doc", params, group, + "[revision:" + i + "]", revision, revisionDate, coach); + } else { + appendSubscriptionItemForFile("notifications.revision.individual.doc", params, assessedIdentity, + "[revision:" + i + "]", revision, revisionDate, coach); + } + } + } + } + } else if(checkRevisionLoop(TaskProcess.revision, i, taskRevisions)) { + // corrections of the coach + File correctionDirectory; + VFSContainer correctionContainer; + if(group != null) { + correctionDirectory = gtaManager.getRevisedDocumentsCorrectionsDirectory(courseEnv, gtaNode, i, group); + correctionContainer = gtaManager.getRevisedDocumentsCorrectionsContainer(courseEnv, gtaNode, i, group); + } else { + correctionDirectory = gtaManager.getRevisedDocumentsCorrectionsDirectory(courseEnv, gtaNode, i, assessedIdentity); + correctionContainer = gtaManager.getRevisedDocumentsCorrectionsContainer(courseEnv, gtaNode, i, assessedIdentity); + } + + Date correctionDate = getRevisionLoopDate(TaskProcess.revision, i, taskRevisions); + if(sendNotificationDueDate) { + if(task.getRevisionsDueDate() != null) { + String[] params = new String[] { + getTaskName(task), + displayName, + formatter.formatDateAndTime(task.getRevisionsDueDate()) + }; + appendSubscriptionItem("notifications.correction.duedate", params, assessedIdentity, correctionDate, coach); + } else { + String[] params = new String[] { + getTaskName(task), + displayName + }; + appendSubscriptionItem("notifications.correction", params, assessedIdentity, correctionDate, coach); + } + sendNotificationDueDate = false; + } + File[] corrections = correctionDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File correction:corrections) { String author = getAuthor(correction, correctionContainer); - appendSubscriptionItem("notifications.correction", new String[] { correction.getName(), author }, correction); + String[] params = new String[] { + getTaskName(task), + displayName, + correction.getName(), + author + }; + appendSubscriptionItemForFile("notifications.correction.doc", params, assessedIdentity, + "[correction:" + i + "]", correction, correctionDate, coach); + } + } + } + } + } + } + + private void createAcceptedItem(Task task, Identity assessedIdentity, BusinessGroup assessedGroup, boolean coach) { + if(task == null || task.getAcceptationDate() == null || coach) return; + + if(task.getAcceptationDate().after(compareDate)) { + RepositoryEntry courseEntry = courseEnv.getCourseGroupManager().getCourseEntry(); + String[] params = new String[] { + getTaskName(task), + courseEntry.getDisplayname() + }; + if(assessedGroup != null) { + appendSubscriptionItem("notifications.accepted", params, assessedGroup, task.getAcceptationDate(), coach); + } else { + appendSubscriptionItem("notifications.accepted", params, assessedIdentity, task.getAcceptationDate(), coach); + } + } + } + + private void createAssessmentItem(Task task, Identity assessedIdentity, boolean coach) { + if(task == null || task.getGraduationDate() == null) return; + + if(task.getGraduationDate().after(compareDate)) { + RepositoryEntry courseEntry = courseEnv.getCourseGroupManager().getCourseEntry(); + AssessmentEntry assessment = courseNodeAssessmentDao.loadAssessmentEntry(assessedIdentity, courseEntry, gtaNode.getIdent()); + boolean resultsVisible = assessment != null + && (assessment.getUserVisibility() == null || assessment.getUserVisibility().booleanValue()); + if(resultsVisible) { + String score = null; + String status = null; + if(gtaNode.hasScoreConfigured() && assessment.getScore() != null) { + score = AssessmentHelper.getRoundedScore(assessment.getScore()); + } + if(gtaNode.hasPassedConfigured() && assessment.getPassed() != null) { + status = assessment.getPassed().booleanValue() + ? translator.translate("notifications.assessment.passed.true") : translator.translate("notifications.assessment.passed.false"); + } + + Date graduationDate = task.getGraduationDate(); + String[] params = new String[] { + getTaskName(task), + courseEntry.getDisplayname(), + score, + status + }; + + if(score != null && status != null) { + if(assessment.getPassed().booleanValue()) { + appendSubscriptionItem("notifications.assessment.score.passed", params, assessedIdentity, graduationDate, coach); + } else { + appendSubscriptionItem("notifications.assessment.score.notpassed", params, assessedIdentity, graduationDate, coach); + } + } else if(score != null) { + appendSubscriptionItem("notifications.assessment.score", params, assessedIdentity, graduationDate, coach); + } else if(status != null) { + appendSubscriptionItem("notifications.assessment.passed", params, assessedIdentity, graduationDate, coach); + } + + ICourse course = CourseFactory.loadCourse(courseEnv.getCourseGroupManager().getCourseEntry()); + UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper + .createAndInitUserCourseEnvironment(assessedIdentity, course); + List<File> docs = gtaNode.getIndividualAssessmentDocuments(assessedUserCourseEnv); + for(File doc:docs) { + String[] docParams = new String[] { + getTaskName(task), + courseEntry.getDisplayname(), + doc.getName() + }; + appendSubscriptionItemForFile("notifications.assessment.doc", docParams, assessedIdentity, + "[assessment:0]", doc, graduationDate, coach); + } + } + } + } + + private void createCoachSolutionItems() { + //copy solutions + if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)) { + File solutionDirectory = gtaManager.getSolutionsDirectory(courseEnv, gtaNode); + VFSContainer solutionContainer = gtaManager.getSolutionsContainer(courseEnv, gtaNode); + File[] solutions = solutionDirectory.listFiles(SystemFileFilter.FILES_ONLY); + for(File solution:solutions) { + String author = getAuthor(solution, solutionContainer); + String[] params = new String[] { + displayName, + solution.getName(), + author + }; + appendSubscriptionItemForFile("notifications.solution", params, "", + "[solution:0]" , solution, null, true); + } + } + } + + private boolean createParticipantSolutionItems(Task task, Identity assessedIdentity, BusinessGroup group) { + //copy solutions + if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)) { + RepositoryEntry re = courseEnv.getCourseGroupManager().getCourseEntry(); + DueDate dueDate = gtaManager.getSolutionDueDate(task, assessedIdentity, group, gtaNode, re, true); + + Date solutionDate = null; + if(dueDate == null) { + if(inStep(task, TaskProcess.solution, TaskProcess.grading, TaskProcess.graded)) { + solutionDate = task.getSolutionDate(); + } else { + return false; + } + } else if(dueDate != null && dueDate.getDueDate() != null) { + if(task == null) { + if(inStep(task, TaskProcess.assignment, TaskProcess.submit, TaskProcess.review, TaskProcess.correction, TaskProcess.revision) + && !dueDate.isRelative() && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_ALL, false)) { + solutionDate = dueDate.getDueDate(); + } else { + return false; + } + } else { + solutionDate = dueDate.getDueDate(); + } + } else if(task != null) { + solutionDate = task.getSolutionDate(); + } + + if(solutionDate != null) { + if(task.getSolutionDate() != null && task.getSolutionDate().after(solutionDate)) { + solutionDate = task.getSolutionDate(); + } + + File solutionDirectory = gtaManager.getSolutionsDirectory(courseEnv, gtaNode); + VFSContainer solutionContainer = gtaManager.getSolutionsContainer(courseEnv, gtaNode); + File[] solutions = solutionDirectory.listFiles(SystemFileFilter.FILES_ONLY); + for(File solution:solutions) { + Date date = solutionDate; + + //check if there are new solutions too + cal.setTimeInMillis(solution.lastModified()); + Date modificationDate = cal.getTime(); + if(date.before(modificationDate)) { + date = modificationDate; + } + + if(date.after(compareDate)) { + String author = getAuthor(solution, solutionContainer); + if(task != null) { + String[] params = new String[] { + getTaskName(task), + displayName, + solution.getName(), + author + }; + appendSubscriptionItemForFile("notifications.solution.task", params, assessedIdentity, + "[solution:0]" , solution, date, false); + } else { + String[] params = new String[] { + displayName, + solution.getName(), + author + }; + appendSubscriptionItemForFile("notifications.solution", params, assessedIdentity, + "[solution:0]" , solution, date, false); } } } + return true; } } + return false; + } + + private Task checkSubmitStep(Identity assessedIdentity, BusinessGroup assessedGroup, Task task) { + if(task != null && task.getTaskStatus() == TaskProcess.submit) { + RepositoryEntry re = courseEnv.getCourseGroupManager().getCourseEntry(); + DueDate dueDate = gtaManager.getSubmissionDueDate(task, assessedIdentity, assessedGroup, gtaNode, re, true); + if(dueDate != null && dueDate.getDueDate() != null && dueDate.getDueDate().before(new Date())) { + int numOfDocs = getNumberOfSubmittedDocuments(assessedIdentity, assessedGroup); + task = gtaManager.submitTask(task, gtaNode, numOfDocs, Role.auto); + doUpdateAttempts(assessedIdentity, assessedGroup); + } + } + return task; + } + + private int getNumberOfSubmittedDocuments(Identity assessedIdentity, BusinessGroup assessedGroup) { + File[] submittedDocuments; + if(GTAType.group.name().equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) { + File documentsDir = gtaManager.getSubmitDirectory(courseEnv, gtaNode, assessedGroup); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + + } else { + File documentsDir = gtaManager.getSubmitDirectory(courseEnv, gtaNode, assessedIdentity); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + } + return submittedDocuments == null ? 0 : submittedDocuments.length; + } + + private boolean checkRevisionLoop(TaskProcess status, int revisionLoop, List<TaskRevisionDate> taskRevisions) { + for(TaskRevisionDate taskRevision:taskRevisions) { + if(taskRevision.getTaskStatus() == status && taskRevision.getRevisionLoop() == revisionLoop) { + Date date = taskRevision.getDate(); + if(date.after(compareDate)) { + return true; + } + } + } + return false; + } + + private Date getRevisionLoopDate(TaskProcess status, int revisionLoop, List<TaskRevisionDate> taskRevisions) { + for(TaskRevisionDate taskRevision:taskRevisions) { + if(taskRevision.getTaskStatus() == status && taskRevision.getRevisionLoop() == revisionLoop) { + return taskRevision.getDate(); + } + } + return null; + } + + /** + * This checks the revision due date. + * + * @param assessedIdentity The identity which is assessed + * @param assessedGroup The group which is assessed + * @param task The task + * @return An updated task if the status as automatically changed + */ + private Task checkRevisionStep(Identity assessedIdentity, BusinessGroup assessedGroup, Task task) { + if(task != null) { + if(task != null && task.getTaskStatus() == TaskProcess.revision + && task.getRevisionsDueDate() != null + && task.getRevisionsDueDate().compareTo(new Date()) < 0) { + //push to the next step + task = gtaManager.nextStep(task, gtaNode, Role.auto); + doUpdateAttempts(assessedIdentity, assessedGroup); + } + } + return task; + } + + private boolean isSolutionVisible(Identity assessedIdentity, BusinessGroup assessedGroup, Task task) { + if(task != null) { + RepositoryEntry re = courseEnv.getCourseGroupManager().getCourseEntry(); + DueDate availableDate = gtaManager.getSolutionDueDate(task, assessedIdentity, assessedGroup, gtaNode, re, true); + boolean visible = availableDate == null || + (availableDate.getDueDate() != null && availableDate.getDueDate().compareTo(new Date()) <= 0); + if(visible) { + if(task.getTaskStatus() == TaskProcess.solution || task.getTaskStatus() == TaskProcess.grading || task.getTaskStatus() == TaskProcess.graded) { + // step solution or beyond + return true; + } else if((task == null || task.getTaskStatus() == TaskProcess.assignment || task.getTaskStatus() == TaskProcess.submit + || task.getTaskStatus() == TaskProcess.review || task.getTaskStatus() == TaskProcess.correction + || task.getTaskStatus() == TaskProcess.revision) + && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_ALL, false)) { + // steps before solution only if configured to + return true; + } + } + } + return false; + } + + private void doUpdateAttempts(Identity assessedIdentity, BusinessGroup assessedGroup) { + ICourse course = CourseFactory.loadCourse(courseEnv.getCourseGroupManager().getCourseEntry()); + if(GTAType.group.name().equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) { + List<Identity> identities = businessGroupService.getMembers(assessedGroup, GroupRoles.participant.name()); + for(Identity identity:identities) { + UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course); + gtaNode.incrementUserAttempts(uce, Role.auto); + } + } else { + UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper + .createAndInitUserCourseEnvironment(assessedIdentity, course); + gtaNode.incrementUserAttempts(assessedUserCourseEnv, Role.auto); + } } private String getAuthor(File file, VFSContainer container) { @@ -323,16 +781,99 @@ class GTANotifications { return author == null ? "" : author; } - private void appendSubscriptionItem(String notificationKey, String[] params, File file) { - cal.setTimeInMillis(file.lastModified()); - Date modDate = cal.getTime(); - if(modDate.compareTo(compareDate) >= 0) { + + private void appendSubscriptionItemForFile(String notificationKey, String[] params, Identity identity, + String fileCategory, File file, Date modificationDate, boolean coach) { + String idPath = "[Identity:" + identity.getKey() + "]"; + appendSubscriptionItemForFile(notificationKey, params, idPath, fileCategory, file, modificationDate, coach); + } + + private void appendSubscriptionItemForFile(String notificationKey, String[] params, BusinessGroup group, + String fileCategory, File file, Date modificationDate, boolean coach) { + String idPath = "[BusinessGroup:" + group.getKey() + "]"; + appendSubscriptionItemForFile(notificationKey, params, idPath, fileCategory, file, modificationDate, coach); + } + + private void appendSubscriptionItemForFile(String notificationKey, String[] params, String idPath, + String fileCategory, File file, Date modificationDate, boolean coach) { + if(modificationDate == null) { + cal.setTimeInMillis(file.lastModified()); + modificationDate = cal.getTime(); + } + if(modificationDate.compareTo(compareDate) >= 0) { String desc = translator.translate(notificationKey, params); String businessPath = subscriber.getPublisher().getBusinessPath(); + if(coach) { + businessPath += "[Coach:0]"; + } + if(StringHelper.containsNonWhitespace(idPath) ) { + businessPath += idPath; + } + if(StringHelper.containsNonWhitespace(fileCategory)) { + businessPath += fileCategory; + } + if(file != null) { + businessPath += "[path=" + file.getName() + ":0]"; + } String urlToSend = BusinessControlFactory.getInstance().getURLFromBusinessPathString(businessPath); String iconCssClass = GTANotificationsHandler.CSS_CLASS_ICON; - SubscriptionListItem item = new SubscriptionListItem(desc, urlToSend, businessPath, modDate, iconCssClass); + SubscriptionListItem item = new SubscriptionListItem(desc, urlToSend, businessPath, modificationDate, iconCssClass); items.add(item); } } + + private void appendSubscriptionItem(String notificationKey, String[] params, Identity identity, Date modificationDate, boolean coach) { + String path = "[Identity:" + identity.getKey() + "]"; + appendSubscriptionItem(notificationKey, params, path, modificationDate, coach); + } + + private void appendSubscriptionItem(String notificationKey, String[] params, BusinessGroup group, Date modificationDate, boolean coach) { + String path = "[BusinessGroup:" + group.getKey() + "]"; + appendSubscriptionItem(notificationKey, params, path, modificationDate, coach); + } + + private void appendSubscriptionItem(String notificationKey, String[] params, String path, Date modificationDate, boolean coach) { + String desc = translator.translate(notificationKey, params); + String businessPath = subscriber.getPublisher().getBusinessPath(); + if(coach) { + businessPath += "[Coach:0]"; + } + if(StringHelper.containsNonWhitespace(path)) { + businessPath += path; + } + String urlToSend = BusinessControlFactory.getInstance().getURLFromBusinessPathString(businessPath); + String iconCssClass = GTANotificationsHandler.CSS_CLASS_ICON; + SubscriptionListItem item = new SubscriptionListItem(desc, urlToSend, businessPath, modificationDate, iconCssClass); + items.add(item); + } + + private boolean notInStep(Task task, TaskProcess... status) { + boolean ok = true; + if(task == null) { + ok &= false; + } else { + for(TaskProcess state:status) { + ok &= task.getTaskStatus() != state; + } + } + return ok; + } + + private boolean inStep(Task task, TaskProcess... status) { + boolean ok = false; + if(task != null) { + for(TaskProcess state:status) { + ok |= task.getTaskStatus() == state; + } + } + return ok; + } + + private String getTaskName (Task task) { + if (!StringHelper.containsNonWhitespace(task.getTaskName())) { + return gtaNode.getShortTitle(); + } else { + return task.getTaskName(); + } + } } diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTANotificationsHandler.java b/src/main/java/org/olat/course/nodes/gta/manager/GTANotificationsHandler.java index 5b4bae76aaf679b997b58e57e7c88161b469e3cb..1ffba243223083209aba429739cee7c4659394a8 100644 --- a/src/main/java/org/olat/course/nodes/gta/manager/GTANotificationsHandler.java +++ b/src/main/java/org/olat/course/nodes/gta/manager/GTANotificationsHandler.java @@ -37,6 +37,7 @@ import org.olat.core.util.Util; import org.olat.course.nodes.gta.GTAManager; import org.olat.course.nodes.gta.ui.GTARunController; import org.olat.group.BusinessGroupService; +import org.olat.modules.assessment.manager.AssessmentEntryDAO; import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryService; import org.olat.user.UserManager; @@ -63,6 +64,8 @@ public class GTANotificationsHandler implements NotificationsHandler { private RepositoryService repositoryService; @Autowired private BusinessGroupService businessGroupService; + @Autowired + private AssessmentEntryDAO courseNodeAssessmentDao; @Override public SubscriptionInfo createSubscriptionInfo(Subscriber subscriber, Locale locale, Date compareDate) { @@ -70,20 +73,16 @@ public class GTANotificationsHandler implements NotificationsHandler { Date latestNews = p.getLatestNewsDate(); SubscriptionInfo si; - // there could be news for me, investigate deeper try { if (NotificationsManager.getInstance().isPublisherValid(p) && compareDate.before(latestNews)) { - Translator translator = Util.createPackageTranslator(GTARunController.class, locale); - GTANotifications notifications = new GTANotifications(subscriber, locale, compareDate, - repositoryService, gtaManager, businessGroupService, userManager); + repositoryService, gtaManager, businessGroupService, userManager, courseNodeAssessmentDao); List<SubscriptionListItem> items = notifications.getItems(); if(items.isEmpty()) { si = NotificationsManager.getInstance().getNoSubscriptionInfo(); } else { - String displayName = notifications.getDisplayName(); - String title = translator.translate("notifications.header", new String[]{ displayName }); + String title = notifications.getNotifificationHeader(); TitleItem titleItem = new TitleItem(title, CSS_CLASS_ICON); si = new SubscriptionInfo(subscriber.getKey(), p.getType(), titleItem, items); } diff --git a/src/main/java/org/olat/course/nodes/gta/model/DueDate.java b/src/main/java/org/olat/course/nodes/gta/model/DueDate.java new file mode 100644 index 0000000000000000000000000000000000000000..9171725652fbb2bf87dab6efcd95e9e45754e928 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/model/DueDate.java @@ -0,0 +1,68 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.model; + +import java.util.Date; + +/** + * + * Initial date: 3 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class DueDate { + + private final Date dueDate; + private final boolean relative; + private final String messageKey; + private final String messageArg; + + public DueDate(boolean relative, String messageKey, String messageArg) { + this(relative, null, messageKey, messageArg); + } + + public DueDate(boolean relative, Date dueDate) { + this(relative, dueDate, null, null); + } + + public DueDate(boolean relative, Date dueDate, String messageKey, String messageArg) { + this.dueDate = dueDate; + this.relative = relative; + this.messageKey = messageKey; + this.messageArg = messageArg; + } + + public Date getDueDate() { + return dueDate; + } + + public boolean isRelative() { + return relative; + } + + public String getMessageKey() { + return messageKey; + } + + public String getMessageArg() { + return messageArg; + } + +} diff --git a/src/main/java/org/olat/course/nodes/gta/model/TaskDueDateImpl.java b/src/main/java/org/olat/course/nodes/gta/model/TaskDueDateImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..5ea86b0b07205bfaeaec480bd38bec119110805c --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/model/TaskDueDateImpl.java @@ -0,0 +1,383 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Parameter; +import org.olat.basesecurity.IdentityImpl; +import org.olat.core.id.CreateInfo; +import org.olat.core.id.Identity; +import org.olat.core.id.ModifiedInfo; +import org.olat.core.id.Persistable; +import org.olat.core.util.StringHelper; +import org.olat.course.nodes.gta.TaskDueDate; +import org.olat.course.nodes.gta.TaskList; +import org.olat.course.nodes.gta.TaskProcess; +import org.olat.group.BusinessGroup; +import org.olat.group.BusinessGroupImpl; + +/** + * + * Only to update the due dates. + * + * Initial date: 25.02.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Entity(name="gtataskduedate") +@Table(name="o_gta_task") +@NamedQueries({ + @NamedQuery(name="dueDateTaskByTask", query="select duedates from gtataskduedate duedates where duedates.key=:taskKey"), +}) +public class TaskDueDateImpl implements TaskDueDate, CreateInfo, Persistable, ModifiedInfo { + + private static final long serialVersionUID = 4202873369981813454L; + + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "enhanced-sequence", parameters={ + @Parameter(name="sequence_name", value="hibernate_unique_key"), + @Parameter(name="force_table_use", value="true"), + @Parameter(name="optimizer", value="legacy-hilo"), + @Parameter(name="value_column", value="next_hi"), + @Parameter(name="increment_size", value="32767"), + @Parameter(name="initial_value", value="32767") + }) + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="lastmodified", nullable=false, insertable=true, updatable=true) + private Date lastModified; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_assignment_date", nullable=true, insertable=true, updatable=false) + private Date assignmentDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_submission_date", nullable=true, insertable=true, updatable=false) + private Date submissionDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_submission_revisions_date", nullable=true, insertable=true, updatable=false) + private Date submissionRevisionsDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_collection_date", nullable=true, insertable=true, updatable=false) + private Date collectionDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_allow_reset_date", nullable=true, insertable=true, updatable=true) + private Date allowResetDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_acceptation_date", nullable=true, insertable=true, updatable=false) + private Date acceptationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_solution_date", nullable=true, insertable=true, updatable=false) + private Date solutionDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_graduation_date", nullable=true, insertable=true, updatable=false) + private Date graduationDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_assignment_due_date", nullable=true, insertable=true, updatable=true) + private Date assignmentDueDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_submission_due_date", nullable=true, insertable=true, updatable=true) + private Date submissionDueDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_revisions_due_date", nullable=true, insertable=true, updatable=true) + private Date revisionsDueDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_solution_due_date", nullable=true, insertable=true, updatable=true) + private Date solutionDueDate; + + @Column(name="g_status", nullable=false, insertable=true, updatable=false) + private String status; + + @Column(name="g_rev_loop", nullable=false, insertable=true, updatable=false) + private int revisionLoop; + + @Column(name="g_taskname", nullable=true, insertable=true, updatable=false) + private String taskName; + + @ManyToOne(targetEntity=TaskListImpl.class,fetch=FetchType.LAZY,optional=false) + @JoinColumn(name="fk_tasklist", nullable=false, insertable=true, updatable=false) + private TaskList taskList; + + @ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_identity", nullable=true, insertable=true, updatable=false) + private Identity identity; + + @ManyToOne(targetEntity=BusinessGroupImpl.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_businessgroup", nullable=true, insertable=true, updatable=false) + private BusinessGroup businessGroup; + + @ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_allow_reset_identity", nullable=true, insertable=true, updatable=false) + private Identity allowResetIdentity; + + @Override + public Long getKey() { + return key; + } + + @Override + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date date) { + this.creationDate = date; + } + + @Override + public Date getLastModified() { + return lastModified; + } + + @Override + public void setLastModified(Date date) { + this.lastModified = date; + } + + @Override + public Identity getIdentity() { + return identity; + } + + public void setIdentity(Identity identity) { + this.identity = identity; + } + + @Override + public BusinessGroup getBusinessGroup() { + return businessGroup; + } + + public void setBusinessGroup(BusinessGroup businessGroup) { + this.businessGroup = businessGroup; + } + + @Override + public String getTaskName() { + return taskName; + } + + public void setTaskName(String taskName) { + this.taskName = taskName; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Override + public Date getAssignmentDate() { + return assignmentDate; + } + + public void setAssignmentDate(Date assignmentDate) { + this.assignmentDate = assignmentDate; + } + + @Override + public Date getSubmissionDate() { + return submissionDate; + } + + public void setSubmissionDate(Date submissionDate) { + this.submissionDate = submissionDate; + } + + @Override + public Date getSubmissionRevisionsDate() { + return submissionRevisionsDate; + } + + public void setSubmissionRevisionsDate(Date submissionRevisionsDate) { + this.submissionRevisionsDate = submissionRevisionsDate; + } + + @Override + public Date getCollectionDate() { + return collectionDate; + } + + public void setCollectionDate(Date collectionDate) { + this.collectionDate = collectionDate; + } + + @Override + public Date getAllowResetDate() { + return allowResetDate; + } + + public void setAllowResetDate(Date allowResetDate) { + this.allowResetDate = allowResetDate; + } + + @Override + public Identity getAllowResetIdentity() { + return allowResetIdentity; + } + + public void setAllowResetIdentity(Identity allowResetIdentity) { + this.allowResetIdentity = allowResetIdentity; + } + + @Override + public Date getAcceptationDate() { + return acceptationDate; + } + + public void setAcceptationDate(Date acceptationDate) { + this.acceptationDate = acceptationDate; + } + + @Override + public Date getSolutionDate() { + return solutionDate; + } + + public void setSolutionDate(Date solutionDate) { + this.solutionDate = solutionDate; + } + + @Override + public Date getGraduationDate() { + return graduationDate; + } + + public void setGraduationDate(Date graduationDate) { + this.graduationDate = graduationDate; + } + + @Override + public Date getAssignmentDueDate() { + return assignmentDueDate; + } + + public void setAssignmentDueDate(Date assignmentDueDate) { + this.assignmentDueDate = assignmentDueDate; + } + + @Override + public Date getSubmissionDueDate() { + return submissionDueDate; + } + + public void setSubmissionDueDate(Date submissionDueDate) { + this.submissionDueDate = submissionDueDate; + } + + @Override + public Date getRevisionsDueDate() { + return revisionsDueDate; + } + + public void setRevisionsDueDate(Date revisionsDueDate) { + this.revisionsDueDate = revisionsDueDate; + } + + @Override + public Date getSolutionDueDate() { + return solutionDueDate; + } + + public void setSolutionDueDate(Date solutionDueDate) { + this.solutionDueDate = solutionDueDate; + } + + @Override + public TaskProcess getTaskStatus() { + if(StringHelper.containsNonWhitespace(status)) { + return TaskProcess.valueOf(status); + } + return null; + } + + public void setTaskStatus(TaskProcess taskStatus) { + if(taskStatus == null) { + status = null; + } else { + status = taskStatus.name(); + } + } + + @Override + public int getRevisionLoop() { + return revisionLoop; + } + + public void setRevisionLoop(int revisionLoop) { + this.revisionLoop = revisionLoop; + } + + @Override + public TaskList getTaskList() { + return taskList; + } + + public void setTaskList(TaskList taskList) { + this.taskList = taskList; + } + + @Override + public int hashCode() { + return key == null ? 83544 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(obj == this) { + return true; + } + if(obj instanceof TaskDueDateImpl) { + TaskDueDateImpl task = (TaskDueDateImpl)obj; + return key != null && key.equals(task.getKey()); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/model/TaskImpl.java b/src/main/java/org/olat/course/nodes/gta/model/TaskImpl.java index d167a1a160f8fd8cf6bb58f29b74c550f62ec263..e4fe25928042a896a20f7a92740601cae94cf588 100644 --- a/src/main/java/org/olat/course/nodes/gta/model/TaskImpl.java +++ b/src/main/java/org/olat/course/nodes/gta/model/TaskImpl.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -90,6 +91,48 @@ public class TaskImpl implements Task, CreateInfo, Persistable, ModifiedInfo { @Temporal(TemporalType.TIMESTAMP) @Column(name="g_assignment_date", nullable=true, insertable=true, updatable=true) private Date assignmentDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_submission_date", nullable=true, insertable=true, updatable=true) + private Date submissionDate; + @Column(name="g_submission_ndocs", nullable=true, insertable=true, updatable=true) + private Integer submissionNumOfDocs; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_submission_revisions_date", nullable=true, insertable=true, updatable=true) + private Date submissionRevisionsDate; + @Column(name="g_submission_revisions_ndocs", nullable=true, insertable=true, updatable=true) + private Integer submissionRevisionsNumOfDocs; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_collection_date", nullable=true, insertable=true, updatable=true) + private Date collectionDate; + @Column(name="g_collection_ndocs", nullable=true, insertable=true, updatable=true) + private Integer collectionNumOfDocs; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_allow_reset_date", nullable=true, insertable=true, updatable=true) + private Date allowResetDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_acceptation_date", nullable=true, insertable=true, updatable=true) + private Date acceptationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_solution_date", nullable=true, insertable=true, updatable=true) + private Date solutionDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_graduation_date", nullable=true, insertable=true, updatable=true) + private Date graduationDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_assignment_due_date", nullable=true, insertable=true, updatable=false) + private Date assignmentDueDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_submission_due_date", nullable=true, insertable=true, updatable=false) + private Date submissionDueDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_revisions_due_date", nullable=true, insertable=true, updatable=false) + private Date revisionsDueDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_solution_due_date", nullable=true, insertable=true, updatable=false) + private Date solutionDueDate; @Column(name="g_status", nullable=false, insertable=true, updatable=true) private String status; @@ -112,6 +155,10 @@ public class TaskImpl implements Task, CreateInfo, Persistable, ModifiedInfo { @JoinColumn(name="fk_businessgroup", nullable=true, insertable=true, updatable=false) private BusinessGroup businessGroup; + @ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_allow_reset_identity", nullable=true, insertable=true, updatable=true) + private Identity allowResetIdentity; + @Override public Long getKey() { return key; @@ -179,6 +226,138 @@ public class TaskImpl implements Task, CreateInfo, Persistable, ModifiedInfo { public void setAssignmentDate(Date assignmentDate) { this.assignmentDate = assignmentDate; } + + @Override + public Date getSubmissionDate() { + return submissionDate; + } + + public void setSubmissionDate(Date submissionDate) { + this.submissionDate = submissionDate; + } + + public Integer getSubmissionNumOfDocs() { + return submissionNumOfDocs; + } + + public void setSubmissionNumOfDocs(Integer submissionNumOfDocs) { + this.submissionNumOfDocs = submissionNumOfDocs; + } + + @Override + public Date getSubmissionRevisionsDate() { + return submissionRevisionsDate; + } + + public void setSubmissionRevisionsDate(Date submissionRevisionsDate) { + this.submissionRevisionsDate = submissionRevisionsDate; + } + + public Integer getSubmissionRevisionsNumOfDocs() { + return submissionRevisionsNumOfDocs; + } + + public void setSubmissionRevisionsNumOfDocs(Integer submissionRevisionsNumOfDocs) { + this.submissionRevisionsNumOfDocs = submissionRevisionsNumOfDocs; + } + + @Override + public Date getCollectionDate() { + return collectionDate; + } + + public void setCollectionDate(Date collectionDate) { + this.collectionDate = collectionDate; + } + + public Integer getCollectionNumOfDocs() { + return collectionNumOfDocs; + } + + public void setCollectionNumOfDocs(Integer collectionNumOfDocs) { + this.collectionNumOfDocs = collectionNumOfDocs; + } + + @Override + public Date getAllowResetDate() { + return allowResetDate; + } + + public void setAllowResetDate(Date allowResetDate) { + this.allowResetDate = allowResetDate; + } + + @Override + public Identity getAllowResetIdentity() { + return allowResetIdentity; + } + + public void setAllowResetIdentity(Identity allowResetIdentity) { + this.allowResetIdentity = allowResetIdentity; + } + + @Override + public Date getAcceptationDate() { + return acceptationDate; + } + + public void setAcceptationDate(Date acceptationDate) { + this.acceptationDate = acceptationDate; + } + + @Override + public Date getSolutionDate() { + return solutionDate; + } + + public void setSolutionDate(Date solutionDate) { + this.solutionDate = solutionDate; + } + + @Override + public Date getGraduationDate() { + return graduationDate; + } + + public void setGraduationDate(Date graduationDate) { + this.graduationDate = graduationDate; + } + + @Override + public Date getAssignmentDueDate() { + return assignmentDueDate; + } + + public void setAssignmentDueDate(Date assignmentDueDate) { + this.assignmentDueDate = assignmentDueDate; + } + + @Override + public Date getSubmissionDueDate() { + return submissionDueDate; + } + + public void setSubmissionDueDate(Date submissionDueDate) { + this.submissionDueDate = submissionDueDate; + } + + @Override + public Date getRevisionsDueDate() { + return revisionsDueDate; + } + + public void setRevisionsDueDate(Date revisionsDueDate) { + this.revisionsDueDate = revisionsDueDate; + } + + @Override + public Date getSolutionDueDate() { + return solutionDueDate; + } + + public void setSolutionDueDate(Date solutionDueDate) { + this.solutionDueDate = solutionDueDate; + } @Override public TaskProcess getTaskStatus() { diff --git a/src/main/java/org/olat/course/nodes/gta/model/TaskLightImpl.java b/src/main/java/org/olat/course/nodes/gta/model/TaskLightImpl.java index 78acaf8a4d03dfd128951ff3a8e5699417c86345..8757c264f97c321765353093b587cddb8df491c0 100644 --- a/src/main/java/org/olat/course/nodes/gta/model/TaskLightImpl.java +++ b/src/main/java/org/olat/course/nodes/gta/model/TaskLightImpl.java @@ -78,6 +78,34 @@ public class TaskLightImpl implements TaskLight, CreateInfo, Persistable, Modifi @Temporal(TemporalType.TIMESTAMP) @Column(name="g_assignment_date", nullable=true, insertable=true, updatable=true) private Date assignmentDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_submission_date", nullable=true, insertable=true, updatable=true) + private Date submissionDate; + @Column(name="g_submission_ndocs", nullable=true, insertable=true, updatable=true) + private Integer submissionNumOfDocs; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_submission_revisions_date", nullable=true, insertable=true, updatable=true) + private Date submissionRevisionsDate; + @Column(name="g_submission_revisions_ndocs", nullable=true, insertable=true, updatable=true) + private Integer submissionRevisionsNumOfDocs; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_collection_date", nullable=true, insertable=true, updatable=true) + private Date collectionDate; + @Column(name="g_collection_ndocs", nullable=true, insertable=true, updatable=true) + private Integer collectionNumOfDocs; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_assignment_due_date", nullable=true, insertable=true, updatable=false) + private Date assignmentDueDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_submission_due_date", nullable=true, insertable=true, updatable=false) + private Date submissionDueDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_revisions_due_date", nullable=true, insertable=true, updatable=false) + private Date revisionsDueDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_solution_due_date", nullable=true, insertable=true, updatable=false) + private Date solutionDueDate; @Column(name="g_status", nullable=false, insertable=false, updatable=false) private String status; @@ -173,6 +201,96 @@ public class TaskLightImpl implements TaskLight, CreateInfo, Persistable, Modifi public void setAssignmentDate(Date assignmentDate) { this.assignmentDate = assignmentDate; } + + @Override + public Date getSubmissionDate() { + return submissionDate; + } + + public void setSubmissionDate(Date submissionDate) { + this.submissionDate = submissionDate; + } + + @Override + public Integer getSubmissionNumOfDocs() { + return submissionNumOfDocs; + } + + public void setSubmissionNumOfDocs(Integer submissionNumOfDocs) { + this.submissionNumOfDocs = submissionNumOfDocs; + } + + @Override + public Date getSubmissionRevisionsDate() { + return submissionRevisionsDate; + } + + public void setSubmissionRevisionsDate(Date submissionRevisionsDate) { + this.submissionRevisionsDate = submissionRevisionsDate; + } + + @Override + public Integer getSubmissionRevisionsNumOfDocs() { + return submissionRevisionsNumOfDocs; + } + + public void setSubmissionRevisionsNumOfDocs(Integer submissionRevisionsNumOfDocs) { + this.submissionRevisionsNumOfDocs = submissionRevisionsNumOfDocs; + } + + @Override + public Date getCollectionDate() { + return collectionDate; + } + + public void setCollectionDate(Date collectionDate) { + this.collectionDate = collectionDate; + } + + @Override + public Integer getCollectionNumOfDocs() { + return collectionNumOfDocs; + } + + public void setCollectionNumOfDocs(Integer collectionNumOfDocs) { + this.collectionNumOfDocs = collectionNumOfDocs; + } + + @Override + public Date getAssignmentDueDate() { + return assignmentDueDate; + } + + public void setAssignmentDueDate(Date assignmentDueDate) { + this.assignmentDueDate = assignmentDueDate; + } + + @Override + public Date getSubmissionDueDate() { + return submissionDueDate; + } + + public void setSubmissionDueDate(Date submissionDueDate) { + this.submissionDueDate = submissionDueDate; + } + + @Override + public Date getRevisionsDueDate() { + return revisionsDueDate; + } + + public void setRevisionsDueDate(Date revisionsDueDate) { + this.revisionsDueDate = revisionsDueDate; + } + + @Override + public Date getSolutionDueDate() { + return solutionDueDate; + } + + public void setSolutionDueDate(Date solutionDueDate) { + this.solutionDueDate = solutionDueDate; + } @Override public TaskProcess getTaskStatus() { diff --git a/src/main/java/org/olat/course/nodes/gta/model/TaskRevisionDateImpl.java b/src/main/java/org/olat/course/nodes/gta/model/TaskRevisionDateImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..c2d1dcd368867d739752ffe92cfcbe9cf07d896e --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/model/TaskRevisionDateImpl.java @@ -0,0 +1,173 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Parameter; +import org.olat.core.id.CreateInfo; +import org.olat.core.id.Persistable; +import org.olat.core.util.StringHelper; +import org.olat.course.nodes.gta.Task; +import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.TaskRevisionDate; + +/** + * + * Initial date: 7 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Entity(name="gtataskrevisiondate") +@Table(name="o_gta_task_revision_date") +public class TaskRevisionDateImpl implements CreateInfo, Persistable, TaskRevisionDate { + + private static final long serialVersionUID = -1476103422622666128L; + + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "enhanced-sequence", parameters={ + @Parameter(name="sequence_name", value="hibernate_unique_key"), + @Parameter(name="force_table_use", value="true"), + @Parameter(name="optimizer", value="legacy-hilo"), + @Parameter(name="value_column", value="next_hi"), + @Parameter(name="increment_size", value="32767"), + @Parameter(name="initial_value", value="32767") + }) + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + + @Column(name="g_status", nullable=false, insertable=true, updatable=true) + private String status; + @Column(name="g_rev_loop", nullable=false, insertable=true, updatable=true) + private int revisionLoop; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="g_date", nullable=true, insertable=true, updatable=false) + private Date date; + + @ManyToOne(targetEntity=TaskImpl.class,fetch=FetchType.LAZY,optional=false) + @JoinColumn(name="fk_task", nullable=false, insertable=true, updatable=false) + private Task task; + + @Override + public Long getKey() { + return key; + } + + @Override + public Date getCreationDate() { + return creationDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Override + @Transient + public TaskProcess getTaskStatus() { + if(StringHelper.containsNonWhitespace(status)) { + return TaskProcess.valueOf(status); + } + return null; + } + + public void setTaskStatus(TaskProcess taskStatus) { + if(taskStatus == null) { + status = null; + } else { + status = taskStatus.name(); + } + } + + @Override + public int getRevisionLoop() { + return revisionLoop; + } + + public void setRevisionLoop(int revisionLoop) { + this.revisionLoop = revisionLoop; + } + + @Override + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + @Override + public Task getTask() { + return task; + } + + public void setTask(Task task) { + this.task = task; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public int hashCode() { + return key == null ? 848502 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(obj == this) { + return true; + } + if(obj instanceof TaskRevisionDateImpl) { + TaskRevisionDateImpl rev = (TaskRevisionDateImpl)obj; + return key != null && key.equals(rev.getKey()); + } + return super.equals(obj); + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } +} diff --git a/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java b/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java index bd6e616d02bb49e4359ca49e34ebe1aa8e05fb12..d0df4f448f207a97c20d282dde3f5b882fa5e97b 100644 --- a/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java +++ b/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java @@ -209,11 +209,13 @@ public abstract class AbstractDueDateTaskRuleSPI implements IdentitiesProviderRu } protected List<Identity> getGroupsToRemind(TaskList taskList, GTACourseNode gtaNode) { - List<Task> tasks = gtaManager.getTasks(taskList, gtaNode); Set<BusinessGroup> doneTasks = new HashSet<BusinessGroup>(); - for(Task task:tasks) { - if(task.getBusinessGroup() != null) { - doneTasks.add(task.getBusinessGroup()); + if(taskList != null) { + List<Task> tasks = gtaManager.getTasks(taskList, gtaNode); + for(Task task:tasks) { + if(task.getBusinessGroup() != null) { + doneTasks.add(task.getBusinessGroup()); + } } } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/AbstractAssignmentEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/AbstractAssignmentEditController.java index e83f0189e2e9da47a52776f71dd125b450099359..7e7248c6f6982df94edf7ab9c2457febf38bd685 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/AbstractAssignmentEditController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/AbstractAssignmentEditController.java @@ -311,8 +311,9 @@ abstract class AbstractAssignmentEditController extends FormBasicController { private void doCreateTask(UserRequest ureq) { newTaskCtrl = new NewTaskController(ureq, getWindowControl(), tasksContainer); listenTo(newTaskCtrl); - - cmc = new CloseableModalController(getWindowControl(), "close", newTaskCtrl.getInitialComponent()); + + String title = translate("create.task"); + cmc = new CloseableModalController(getWindowControl(), "close", newTaskCtrl.getInitialComponent(), true, title, false); listenTo(cmc); cmc.activate(); } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsTableModel.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsTableModel.java index fb64ab22515530e6e6e5f549ac52968d57ab86c8..3bf2a4178ea6ddd76240c19c9dddf59d2b26af9c 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsTableModel.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachGroupsTableModel.java @@ -25,6 +25,7 @@ import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.course.nodes.gta.ui.component.SubmissionDateCellRenderer; /** * @@ -63,6 +64,7 @@ public class CoachGroupsTableModel extends DefaultFlexiTableDataModel<CoachedGro case name: return row.getName(); case taskName: return row.getTaskName(); case taskStatus: return row.getTaskStatus(); + case submissionDate: return SubmissionDateCellRenderer.cascading(row); default: return "ERROR"; } } @@ -70,7 +72,8 @@ public class CoachGroupsTableModel extends DefaultFlexiTableDataModel<CoachedGro public enum CGCols { name("table.header.group.name"), taskName("table.header.group.taskName"), - taskStatus("table.header.group.step"); + taskStatus("table.header.group.step"), + submissionDate("table.header.submissionDate"); private final String i18nKey; diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java index 25cb932edd6b1982ef096edb51d2a078709027ac..d633a795238980dfe5977c1af921ce6a7f2ebe99 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java @@ -26,6 +26,7 @@ import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.course.nodes.gta.ui.component.SubmissionDateCellRenderer; import org.olat.user.propertyhandlers.UserPropertyHandler; /** @@ -71,8 +72,10 @@ public class CoachParticipantsTableModel extends DefaultFlexiTableDataModel<Coac return row.getIdentity().getIdentityName(); } else if(col == CGCols.taskStatus.ordinal()) { return row.getTaskStatus(); - } else if(col == CGCols.taskName.ordinal()) { + } else if(col == CGCols.taskName.ordinal()) { return row.getTaskName(); + } else if(col == CGCols.submissionDate.ordinal()) { + return SubmissionDateCellRenderer.cascading(row); } else if(col >= GTACoachedGroupGradingController.USER_PROPS_OFFSET) { int propIndex = col - GTACoachedGroupGradingController.USER_PROPS_OFFSET; return row.getIdentity().getIdentityProp(propIndex); @@ -83,7 +86,8 @@ public class CoachParticipantsTableModel extends DefaultFlexiTableDataModel<Coac public enum CGCols { username("username"), taskName("table.header.group.taskName"), - taskStatus("table.header.group.step"); + taskStatus("table.header.group.step"), + submissionDate("table.header.submissionDate"); private final String i18nKey; diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachedElementRow.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachedElementRow.java new file mode 100644 index 0000000000000000000000000000000000000000..6eb3de2b6c706c397e4d634c3da0ee4a38173dac --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachedElementRow.java @@ -0,0 +1,57 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.ui; + +import java.util.Date; + +import org.olat.course.nodes.gta.TaskLight; +import org.olat.course.nodes.gta.TaskProcess; + +/** + * Common interface for CoachedIdentityRow and CoachedGroupRow + * + * Initial date: 3 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface CoachedElementRow { + + public String getTaskName(); + + public TaskProcess getTaskStatus(); + + /** + * @return Date only if there is a due date and the task is not submitted. + */ + public Date getSubmissionDueDate(); + + public Date getSubmissionDate(); + + public Date getSubmissionRevisionsDate(); + + public Date getCollectionDate(); + + public Date getSyntheticSubmissionDate(); + + public boolean getHasSubmittedDocuments(); + + public TaskLight getTask(); + +} diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachedGroupRow.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachedGroupRow.java index 03ba415522b5f80ee7d0b38e3e93f3fb862ee607..bb7a58da910730edbcd1039cea812e8aa84279d0 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/CoachedGroupRow.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachedGroupRow.java @@ -19,6 +19,8 @@ */ package org.olat.course.nodes.gta.ui; +import java.util.Date; + import org.olat.course.nodes.gta.TaskLight; import org.olat.course.nodes.gta.TaskProcess; import org.olat.group.BusinessGroup; @@ -29,28 +31,68 @@ import org.olat.group.BusinessGroup; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class CoachedGroupRow { +public class CoachedGroupRow implements CoachedElementRow { private final TaskLight task; + private final Date submissionDueDate; + private final Date syntheticSubmissionDate; + private final boolean hasSubmittedDocuments; private final BusinessGroup businessGroup; - public CoachedGroupRow(BusinessGroup businessGroup, TaskLight task) { + public CoachedGroupRow(BusinessGroup businessGroup, TaskLight task, Date submissionDueDate, + Date syntheticSubmissionDate, boolean hasSubmittedDocuments) { this.task = task; this.businessGroup = businessGroup; + this.submissionDueDate = submissionDueDate; + this.hasSubmittedDocuments = hasSubmittedDocuments; + this.syntheticSubmissionDate = syntheticSubmissionDate; } public String getName() { return businessGroup.getName(); } - + + @Override public String getTaskName() { return task == null ? null : task.getTaskName(); } - + + @Override public TaskProcess getTaskStatus() { return task == null ? null : task.getTaskStatus(); } - + + @Override + public Date getSubmissionDate() { + return task == null ? null : task.getSubmissionDate(); + } + + @Override + public Date getSubmissionDueDate() { + return submissionDueDate; + } + + @Override + public Date getSubmissionRevisionsDate() { + return task == null ? null : task.getSubmissionRevisionsDate(); + } + + @Override + public Date getCollectionDate() { + return task == null ? null : task.getCollectionDate(); + } + + @Override + public Date getSyntheticSubmissionDate() { + return syntheticSubmissionDate; + } + + @Override + public boolean getHasSubmittedDocuments() { + return hasSubmittedDocuments; + } + + @Override public TaskLight getTask() { return task; } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java index ea03e53559f76fee35c7ab3094bf5c50d55186f6..5d8cea03f80f53fec68a994082c92018d9ada9ec 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java @@ -19,6 +19,8 @@ */ package org.olat.course.nodes.gta.ui; +import java.util.Date; + import org.olat.course.nodes.gta.TaskLight; import org.olat.course.nodes.gta.TaskProcess; import org.olat.user.UserPropertiesRow; @@ -29,24 +31,68 @@ import org.olat.user.UserPropertiesRow; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class CoachedIdentityRow { +public class CoachedIdentityRow implements CoachedElementRow { private final TaskLight task; + private final Date submissionDueDate; + private final Date syntheticSubmissionDate; + private final boolean hasSubmittedDocuments; private final UserPropertiesRow identity; - public CoachedIdentityRow(UserPropertiesRow identity, TaskLight task) { + public CoachedIdentityRow(UserPropertiesRow identity, TaskLight task, Date submissionDueDate, + Date syntheticSubmissionDate, boolean hasSubmittedDocuments) { this.identity = identity; this.task = task; + this.submissionDueDate = submissionDueDate; + this.hasSubmittedDocuments = hasSubmittedDocuments; + this.syntheticSubmissionDate = syntheticSubmissionDate; } - + + @Override public String getTaskName() { return task == null ? null : task.getTaskName(); } + @Override public TaskProcess getTaskStatus() { return task == null ? null : task.getTaskStatus(); } + + @Override + public Date getSubmissionDate() { + return task == null ? null : task.getSubmissionDate(); + } + + @Override + public Date getSubmissionDueDate() { + return submissionDueDate; + } + + @Override + public Date getSubmissionRevisionsDate() { + return task == null ? null : task.getSubmissionRevisionsDate(); + } + + @Override + public Date getCollectionDate() { + return task == null ? null : task.getCollectionDate(); + } + + @Override + public Date getSyntheticSubmissionDate() { + return syntheticSubmissionDate; + } + + @Override + public boolean getHasSubmittedDocuments() { + return hasSubmittedDocuments; + } + @Override + public TaskLight getTask() { + return task; + } + public UserPropertiesRow getIdentity() { return identity; } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/ConfirmResetTaskController.java b/src/main/java/org/olat/course/nodes/gta/ui/ConfirmResetTaskController.java new file mode 100644 index 0000000000000000000000000000000000000000..c4d21b509731b48f773acf655232a1a6007f5b91 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/ConfirmResetTaskController.java @@ -0,0 +1,114 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.ui; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.Task; +import org.olat.course.run.environment.CourseEnvironment; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 10 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ConfirmResetTaskController extends FormBasicController { + + private FormLink dontResetButton; + + private Task task; + private final GTACourseNode gtaNode; + private final CourseEnvironment courseEnv; + + @Autowired + private GTAManager gtaManager; + @Autowired + private UserManager userManager; + + public ConfirmResetTaskController(UserRequest ureq, WindowControl wControl, Task task, + GTACourseNode gtaNode, CourseEnvironment courseEnv) { + super(ureq, wControl, "participant_reset_task"); + this.task = task; + this.gtaNode = gtaNode; + this.courseEnv = courseEnv; + initForm(ureq); + } + + public Task getTask() { + return task; + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + if(formLayout instanceof FormLayoutContainer) { + FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; + String allower = userManager.getUserDisplayName(task.getAllowResetIdentity()); + String message = translate("participant.confirm.reset.task.text", new String[] { allower, task.getTaskName() }); + layoutCont.contextPut("msg", message); + } + + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + formLayout.add(buttonsCont); + uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); + dontResetButton = uifactory.addFormLink("participant.confirm.reset.task.nok", buttonsCont, Link.BUTTON); + uifactory.addFormSubmitButton("participant.confirm.reset.task.ok", buttonsCont); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + task = gtaManager.resetTask(task, gtaNode, courseEnv); + gtaManager.log("Reset task", "reset task", task, getIdentity(), getIdentity(), null, courseEnv, gtaNode); + fireEvent(ureq, Event.DONE_EVENT); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(dontResetButton == source) { + task = gtaManager.resetTaskRefused(task, gtaNode); + gtaManager.log("Refuse reset task", "refuse reset task", task, getIdentity(), getIdentity(), null, courseEnv, gtaNode); + fireEvent(ureq, Event.DONE_EVENT); + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/ConfirmRevisionsController.java b/src/main/java/org/olat/course/nodes/gta/ui/ConfirmRevisionsController.java new file mode 100644 index 0000000000000000000000000000000000000000..a8f1c42ee68b5695cc49aa8febc006267ae03c4e --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/ConfirmRevisionsController.java @@ -0,0 +1,128 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.ui; + +import java.io.File; +import java.util.Date; + +import org.olat.core.commons.persistence.DB; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.DateChooser; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +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.id.Identity; +import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.Task; +import org.olat.course.nodes.gta.TaskDueDate; +import org.olat.course.nodes.gta.TaskHelper; +import org.olat.course.run.environment.CourseEnvironment; +import org.olat.group.BusinessGroup; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 4 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ConfirmRevisionsController extends FormBasicController { + + private DateChooser revisionDueDateEl; + + private Task assignedTask; + private final GTACourseNode gtaNode; + private final Identity assessedIdentity; + private final BusinessGroup assessedGroup; + private final CourseEnvironment courseEnv; + + @Autowired + private DB dbInstance; + @Autowired + private GTAManager gtaManager; + + public ConfirmRevisionsController(UserRequest ureq, WindowControl wControl, Task assignedTask, + Identity assessedIdentity, BusinessGroup assessedGroup, + GTACourseNode gtaNode, CourseEnvironment courseEnv) { + super(ureq, wControl); + this.gtaNode = gtaNode; + this.courseEnv = courseEnv; + this.assignedTask = assignedTask; + this.assessedGroup = assessedGroup; + this.assessedIdentity = assessedIdentity; + initForm(ureq); + } + + public Task getTask() { + return assignedTask; + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + File documentsDir; + int iteration = assignedTask.getRevisionLoop(); + if(assessedGroup != null) { + documentsDir = gtaManager.getRevisedDocumentsCorrectionsDirectory(courseEnv, gtaNode, iteration, assessedGroup); + } else { + documentsDir = gtaManager.getRevisedDocumentsCorrectionsDirectory(courseEnv, gtaNode, iteration, assessedIdentity); + } + + boolean hasDocument = TaskHelper.hasDocuments(documentsDir); + if(!hasDocument) { + setFormWarning("coach.revisions.confirm.text.warn"); + } + + setFormDescription("coach.revisions.confirm.text"); + + Date revisionsDueDate = assignedTask.getRevisionsDueDate(); + revisionDueDateEl = uifactory.addDateChooser("revisions.duedate", revisionsDueDate, formLayout); + revisionDueDateEl.setDateChooserTimeEnabled(true); + + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + formLayout.add(buttonsCont); + uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); + uifactory.addFormSubmitButton("ok", buttonsCont); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + TaskDueDate dueDates = gtaManager.getDueDatesTask(assignedTask); + dueDates.setRevisionsDueDate(revisionDueDateEl.getDate()); + gtaManager.updateTaskDueDate(dueDates); + dbInstance.commit(); + // make sure the task is up to date + assignedTask = gtaManager.getTask(dueDates); + fireEvent(ureq, Event.DONE_EVENT); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/DirectoryController.java b/src/main/java/org/olat/course/nodes/gta/ui/DirectoryController.java index ab4cf8d3214e6cd7327969ca2c61b19b41a12c0a..6d997abfe85d8145dabbe5090c9975aec7727593 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/DirectoryController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/DirectoryController.java @@ -29,6 +29,7 @@ import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; import org.olat.core.commons.modules.singlepage.SinglePageController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.download.DisplayOrDownloadComponent; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.velocity.VelocityContainer; @@ -37,15 +38,20 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.media.FileMediaResource; import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.util.CSSHelper; +import org.olat.core.id.context.BusinessControlFactory; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; import org.olat.core.util.CodeHelper; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.io.SystemFileFilter; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; +import org.olat.course.nodes.gta.ui.component.DownloadDocumentMapper; import org.olat.fileresource.ZippedDirectoryMediaResource; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; @@ -56,11 +62,15 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class DirectoryController extends BasicController { +public class DirectoryController extends BasicController implements Activateable2 { private Link bulkReviewLink; + private final VelocityContainer mainVC; + private final DisplayOrDownloadComponent download; + private final String zipName; + private final String mapperUri; private final File documentsDir; private final VFSContainer documentsContainer; @@ -87,9 +97,13 @@ public class DirectoryController extends BasicController { format = Formatter.getInstance(ureq.getLocale()); - VelocityContainer mainVC = createVelocityContainer("documents_readonly"); + mainVC = createVelocityContainer("documents_readonly"); mainVC.contextPut("description", translate(i18nDescription)); + mapperUri = registerMapper(ureq, new DownloadDocumentMapper(documentsDir)); + download = new DisplayOrDownloadComponent("download", null); + mainVC.put("download", download); + if(StringHelper.containsNonWhitespace(i18nBulkDownload)) { bulkReviewLink = LinkFactory.createCustomLink("bulk", "bulk", null, Link.BUTTON + Link.NONTRANSLATED, mainVC, this); bulkReviewLink.setIconLeftCSS("o_icon o_icon_download"); @@ -135,6 +149,18 @@ public class DirectoryController extends BasicController { // } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + String path = BusinessControlFactory.getInstance().getPath(entries.get(0)); + File document = new File(documentsDir, path); + if(document.exists()) { + String url = mapperUri + "/" + document.getName(); + download.triggerFileDownload(url); + } + } + @Override protected void event(UserRequest ureq, Component source, Event event) { if(bulkReviewLink == source) { diff --git a/src/main/java/org/olat/course/nodes/gta/ui/DocumentUploadController.java b/src/main/java/org/olat/course/nodes/gta/ui/DocumentUploadController.java index 4026e0e3ebbb1b3cf7c81213f0b5f385be3bca78..486677e64f0567e03923351238b18aa4a50a715b 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/DocumentUploadController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/DocumentUploadController.java @@ -30,10 +30,11 @@ 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.FileUtils; import org.olat.course.nodes.gta.ui.SubmitDocumentsController.SubmittedSolution; /** - * + * * Initial date: 27.02.2015<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * @@ -43,11 +44,11 @@ public class DocumentUploadController extends FormBasicController { private FileElement fileEl; private final File fileToReplace; private final SubmittedSolution solution; - + public DocumentUploadController(UserRequest ureq, WindowControl wControl) { this(ureq, wControl, null, null); } - + public DocumentUploadController(UserRequest ureq, WindowControl wControl, SubmittedSolution solution, File fileToReplace) { super(ureq, wControl); this.solution = solution; @@ -62,29 +63,29 @@ public class DocumentUploadController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { formLayout.setElementCssClass("o_sel_course_gta_upload_form"); - + fileEl = uifactory.addFileElement(getWindowControl(), "file", "solution.file", formLayout); fileEl.setMandatory(true); fileEl.addActionListener(FormEvent.ONCHANGE); if(fileToReplace != null) { fileEl.setInitialFile(fileToReplace); } - + FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonCont.setRootForm(mainForm); formLayout.add(buttonCont); uifactory.addFormSubmitButton("save", buttonCont); uifactory.addFormCancelButton("cancel", buttonCont, ureq, getWindowControl()); } - + public String getUploadedFilename() { return fileEl.getUploadFileName(); } - + public File getUploadedFile() { return fileEl.getUploadFile(); } - + @Override protected void doDispose() { // @@ -93,13 +94,16 @@ public class DocumentUploadController extends FormBasicController { @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; - + fileEl.clearError(); if(fileEl.getUploadFile() == null) { fileEl.setErrorKey("form.mandatory.hover", null); allOk &= false; + } else if (!FileUtils.validateFilename(fileEl.getUploadFileName())) { + fileEl.setErrorKey("error.file.invalid", null); + allOk = false; } - + return allOk & super.validateFormLogic(ureq); } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/EditDueDatesController.java b/src/main/java/org/olat/course/nodes/gta/ui/EditDueDatesController.java new file mode 100644 index 0000000000000000000000000000000000000000..de24295be43424f108bb029508dd6eb989788b41 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/EditDueDatesController.java @@ -0,0 +1,143 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.ui; + +import java.util.Date; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.DateChooser; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +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.id.Identity; +import org.olat.core.util.Formatter; +import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.Task; +import org.olat.course.nodes.gta.TaskDueDate; +import org.olat.course.nodes.gta.model.DueDate; +import org.olat.group.BusinessGroup; +import org.olat.modules.ModuleConfiguration; +import org.olat.repository.RepositoryEntry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 4 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class EditDueDatesController extends FormBasicController { + + private DateChooser assignmentDueDateEl, submissionDueDateEl, revisionDueDateEl, solutionDueDateEl; + + private Task task; + private GTACourseNode gtaNode; + private Identity assessedIdentity; + private BusinessGroup assessedGroup; + private final Formatter formatter; + private final RepositoryEntry courseEntry; + + @Autowired + private GTAManager gtaManager; + + public EditDueDatesController(UserRequest ureq, WindowControl wControl, Task task, + Identity assessedIdentity, BusinessGroup assessedGroup, + GTACourseNode gtaNode, RepositoryEntry courseEntry) { + super(ureq, wControl); + this.task = task; + this.gtaNode = gtaNode; + this.courseEntry = courseEntry; + this.assessedGroup = assessedGroup; + this.assessedIdentity = assessedIdentity; + formatter = Formatter.getInstance(getLocale()); + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + ModuleConfiguration config = gtaNode.getModuleConfiguration(); + + Date assignmentDueDate = task.getAssignmentDueDate(); + assignmentDueDateEl = uifactory.addDateChooser("assignment.duedate", assignmentDueDate, formLayout); + assignmentDueDateEl.setDateChooserTimeEnabled(true); + DueDate standardAssignmentDueDate = gtaManager.getAssignmentDueDate(task, assessedIdentity, assessedGroup, gtaNode, courseEntry, false); + setDueDateExplanation(assignmentDueDateEl, standardAssignmentDueDate); + assignmentDueDateEl.setVisible(config.getBooleanSafe(GTACourseNode.GTASK_ASSIGNMENT)); + + Date submissionDueDate = task.getSubmissionDueDate(); + submissionDueDateEl = uifactory.addDateChooser("submission.duedate", submissionDueDate, formLayout); + submissionDueDateEl.setDateChooserTimeEnabled(true); + DueDate standardSubmissionDueDate = gtaManager.getSubmissionDueDate(task, assessedIdentity, assessedGroup, gtaNode, courseEntry, false); + setDueDateExplanation(submissionDueDateEl, standardSubmissionDueDate); + submissionDueDateEl.setVisible(config.getBooleanSafe(GTACourseNode.GTASK_SUBMIT)); + + Date revisionsDueDate = task.getRevisionsDueDate(); + revisionDueDateEl = uifactory.addDateChooser("revisions.duedate", revisionsDueDate, formLayout); + revisionDueDateEl.setDateChooserTimeEnabled(true); + revisionDueDateEl.setVisible(config.getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)); + + Date solutionDueDate = task.getSolutionDueDate(); + solutionDueDateEl = uifactory.addDateChooser("solution.duedate", solutionDueDate, formLayout); + solutionDueDateEl.setDateChooserTimeEnabled(true); + DueDate standardSolutionDueDate = gtaManager.getSolutionDueDate(task, assessedIdentity, assessedGroup, gtaNode, courseEntry, true); + setDueDateExplanation(solutionDueDateEl, standardSolutionDueDate); + solutionDueDateEl.setVisible(config.getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)); + + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + formLayout.add(buttonsCont); + uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); + uifactory.addFormSubmitButton("save", buttonsCont); + } + + private void setDueDateExplanation(DateChooser dateEl, DueDate standardDueDate) { + if(standardDueDate != null) { + if(standardDueDate.getDueDate() != null) { + dateEl.setExampleKey("duedate.standard", new String[] { formatter.formatDateAndTime(standardDueDate.getDueDate()) }); + } else if(standardDueDate.getMessageKey() != null) { + dateEl.setExampleKey(standardDueDate.getMessageKey(), new String[] { standardDueDate.getMessageArg() }); + } + } + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + TaskDueDate dueDates = gtaManager.getDueDatesTask(task); + dueDates.setAssignmentDueDate(assignmentDueDateEl.getDate()); + dueDates.setSubmissionDueDate(submissionDueDateEl.getDate()); + dueDates.setRevisionsDueDate(revisionDueDateEl.getDate()); + dueDates.setSolutionDueDate(solutionDueDateEl.getDate()); + dueDates = gtaManager.updateTaskDueDate(dueDates); + fireEvent(ureq, Event.DONE_EVENT); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/EditSolutionController.java b/src/main/java/org/olat/course/nodes/gta/ui/EditSolutionController.java index b4cd37a1ae6ff6c944d75c75b5e645dda8797211..e6929dc05c73028cb7149cb4a48564e19ddd1ed7 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/EditSolutionController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/EditSolutionController.java @@ -36,6 +36,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.FileUtils; import org.olat.core.util.StringHelper; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; @@ -44,32 +45,32 @@ import org.olat.course.nodes.gta.model.Solution; /** - * + * * Initial date: 24.02.2015<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class EditSolutionController extends FormBasicController { - + private TextElement titleEl; private FileElement fileEl; - + private final boolean replaceFile; private final Solution solution; private final File solutionDir; private final VFSContainer solutionContainer; private final String filenameToReplace; - + public EditSolutionController(UserRequest ureq, WindowControl wControl, File solutionDir, VFSContainer solutionContainer) { this(ureq, wControl, new Solution(), solutionDir, solutionContainer, false); } - + public EditSolutionController(UserRequest ureq, WindowControl wControl, Solution solution, File solutionDir, VFSContainer solutionContainer) { this(ureq, wControl, solution, solutionDir, solutionContainer, true); } - + private EditSolutionController(UserRequest ureq, WindowControl wControl, Solution solution, File solutionDir, VFSContainer solutionContainer, boolean replaceFile) { super(ureq, wControl); @@ -80,11 +81,11 @@ public class EditSolutionController extends FormBasicController { this.solutionContainer = solutionContainer; initForm(ureq); } - + public Solution getSolution() { return solution; } - + public String getFilenameToReplace() { return filenameToReplace; } @@ -92,7 +93,7 @@ public class EditSolutionController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { formLayout.setElementCssClass("o_sel_course_gta_upload_solution_form"); - + String title = solution.getTitle() == null ? "" : solution.getTitle(); titleEl = uifactory.addTextElement("title", "solution.title", 128, title, formLayout); titleEl.setElementCssClass("o_sel_course_gta_upload_solution_title"); @@ -107,7 +108,7 @@ public class EditSolutionController extends FormBasicController { fileEl.setInitialFile(currentFile); } } - + FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonCont.setRootForm(mainForm); formLayout.add(buttonCont); @@ -119,30 +120,33 @@ public class EditSolutionController extends FormBasicController { protected void doDispose() { // } - + @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; - + titleEl.clearError(); if(!StringHelper.containsNonWhitespace(titleEl.getValue())) { titleEl.setErrorKey("form.mandatory.hover", null); allOk &= false; } - + fileEl.clearError(); if(fileEl.getInitialFile() == null && fileEl.getUploadFile() == null) { fileEl.setErrorKey("form.mandatory.hover", null); allOk &= false; + } else if (!FileUtils.validateFilename(fileEl.getUploadFileName())) { + fileEl.setErrorKey("error.file.invalid", null); + allOk = false; } - + return allOk & super.validateFormLogic(ureq); } @Override protected void formOK(UserRequest ureq) { solution.setTitle(titleEl.getValue()); - + if(fileEl.getUploadFile() != null) { if(replaceFile && StringHelper.containsNonWhitespace(solution.getFilename())) { File currentFile = new File(solutionDir, solution.getFilename()); @@ -150,7 +154,7 @@ public class EditSolutionController extends FormBasicController { currentFile.delete(); } } - + String filename = fileEl.getUploadFileName(); if(!replaceFile) { File currentFile = new File(solutionDir, filename); @@ -158,14 +162,14 @@ public class EditSolutionController extends FormBasicController { filename = VFSManager.rename(solutionContainer, filename); } } - + solution.setFilename(filename); - + try { Path upload = fileEl.getUploadFile().toPath(); File newFile = new File(solutionDir, filename); Files.move(upload, newFile.toPath(), StandardCopyOption.REPLACE_EXISTING); - + VFSItem uploadedItem = solutionContainer.resolve(filename); if(uploadedItem instanceof MetaTagged) { MetaInfo metaInfo = ((MetaTagged)uploadedItem).getMetaInfo(); @@ -176,7 +180,7 @@ public class EditSolutionController extends FormBasicController { logError("", ex); } } - + fireEvent(ureq, Event.DONE_EVENT); } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/EditTaskController.java b/src/main/java/org/olat/course/nodes/gta/ui/EditTaskController.java index 328b62a4dd8e579a1f4d1c6d134666b55ac3d24c..21ac692a888cb24b5cc2cc0d2f292c298800a5ce 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/EditTaskController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/EditTaskController.java @@ -35,37 +35,38 @@ 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.FileUtils; import org.olat.core.util.StringHelper; import org.olat.course.nodes.gta.model.TaskDefinition; /** - * + * * Initial date: 24.02.2015<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class EditTaskController extends FormBasicController { - + private TextElement titleEl, descriptionEl; private FileElement fileEl; - + private final boolean replaceFile; private final TaskDefinition task; private final File taskContainer; - + private final String filenameToReplace; private final List<TaskDefinition> currentDefinitions; - + public EditTaskController(UserRequest ureq, WindowControl wControl, File taskContainer, List<TaskDefinition> currentDefinitions) { this(ureq, wControl, new TaskDefinition(), taskContainer, currentDefinitions, false); } - + public EditTaskController(UserRequest ureq, WindowControl wControl, TaskDefinition task, File taskContainer, List<TaskDefinition> currentDefinitions) { this(ureq, wControl, task, taskContainer, currentDefinitions, true); } - + public EditTaskController(UserRequest ureq, WindowControl wControl, TaskDefinition task, File taskContainer, List<TaskDefinition> currentDefinitions, boolean replaceFile) { @@ -77,11 +78,11 @@ public class EditTaskController extends FormBasicController { this.currentDefinitions = currentDefinitions; initForm(ureq); } - + public TaskDefinition getTask() { return task; } - + public String getFilenameToReplace() { return filenameToReplace; } @@ -89,15 +90,15 @@ public class EditTaskController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { formLayout.setElementCssClass("o_sel_course_gta_upload_task_form"); - + String title = task.getTitle() == null ? "" : task.getTitle(); titleEl = uifactory.addTextElement("title", "task.title", 128, title, formLayout); titleEl.setElementCssClass("o_sel_course_gta_upload_task_title"); titleEl.setMandatory(true); - + String description = task.getDescription() == null ? "" : task.getDescription(); descriptionEl = uifactory.addTextAreaElement("descr", "task.description", 2048, 10, -1, true, description, formLayout); - + fileEl = uifactory.addFileElement(getWindowControl(), "file", "task.file", formLayout); fileEl.setMandatory(true); fileEl.addActionListener(FormEvent.ONCHANGE); @@ -107,7 +108,7 @@ public class EditTaskController extends FormBasicController { fileEl.setInitialFile(currentFile); } } - + FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonCont.setRootForm(mainForm); formLayout.add(buttonCont); @@ -119,21 +120,24 @@ public class EditTaskController extends FormBasicController { protected void doDispose() { // } - + @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; - + titleEl.clearError(); if(!StringHelper.containsNonWhitespace(titleEl.getValue())) { titleEl.setErrorKey("form.mandatory.hover", null); allOk &= false; } - + fileEl.clearError(); if(fileEl.getInitialFile() == null && fileEl.getUploadFile() == null) { fileEl.setErrorKey("form.mandatory.hover", null); allOk &= false; + } else if (!FileUtils.validateFilename(fileEl.getUploadFileName())) { + fileEl.setErrorKey("error.file.invalid", null); + allOk = false; } else if(!replaceFile && fileEl.getUploadFile() != null) { String filename = fileEl.getUploadFileName(); File target = new File(taskContainer, filename); @@ -152,7 +156,7 @@ public class EditTaskController extends FormBasicController { } } } - + return allOk & super.validateFormLogic(ureq); } @@ -160,7 +164,7 @@ public class EditTaskController extends FormBasicController { protected void formOK(UserRequest ureq) { task.setTitle(titleEl.getValue()); task.setDescription(descriptionEl.getValue()); - + if(fileEl.getUploadFile() != null) { if(replaceFile && StringHelper.containsNonWhitespace(task.getFilename())) { int usage = 0; @@ -171,7 +175,7 @@ public class EditTaskController extends FormBasicController { } } } - + if(usage == 1) { File currentFile = new File(taskContainer, task.getFilename()); if(currentFile.exists()) { @@ -179,7 +183,7 @@ public class EditTaskController extends FormBasicController { } } } - + String filename = fileEl.getUploadFileName(); task.setFilename(filename); try { @@ -190,7 +194,7 @@ public class EditTaskController extends FormBasicController { logError("", ex); } } - + fireEvent(ureq, Event.DONE_EVENT); } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAAbstractController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAAbstractController.java index d2cf903fb61f0a5161c9cf6951f3a8ce17520f32..5f45a1b6e671dd74663f9919cf54e419ba90d1a5 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTAAbstractController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAAbstractController.java @@ -19,6 +19,7 @@ */ package org.olat.course.nodes.gta.ui; +import java.io.File; import java.util.Calendar; import java.util.Date; import java.util.List; @@ -39,6 +40,7 @@ import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.GenericEventListener; +import org.olat.core.util.io.SystemFilenameFilter; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; import org.olat.course.CourseModule; @@ -47,20 +49,20 @@ import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.manager.UserCourseInformationsManager; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; -import org.olat.course.nodes.gta.GTARelativeToDates; import org.olat.course.nodes.gta.GTAType; import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskList; import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.model.DueDate; import org.olat.course.nodes.gta.ui.events.TaskMultiUserEvent; import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; -import org.olat.repository.model.RepositoryEntryLifecycle; import org.springframework.beans.factory.annotation.Autowired; /** @@ -210,7 +212,7 @@ public abstract class GTAAbstractController extends BasicController implements G if(submit) { task = stepSubmit(ureq, task); } else if(task != null && task.getTaskStatus() == TaskProcess.submit) { - task = gtaManager.nextStep(task, gtaNode); + task = gtaManager.nextStep(task, gtaNode, Role.auto); } boolean reviewAndCorrection = config.getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION); @@ -218,7 +220,7 @@ public abstract class GTAAbstractController extends BasicController implements G if(reviewAndCorrection) { task = stepReviewAndCorrection(ureq, task); } else if(task != null && task.getTaskStatus() == TaskProcess.review) { - task = gtaManager.nextStep(task, gtaNode); + task = gtaManager.nextStep(task, gtaNode, Role.auto); } boolean revision = config.getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD); @@ -226,7 +228,7 @@ public abstract class GTAAbstractController extends BasicController implements G if(reviewAndCorrection && revision) { task = stepRevision(ureq, task); } else if(task != null && (task.getTaskStatus() == TaskProcess.revision || task.getTaskStatus() == TaskProcess.correction)) { - task = gtaManager.nextStep(task, gtaNode); + task = gtaManager.nextStep(task, gtaNode, Role.auto); } boolean solution = config.getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION); @@ -234,7 +236,7 @@ public abstract class GTAAbstractController extends BasicController implements G if(solution) { stepSolution(ureq, task); } else if(task != null && task.getTaskStatus() == TaskProcess.solution) { - task = gtaManager.nextStep(task, gtaNode); + task = gtaManager.nextStep(task, gtaNode, Role.auto); } boolean grading = config.getBooleanSafe(GTACourseNode.GTASK_GRADING); @@ -242,15 +244,19 @@ public abstract class GTAAbstractController extends BasicController implements G if(grading) { stepGrading(ureq, task); } else if(task != null && task.getTaskStatus() == TaskProcess.grading) { - task = gtaManager.nextStep(task, gtaNode); + task = gtaManager.nextStep(task, gtaNode, Role.auto); } mainVC.contextPut("changelogconfig", courseModule.isDisplayChangeLog()); + resetTask(ureq, task); + nodeLog(); collapsedContents(task); } + protected abstract void resetTask(UserRequest ureq, Task task); + protected final void collapsedContents(Task currentTask) { TaskProcess status = null; TaskProcess previousStatus = null; @@ -294,13 +300,13 @@ public abstract class GTAAbstractController extends BasicController implements G mainVC.contextPut("assignmentDueDate", dateAsString); mainVC.contextRemove("assignmentDueDateMsg"); - if(assignedTask != null && assignedTask.getTaskStatus() == TaskProcess.assignment - && date.compareTo(new Date()) < 0) { - //push to the next step - assignedTask = gtaManager.nextStep(assignedTask, gtaNode); + if(assignedTask != null && StringHelper.containsNonWhitespace(assignedTask.getTaskName()) + && assignedTask.getTaskStatus() == TaskProcess.assignment && date.compareTo(new Date()) < 0) { + //push to the next step if the task is blocked in assignment (it's a security) + assignedTask = gtaManager.nextStep(assignedTask, gtaNode, Role.auto); } - } else if(dueDate.getMessage() != null) { - mainVC.contextPut("assignmentDueDateMsg", dueDate.getMessage()); + } else if(dueDate.getMessageKey() != null) { + mainVC.contextPut("assignmentDueDateMsg", translate(dueDate.getMessageKey(), dueDate.getMessageArg())); mainVC.contextRemove("assignmentDueDate"); } } @@ -340,67 +346,11 @@ public abstract class GTAAbstractController extends BasicController implements G protected DueDate getAssignementDueDate(Task task) { if(assignmentDueDate == null) { - Date dueDate = gtaNode.getModuleConfiguration().getDateValue(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE); - boolean relativeDate = gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_RELATIVE_DATES); - if(relativeDate) { - int numOfDays = gtaNode.getModuleConfiguration().getIntegerSafe(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE_RELATIVE, -1); - String relativeTo = gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE_RELATIVE_TO); - if(numOfDays >= 0 && StringHelper.containsNonWhitespace(relativeTo)) { - assignmentDueDate = getReferenceDate(numOfDays, relativeTo, task); - } - } else if(dueDate != null) { - assignmentDueDate = new DueDate(dueDate); - } + assignmentDueDate = gtaManager.getAssignmentDueDate(task, assessedIdentity, assessedGroup, gtaNode, courseEntry, true); } return assignmentDueDate; } - protected DueDate getReferenceDate(int numOfDays, String relativeTo, Task assignedTask) { - DueDate dueDate = null; - if(numOfDays >= 0 && StringHelper.containsNonWhitespace(relativeTo)) { - GTARelativeToDates rel = GTARelativeToDates.valueOf(relativeTo); - Date referenceDate = null; - String message = null; - switch(rel) { - case courseStart: { - RepositoryEntryLifecycle lifecycle = courseEntry.getLifecycle(); - if(lifecycle != null && lifecycle.getValidFrom() != null) { - referenceDate = lifecycle.getValidFrom(); - } - break; - } - case courseLaunch: { - referenceDate = userCourseInformationsManager - .getInitialLaunchDate(courseEnv.getCourseGroupManager().getCourseResource(), assessedIdentity); - break; - } - case enrollment: { - referenceDate = repositoryService - .getEnrollmentDate(courseEntry, assessedIdentity); - break; - } - case assignment: { - if(assignedTask != null) { - referenceDate = assignedTask.getAssignmentDate(); - } else { - message = translate("relative.to.assignment.message", Integer.toString(numOfDays)); - } - break; - } - } - - if(referenceDate != null) { - Calendar cal = Calendar.getInstance(); - cal.setTime(referenceDate); - cal.add(Calendar.DATE, numOfDays); - dueDate = new DueDate(cal.getTime()); - } else if(message != null) { - dueDate = new DueDate(message); - } - } - return dueDate; - } - protected Task stepSubmit(@SuppressWarnings("unused")UserRequest ureq, Task assignedTask) { DueDate dueDate = getSubmissionDueDate(assignedTask); if(dueDate != null) { @@ -413,11 +363,12 @@ public abstract class GTAAbstractController extends BasicController implements G if(assignedTask != null && assignedTask.getTaskStatus() == TaskProcess.submit && date.compareTo(new Date()) < 0) { //push to the next step - assignedTask = gtaManager.nextStep(assignedTask, gtaNode); + int numOfDocs = getNumberOfSubmittedDocuments(); + assignedTask = gtaManager.submitTask(assignedTask, gtaNode, numOfDocs, Role.auto); doUpdateAttempts(); } - } else if(dueDate.getMessage() != null) { - mainVC.contextPut("submitDueDateMsg", dueDate.getMessage()); + } else if(dueDate.getMessageKey() != null) { + mainVC.contextPut("submitDueDateMsg", translate(dueDate.getMessageKey(), dueDate.getMessageArg())); mainVC.contextRemove("submitDueDate"); } } @@ -427,29 +378,57 @@ public abstract class GTAAbstractController extends BasicController implements G protected DueDate getSubmissionDueDate(Task assignedTask) { if(submissionDueDate == null) { - Date dueDate = gtaNode.getModuleConfiguration().getDateValue(GTACourseNode.GTASK_SUBMIT_DEADLINE); - boolean relativeDate = gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_RELATIVE_DATES); - if(relativeDate) { - int numOfDays = gtaNode.getModuleConfiguration().getIntegerSafe(GTACourseNode.GTASK_SUBMIT_DEADLINE_RELATIVE, -1); - String relativeTo = gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_SUBMIT_DEADLINE_RELATIVE_TO); - if(numOfDays >= 0 && StringHelper.containsNonWhitespace(relativeTo)) { - submissionDueDate = getReferenceDate(numOfDays, relativeTo, assignedTask); - } - } else if(dueDate != null) { - submissionDueDate = new DueDate(dueDate); - } + submissionDueDate = gtaManager.getSubmissionDueDate(assignedTask, assessedIdentity, assessedGroup, gtaNode, courseEntry, true); } return submissionDueDate; } + protected int getNumberOfSubmittedDocuments() { + File[] submittedDocuments; + if(GTAType.group.name().equals(config.getStringValue(GTACourseNode.GTASK_TYPE))) { + File documentsDir = gtaManager.getSubmitDirectory(courseEnv, gtaNode, assessedGroup); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + + } else { + File documentsDir = gtaManager.getSubmitDirectory(courseEnv, gtaNode, assessedIdentity); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + } + return submittedDocuments == null ? 0 : submittedDocuments.length; + } + protected Task stepReviewAndCorrection(@SuppressWarnings("unused")UserRequest ureq, Task assignedTask) { return assignedTask; } protected Task stepRevision(@SuppressWarnings("unused")UserRequest ureq, Task assignedTask) { + if(assignedTask != null && assignedTask.getRevisionsDueDate() != null) { + Date date = assignedTask.getRevisionsDueDate(); + String dateAsString = formatDueDate(new DueDate(false, date), false); + mainVC.contextPut("revisionDueDate", dateAsString); + if(assignedTask != null && assignedTask.getTaskStatus() == TaskProcess.revision + && date.compareTo(new Date()) < 0) { + //push to the next step + int numOfDocs = getNumberOfRevisionDocuments(assignedTask); + assignedTask = gtaManager.submitRevisions(assignedTask, gtaNode, numOfDocs, Role.auto); + doUpdateAttempts(); + } + } return assignedTask; } + protected int getNumberOfRevisionDocuments(Task assignedTask) { + File[] submittedDocuments; + int iteration = assignedTask.getRevisionLoop(); + if(GTAType.group.name().equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) { + File documentsDir = gtaManager.getRevisedDocumentsDirectory(courseEnv, gtaNode, iteration, assessedGroup); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + } else { + File documentsDir = gtaManager.getRevisedDocumentsDirectory(courseEnv, gtaNode, iteration, assessedIdentity); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + } + return submittedDocuments == null ? 0 : submittedDocuments.length; + } + protected Task stepSolution(@SuppressWarnings("unused")UserRequest ureq, Task assignedTask) { DueDate availableDate = getSolutionDueDate(assignedTask); if(availableDate != null) { @@ -457,8 +436,8 @@ public abstract class GTAAbstractController extends BasicController implements G String date = formatDueDate(availableDate, false); mainVC.contextPut("solutionAvailableDate", date); mainVC.contextRemove("solutionAvailableDateMsg"); - } else if(availableDate.getMessage() != null) { - mainVC.contextPut("solutionAvailableDateMsg", availableDate.getMessage()); + } else if(availableDate.getMessageKey() != null) { + mainVC.contextPut("solutionAvailableDateMsg", translate(availableDate.getMessageKey(), availableDate.getMessageArg())); mainVC.contextRemove("solutionAvailableDate"); } } @@ -467,17 +446,7 @@ public abstract class GTAAbstractController extends BasicController implements G protected DueDate getSolutionDueDate(Task assignedTask) { if(solutionDueDate == null) { - boolean relativeDate = gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_RELATIVE_DATES); - Date dueDate = gtaNode.getModuleConfiguration().getDateValue(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER); - if(relativeDate) { - int numOfDays = gtaNode.getModuleConfiguration().getIntegerSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER_RELATIVE, -1); - String relativeTo = gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER_RELATIVE_TO); - if(numOfDays >= 0 && StringHelper.containsNonWhitespace(relativeTo)) { - solutionDueDate = getReferenceDate(numOfDays, relativeTo, assignedTask); - } - } else if(dueDate != null) { - solutionDueDate = new DueDate(dueDate); - } + solutionDueDate = gtaManager.getSolutionDueDate(assignedTask, assessedIdentity, assessedGroup, gtaNode, courseEntry, true); } return solutionDueDate; } @@ -505,16 +474,17 @@ public abstract class GTAAbstractController extends BasicController implements G } protected void doUpdateAttempts() { + Role by = getDoer(); if(businessGroupTask) { List<Identity> identities = businessGroupService.getMembers(assessedGroup, GroupRoles.participant.name()); ICourse course = CourseFactory.loadCourse(courseEnv.getCourseGroupManager().getCourseEntry()); for(Identity identity:identities) { UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course); - gtaNode.incrementUserAttempts(uce); + gtaNode.incrementUserAttempts(uce, by); } } else { UserCourseEnvironment assessedUserCourseEnv = getAssessedUserCourseEnvironment(); - gtaNode.incrementUserAttempts(assessedUserCourseEnv); + gtaNode.incrementUserAttempts(assessedUserCourseEnv, by); } } @@ -561,30 +531,5 @@ public abstract class GTAAbstractController extends BasicController implements G .putAndSave(GTAStepPreferences.class, taskList.getKey().toString(), stepPreferences); } - public static class DueDate { - - private final Date dueDate; - private final String message; - - public DueDate(String message) { - this(null, message); - } - - public DueDate(Date dueDate) { - this(dueDate, null); - } - - public DueDate(Date dueDate, String message) { - this.dueDate = dueDate; - this.message = message; - } - - public Date getDueDate() { - return dueDate; - } - - public String getMessage() { - return message; - } - } + protected abstract Role getDoer(); } \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java index 198e40d767ade0a3b4474847e3167276885ae977..ef3b134b070c677a3269e5f231a3c64b30c641b0 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java @@ -178,14 +178,14 @@ public class GTAAssessmentDetailsController extends BasicController implements A private void doSelectBusinessGroup(UserRequest ureq, BusinessGroup group) { removeAsListenerAndDispose(coachingCtrl); - coachingCtrl = new GTACoachController(ureq, getWindowControl(), courseEnv, gtaNode, coachCourseEnv, group, true, true, true); + coachingCtrl = new GTACoachController(ureq, getWindowControl(), courseEnv, gtaNode, coachCourseEnv, group, true, true, true, true); listenTo(coachingCtrl); mainVC.put("selection", coachingCtrl.getInitialComponent()); } private void doSelectParticipant(UserRequest ureq, Identity identity) { removeAsListenerAndDispose(coachingCtrl); - coachingCtrl = new GTACoachController(ureq, getWindowControl(), courseEnv, gtaNode, coachCourseEnv, identity, false, false, true); + coachingCtrl = new GTACoachController(ureq, getWindowControl(), courseEnv, gtaNode, coachCourseEnv, identity, false, false, true, true); listenTo(coachingCtrl); mainVC.put("selection", coachingCtrl.getInitialComponent()); } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAAvailableTaskController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAAvailableTaskController.java index cfa2a53aaf99861a61fd880bf8b08852c4f1e310..184d4557ae5eb86a40d1b189ed2b220a507c6339 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTAAvailableTaskController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAAvailableTaskController.java @@ -60,8 +60,10 @@ import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.AssignmentResponse; import org.olat.course.nodes.gta.GTAManager; import org.olat.course.nodes.gta.GTAType; +import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskList; import org.olat.course.nodes.gta.model.TaskDefinition; +import org.olat.course.nodes.gta.ui.component.DescriptionWithTooltipCellRenderer; import org.olat.course.run.environment.CourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; @@ -269,11 +271,11 @@ public class GTAAvailableTaskController extends FormBasicController { showInfo("task.successfully.assigned"); fireEvent(ureq, Event.DONE_EVENT); gtaManager.log("Assignment", "task assigned", response.getTask(), getIdentity(), assessedIdentity, assessedGroup, courseEnv, gtaNode); - doSendConfirmationEmail(); + doSendConfirmationEmail(response.getTask()); } } - private void doSendConfirmationEmail() { + private void doSendConfirmationEmail(Task assignedTask) { MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); MailBundle bundle = new MailBundle(); @@ -287,9 +289,15 @@ public class GTAAvailableTaskController extends FormBasicController { contacts.add(assessedIdentity); } bundle.setContactList(contacts); - - String subject = translate("mail.confirm.assignment.subject"); - String body = translate("mail.confirm.assignment.body"); + + String[] args = new String[] { + getIdentity().getUser().getFirstName(), //0 first name + getIdentity().getUser().getLastName(), //1 last name + courseEnv.getCourseTitle(), //2 course name + assignedTask.getTaskName() //3 task + }; + String subject = translate("mail.confirm.assignment.subject", args); + String body = translate("mail.confirm.assignment.body", args); bundle.setContent(subject, body); mailManager.sendMessage(bundle); diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java index 6f6d494a2143d89227560b2e78e07ba0b7b9d612..0d52ac8954f9a1998026e4afe02b7e62597c16f4 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java @@ -34,9 +34,13 @@ 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.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.id.Identity; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.io.SystemFilenameFilter; import org.olat.core.util.mail.ContactList; @@ -49,12 +53,14 @@ import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskHelper; import org.olat.course.nodes.gta.TaskHelper.FilesLocked; import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.model.DueDate; import org.olat.course.nodes.gta.model.TaskDefinition; import org.olat.course.nodes.gta.ui.events.SubmitEvent; import org.olat.course.nodes.gta.ui.events.TaskMultiUserEvent; import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; +import org.olat.modules.assessment.Role; import org.olat.modules.co.ContactFormController; import org.olat.resource.OLATResource; import org.olat.user.DisplayPortraitController; @@ -67,8 +73,7 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class GTACoachController extends GTAAbstractController implements AssessmentFormCallback { - +public class GTACoachController extends GTAAbstractController implements AssessmentFormCallback, Activateable2 { private DirectoryController solutionsCtrl; private DirectoryController correctionsCtrl; @@ -78,12 +83,16 @@ public class GTACoachController extends GTAAbstractController implements Assessm private GTACoachedGroupGradingController groupGradingCtrl; private GTACoachedParticipantGradingController participantGradingCtrl; private GTACoachRevisionAndCorrectionsController revisionDocumentsCtrl; - private DialogBoxController confirmRevisionsCtrl, confirmReviewDocumentCtrl, confirmCollectCtrl, confirmBackToSubmissionCtrl; + private ConfirmRevisionsController confirmRevisionsCtrl; + private DialogBoxController confirmReviewDocumentCtrl, confirmCollectCtrl, confirmBackToSubmissionCtrl, confirmResetTaskCtrl; private ContactFormController emailController; private CloseableModalController cmc; - private Link reviewedButton, needRevisionsButton, emailLink, collectSubmissionsLink, backToSubmissionLink; + private Link reviewedButton, needRevisionsButton, emailLink, collectSubmissionsLink, backToSubmissionLink, resetTaskButton; + + private final boolean isAdmin; + private final boolean withReset; private final UserCourseEnvironment coachCourseEnv; @Autowired @@ -91,14 +100,16 @@ public class GTACoachController extends GTAAbstractController implements Assessm public GTACoachController(UserRequest ureq, WindowControl wControl, CourseEnvironment courseEnv, GTACourseNode gtaNode, UserCourseEnvironment coachCourseEnv, BusinessGroup assessedGroup, - boolean withTitle, boolean withGrading, boolean withSubscription) { - this(ureq, wControl, courseEnv, gtaNode, coachCourseEnv, assessedGroup, null, withTitle, withGrading, withSubscription); + boolean withTitle, boolean withGrading, boolean withSubscription, boolean withReset) { + this(ureq, wControl, courseEnv, gtaNode, coachCourseEnv, assessedGroup, null, + withTitle, withGrading, withSubscription, withReset); } public GTACoachController(UserRequest ureq, WindowControl wControl, CourseEnvironment courseEnv, GTACourseNode gtaNode, UserCourseEnvironment coachCourseEnv, Identity assessedIdentity, - boolean withTitle, boolean withGrading, boolean withSubscription) { - this(ureq, wControl, courseEnv, gtaNode, coachCourseEnv, null, assessedIdentity, withTitle, withGrading, withSubscription); + boolean withTitle, boolean withGrading, boolean withSubscription, boolean withReset) { + this(ureq, wControl, courseEnv, gtaNode, coachCourseEnv, null, assessedIdentity, + withTitle, withGrading, withSubscription, withReset); } /** @@ -114,9 +125,11 @@ public class GTACoachController extends GTAAbstractController implements Assessm */ private GTACoachController(UserRequest ureq, WindowControl wControl, CourseEnvironment courseEnv, GTACourseNode gtaNode, UserCourseEnvironment coachCourseEnv, BusinessGroup assessedGroup, Identity assessedIdentity, - boolean withTitle, boolean withGrading, boolean withSubscription) { + boolean withTitle, boolean withGrading, boolean withSubscription, boolean withReset) { super(ureq, wControl, gtaNode, courseEnv, null, assessedGroup, assessedIdentity, withTitle, withGrading, withSubscription); this.coachCourseEnv = coachCourseEnv; + this.withReset = withReset; + isAdmin = coachCourseEnv.isAdmin(); initContainer(ureq); process(ureq); } @@ -153,6 +166,12 @@ public class GTACoachController extends GTAAbstractController implements Assessm } } + if(withReset) { + resetTaskButton = LinkFactory.createCustomLink("coach.reset.button", "reset", "coach.reset.button", Link.BUTTON, mainVC, this); + resetTaskButton.setElementCssClass("o_sel_course_gta_reset"); + resetTaskButton.setVisible(false); + } + putInitialPanel(mainVC); } @@ -172,7 +191,7 @@ public class GTACoachController extends GTAAbstractController implements Assessm listenTo(assignedTaskCtrl); mainVC.put("assignedTask", assignedTaskCtrl.getInitialComponent()); } - + return assignedTask; } @@ -442,6 +461,18 @@ public class GTACoachController extends GTAAbstractController implements Assessm mainVC.put("grading", participantGradingCtrl.getInitialComponent()); } } + + @Override + protected void resetTask(UserRequest ureq, Task task) { + if(resetTaskButton != null) { + resetTaskButton.setUserObject(task); + boolean allowed = isAdmin && task != null + && (StringHelper.containsNonWhitespace(task.getTaskName()) || (task.getTaskStatus() == TaskProcess.submit && !StringHelper.containsNonWhitespace(task.getTaskName()))) + && (task.getTaskStatus() == TaskProcess.assignment || task.getTaskStatus() == TaskProcess.submit) + && GTACourseNode.GTASK_ASSIGNEMENT_TYPE_MANUAL.equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_ASSIGNEMENT_TYPE)); + resetTaskButton.setVisible(allowed); + } + } @Override protected void processEvent(TaskMultiUserEvent event) { @@ -457,7 +488,7 @@ public class GTACoachController extends GTAAbstractController implements Assessm task = gtaManager.getTask(assessedIdentity, taskList); } if(task != null) { - task = gtaManager.updateTask(task, TaskProcess.graded, gtaNode); + task = gtaManager.updateTask(task, TaskProcess.graded, gtaNode, Role.coach); cleanUpProcess(); process(ureq); } @@ -472,11 +503,28 @@ public class GTACoachController extends GTAAbstractController implements Assessm task = gtaManager.getTask(assessedIdentity, taskList); } if(task != null && task.getTaskStatus() == TaskProcess.graded) { - task = gtaManager.updateTask(task, TaskProcess.grading, gtaNode); + task = gtaManager.updateTask(task, TaskProcess.grading, gtaNode, Role.coach); cleanUpProcess(); process(ureq); } } + + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.size() <= 1) return; + + String type = entries.get(0).getOLATResourceable().getResourceableTypeName(); + if("Submit".equalsIgnoreCase(type)) { + if(submittedDocCtrl != null) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + submittedDocCtrl.activate(ureq, subEntries, null); + } + } else if("Revision".equalsIgnoreCase(type)) { + if(revisionDocumentsCtrl != null) { + revisionDocumentsCtrl.activate(ureq, entries, null); + } + } + } @Override protected void event(UserRequest ureq, Component source, Event event) { @@ -496,6 +544,8 @@ public class GTACoachController extends GTAAbstractController implements Assessm doConfirmCollectTask(ureq, (Task)collectSubmissionsLink.getUserObject()); } else if(backToSubmissionLink == source) { doConfirmBackToSubmission(ureq, (Task)backToSubmissionLink.getUserObject()); + } else if(resetTaskButton == source) { + doConfirmResetTask(ureq, (Task)resetTaskButton.getUserObject()); } super.event(ureq, source, event); } @@ -522,20 +572,26 @@ public class GTACoachController extends GTAAbstractController implements Assessm doReviewedDocument(ureq, assignedTask); } } else if(confirmRevisionsCtrl == source) { - if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { - Task assignedTask = (Task)confirmRevisionsCtrl.getUserObject(); - doRevisions(ureq, assignedTask); + if(event == Event.DONE_EVENT) { + doRevisions(ureq, confirmRevisionsCtrl.getTask()); } + cmc.deactivate(); + cleanUp(); } else if(confirmCollectCtrl == source) { if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { Task assignedTask = (Task)confirmCollectCtrl.getUserObject(); doCollectTask(ureq, assignedTask); } - } else if(confirmBackToSubmissionCtrl == source) { + } else if(confirmBackToSubmissionCtrl == source) { if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { Task assignedTask = (Task)confirmBackToSubmissionCtrl.getUserObject(); doBackToSubmission(ureq, assignedTask); } + } else if(confirmResetTaskCtrl == source) { + if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { + Task assignedTask = (Task)confirmResetTaskCtrl.getUserObject(); + doAllowResetTask(ureq, assignedTask); + } } else if(source == cmc) { doCloseMailForm(false); } else if (source == emailController) { @@ -543,6 +599,13 @@ public class GTACoachController extends GTAAbstractController implements Assessm } super.event(ureq, source, event); } + + private void cleanUp() { + removeAsListenerAndDispose(confirmRevisionsCtrl); + removeAsListenerAndDispose(cmc); + confirmRevisionsCtrl = null; + cmc = null; + } @Override protected void doDispose() { @@ -592,8 +655,7 @@ public class GTACoachController extends GTAAbstractController implements Assessm private void doReviewedDocument(UserRequest ureq, Task task) { //go to solution, grading or graded - TaskProcess nextStep = gtaManager.nextStep(TaskProcess.correction, gtaNode); - gtaManager.updateTask(task, nextStep, gtaNode); + gtaManager.reviewedTask(task, gtaNode); showInfo("coach.documents.successfully.reviewed"); gtaManager.log("Review", "documents reviewed", task, getIdentity(), assessedIdentity, assessedGroup, courseEnv, gtaNode); @@ -602,29 +664,18 @@ public class GTACoachController extends GTAAbstractController implements Assessm } private void doConfirmRevisions(UserRequest ureq, Task task) { - String title = translate("coach.revisions.confirm.title"); - String text = translate("coach.revisions.confirm.text"); - - File documentsDir; - if(GTAType.group.name().equals(config.getStringValue(GTACourseNode.GTASK_TYPE))) { - documentsDir = gtaManager.getCorrectionDirectory(courseEnv, gtaNode, assessedGroup); - } else { - documentsDir = gtaManager.getCorrectionDirectory(courseEnv, gtaNode, assessedIdentity); - } - - boolean hasDocument = TaskHelper.hasDocuments(documentsDir); - if(!hasDocument) { - String warning = translate("coach.revisions.confirm.text.warn"); - text = "<div class='o_warning'>" + warning + "</div>" + text; - } - - confirmRevisionsCtrl = activateOkCancelDialog(ureq, title, text, confirmRevisionsCtrl); + confirmRevisionsCtrl = new ConfirmRevisionsController(ureq, getWindowControl(), task, + assessedIdentity, assessedGroup, gtaNode, courseEnv); listenTo(confirmRevisionsCtrl); - confirmRevisionsCtrl.setUserObject(task); + + String title = translate("coach.revisions.confirm.title"); // same title as link button + cmc = new CloseableModalController(getWindowControl(), translate("close"), confirmRevisionsCtrl.getInitialComponent(), true, title); + listenTo(cmc); + cmc.activate(); } private void doRevisions(UserRequest ureq, Task task) { - gtaManager.updateTask(task, TaskProcess.revision, 1, gtaNode); + gtaManager.updateTask(task, TaskProcess.revision, 1, gtaNode, Role.coach); gtaManager.log("Review", "need revision", task, getIdentity(), assessedIdentity, assessedGroup, courseEnv, gtaNode); cleanUpProcess(); @@ -665,8 +716,17 @@ public class GTACoachController extends GTAAbstractController implements Assessm } private void doCollectTask(UserRequest ureq, Task task) { - TaskProcess review = gtaManager.nextStep(TaskProcess.submit, gtaNode); - task = gtaManager.updateTask(task, review, gtaNode); + File[] submittedDocuments; + if(GTAType.group.name().equals(config.getStringValue(GTACourseNode.GTASK_TYPE))) { + File documentsDir = gtaManager.getSubmitDirectory(courseEnv, gtaNode, assessedGroup); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + } else { + File documentsDir = gtaManager.getSubmitDirectory(courseEnv, gtaNode, getIdentity()); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + } + + int numOfDocs = submittedDocuments == null ? 0 : submittedDocuments.length; + task = gtaManager.collectTask(task, gtaNode, numOfDocs); showInfo("run.documents.successfully.submitted"); TaskMultiUserEvent event = new TaskMultiUserEvent(TaskMultiUserEvent.SUMBIT_TASK, @@ -700,7 +760,7 @@ public class GTACoachController extends GTAAbstractController implements Assessm private void doBackToSubmission(UserRequest ureq, Task task) { TaskProcess submit = gtaManager.previousStep(TaskProcess.review, gtaNode);//only submit allowed if(submit == TaskProcess.submit) { - task = gtaManager.updateTask(task, submit, gtaNode); + task = gtaManager.updateTask(task, submit, gtaNode, Role.coach); gtaManager.log("Back to submission", "revert status of task back to submission", task, getIdentity(), assessedIdentity, assessedGroup, courseEnv, gtaNode); @@ -709,6 +769,29 @@ public class GTACoachController extends GTAAbstractController implements Assessm } } + private void doConfirmResetTask(UserRequest ureq, Task assignedTask) { + String toName = null; + if (assessedGroup != null) { + toName = assessedGroup.getName(); + } else if (assessedIdentity != null) { + toName = userManager.getUserDisplayName(assessedIdentity); + } + + String title = translate("coach.reset.task.confirm.title"); + String text = translate("coach.reset.task.confirm.text", new String[]{ toName }); + confirmResetTaskCtrl = activateOkCancelDialog(ureq, title, text, confirmResetTaskCtrl); + confirmResetTaskCtrl.setUserObject(assignedTask); + listenTo(confirmResetTaskCtrl); + } + + private void doAllowResetTask(UserRequest ureq, Task assignedTask) { + gtaManager.allowResetTask(assignedTask, getIdentity(), gtaNode); + gtaManager.log("Allow reset task", "Allow the user to reset the task", assignedTask, getIdentity(), assessedIdentity, assessedGroup, courseEnv, gtaNode); + cleanUpProcess(); + process(ureq); + showInfo("info.task.reset.allowed", (String)null); + } + private void doOpenMailForm(UserRequest ureq) { // build recipient list ContactList contactList = null; @@ -764,5 +847,9 @@ public class GTACoachController extends GTAAbstractController implements Assessm } return taskDef; } - + + @Override + protected Role getDoer() { + return Role.coach; + } } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java index 6fc1d1d99255c519ae599e346c85387477d11ca7..c249466d6428afcc21b852c8061d75017b3da9a7 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java @@ -21,7 +21,9 @@ package org.olat.course.nodes.gta.ui; import java.io.File; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.olat.basesecurity.GroupRoles; import org.olat.core.gui.UserRequest; @@ -34,10 +36,14 @@ 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.controller.BasicController; +import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.io.SystemFilenameFilter; import org.olat.core.util.vfs.VFSContainer; @@ -57,6 +63,7 @@ import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; +import org.olat.modules.assessment.Role; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; @@ -66,13 +73,17 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class GTACoachRevisionAndCorrectionsController extends BasicController { +public class GTACoachRevisionAndCorrectionsController extends BasicController implements Activateable2 { private final VelocityContainer mainVC; private Link returnToRevisionsButton, closeRevisionsButton, collectButton; - private DirectoryController revisionsCtrl, correctionsCtrl; + + private CloseableModalController cmc; + private Map<Integer,DirectoryController> loopToRevisionCtrl = new HashMap<>(); + //private DirectoryController revisionsCtrl, correctionsCtrl; private SubmitDocumentsController uploadCorrectionsCtrl; - private DialogBoxController confirmCloseRevisionProcessCtrl, confirmReturnToRevisionsCtrl, confirmCollectCtrl; + private ConfirmRevisionsController confirmReturnToRevisionsCtrl; + private DialogBoxController confirmCloseRevisionProcessCtrl, confirmCollectCtrl; private Task assignedTask; private final int currentIteration; @@ -181,10 +192,11 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { boolean hasDocuments = TaskHelper.hasDocuments(documentsDir); if(hasDocuments) { - revisionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, + DirectoryController revisionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, "coach.revisions.description", "bulk.revisions", "revisions.zip"); listenTo(revisionsCtrl); mainVC.put(cmpName, revisionsCtrl.getInitialComponent()); + loopToRevisionCtrl.put(iteration, revisionsCtrl); } else if (assignedTask.getTaskStatus() == TaskProcess.revision) { String msg = "<i class='o_icon o_icon_error'> </i> " + translate("coach.corrections.rejected"); TextFactory.createTextComponentFromString(cmpName, msg, null, true, mainVC); @@ -207,7 +219,7 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { boolean hasDocuments = TaskHelper.hasDocuments(documentsDir); if(hasDocuments) { - correctionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, + DirectoryController correctionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, "run.coach.corrections.description", "bulk.review", "review"); listenTo(correctionsCtrl); mainVC.put(cmpName, correctionsCtrl.getInitialComponent()); @@ -256,6 +268,20 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { closeRevisionsButton.setVisible(!coachCourseEnv.isCourseReadOnly()); } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.size() <= 1) return; + + String type = entries.get(0).getOLATResourceable().getResourceableTypeName(); + if("Revision".equalsIgnoreCase(type)) { + int revisionLoop = entries.get(0).getOLATResourceable().getResourceableId().intValue(); + if(loopToRevisionCtrl.containsKey(revisionLoop)) { + List<ContextEntry> subEntriess = entries.subList(1, entries.size()); + loopToRevisionCtrl.get(revisionLoop).activate(ureq, subEntriess, null); + } + } + } + @Override protected void event(UserRequest ureq, Controller source, Event event) { if(uploadCorrectionsCtrl == source) { @@ -264,10 +290,12 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { gtaManager.log("Corrections", (SubmitEvent)event, aTask, getIdentity(), assessedIdentity, assessedGroup, courseEnv, gtaNode); } } else if(confirmReturnToRevisionsCtrl == source) { - if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { - doReturnToRevisions(); + if(event == Event.DONE_EVENT) { + doReturnToRevisions(confirmReturnToRevisionsCtrl.getTask()); fireEvent(ureq, Event.DONE_EVENT); } + cmc.deactivate(); + cleanUp(); } else if(confirmCloseRevisionProcessCtrl == source) { if(DialogBoxUIFactory.isOkEvent(event) || DialogBoxUIFactory.isYesEvent(event)) { doCloseRevisionProcess(); @@ -278,9 +306,16 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { doCollect(); fireEvent(ureq, Event.DONE_EVENT); } + } else if(cmc == source) { + cleanUp(); } super.event(ureq, source, event); } + + private void cleanUp() { + removeAsListenerAndDispose(cmc); + cmc = null; + } @Override protected void event(UserRequest ureq, Component source, Event event) { @@ -294,25 +329,16 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { } private void doConfirmReturnToRevisions(UserRequest ureq) { - String title = translate("coach.revisions.confirm.title"); - String text = translate("coach.revisions.confirm.text"); + if(confirmReturnToRevisionsCtrl != null) return; - File documentsDir; - int iteration = assignedTask.getRevisionLoop(); - if(businessGroupTask) { - documentsDir = gtaManager.getRevisedDocumentsCorrectionsDirectory(courseEnv, gtaNode, iteration, assessedGroup); - } else { - documentsDir = gtaManager.getRevisedDocumentsCorrectionsDirectory(courseEnv, gtaNode, iteration, assessedIdentity); - } - - boolean hasDocument = TaskHelper.hasDocuments(documentsDir); - if(!hasDocument) { - String warning = translate("coach.revisions.confirm.text.warn"); - text = "<div class='o_warning'>" + warning + "</div>" + text; - } - - confirmReturnToRevisionsCtrl = activateOkCancelDialog(ureq, title, text, confirmReturnToRevisionsCtrl); + confirmReturnToRevisionsCtrl = new ConfirmRevisionsController(ureq, getWindowControl(), assignedTask, + assessedIdentity, assessedGroup, gtaNode, courseEnv); listenTo(confirmReturnToRevisionsCtrl); + + String title = translate("coach.revisions.confirm.title"); // same title as link button + cmc = new CloseableModalController(getWindowControl(), translate("close"), confirmReturnToRevisionsCtrl.getInitialComponent(), true, title); + listenTo(cmc); + cmc.activate(); } private void doConfirmCollect(UserRequest ureq) { @@ -349,7 +375,7 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { } private void doCollect() { - assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.correction, gtaNode); + assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.correction, gtaNode, Role.coach); gtaManager.log("Collect revision", "revision collected", assignedTask, getIdentity(), assessedIdentity, assessedGroup, courseEnv, gtaNode); ICourse course = CourseFactory.loadCourse(courseEnv.getCourseResourceableId()); @@ -357,10 +383,10 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { List<Identity> identities = businessGroupService.getMembers(assessedGroup, GroupRoles.participant.name()); for(Identity identity:identities) { UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course); - gtaNode.incrementUserAttempts(userCourseEnv); + gtaNode.incrementUserAttempts(userCourseEnv, Role.coach); } } else { - gtaNode.incrementUserAttempts(assessedUserCourseEnv); + gtaNode.incrementUserAttempts(assessedUserCourseEnv, Role.coach); } TaskMultiUserEvent event = new TaskMultiUserEvent(TaskMultiUserEvent.SUBMIT_REVISION, @@ -369,8 +395,8 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { .fireEventToListenersOf(event, taskListEventResource); } - private void doReturnToRevisions() { - assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.revision, currentIteration + 1, gtaNode); + private void doReturnToRevisions(Task task) { + assignedTask = gtaManager.updateTask(task, TaskProcess.revision, currentIteration + 1, gtaNode, Role.coach); gtaManager.log("Revision", "need another revision", assignedTask, getIdentity(), assessedIdentity, assessedGroup, courseEnv, gtaNode); } @@ -382,8 +408,7 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController { } private void doCloseRevisionProcess() { - TaskProcess nextStep = gtaManager.nextStep(TaskProcess.correction, gtaNode); - assignedTask = gtaManager.updateTask(assignedTask, nextStep, gtaNode); + assignedTask = gtaManager.reviewedTask(assignedTask, gtaNode); gtaManager.log("Revision", "close revision", assignedTask, getIdentity(), assessedIdentity, assessedGroup, courseEnv, gtaNode); } } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java index 615de79921187b128ca83519efc5370620394099..ca06397e1a290a0d4647c54fdc6cb7a003c02361 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -19,6 +20,7 @@ */ package org.olat.course.nodes.gta.ui; +import java.io.File; import java.util.Collections; import java.util.List; @@ -28,6 +30,7 @@ import org.olat.core.commons.services.notifications.SubscriptionContext; import org.olat.core.commons.services.notifications.ui.ContextualSubscriptionController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.download.DisplayOrDownloadComponent; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.velocity.VelocityContainer; @@ -35,11 +38,19 @@ 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.controller.BasicController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.id.Identity; +import org.olat.core.id.context.BusinessControlFactory; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.resource.OresHelper; +import org.olat.course.archiver.ArchiveResource; import org.olat.course.groupsandrights.CourseGroupManager; +import org.olat.course.nodes.ArchiveOptions; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; import org.olat.course.nodes.gta.GTAType; +import org.olat.course.nodes.gta.ui.component.DownloadDocumentMapper; import org.olat.course.nodes.gta.ui.events.SelectBusinessGroupEvent; import org.olat.course.nodes.gta.ui.events.SelectIdentityEvent; import org.olat.course.run.environment.CourseEnvironment; @@ -47,6 +58,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.group.BusinessGroup; import org.olat.modules.ModuleConfiguration; +import org.olat.resource.OLATResource; import org.springframework.beans.factory.annotation.Autowired; /** @@ -55,14 +67,17 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class GTACoachSelectionController extends BasicController { +public class GTACoachSelectionController extends BasicController implements Activateable2 { private GTACoachController coachingCtrl; private GTACoachedGroupListController groupListCtrl; private GTACoachedParticipantListController participantListCtrl; - private final Link backLink; + private final Link backLink, downloadButton; private final VelocityContainer mainVC; + + private final String solutionMapperUri; + private final DisplayOrDownloadComponent solutionDownloadCmp; private final GTACourseNode gtaNode; private final CourseEnvironment courseEnv; @@ -86,6 +101,14 @@ public class GTACoachSelectionController extends BasicController { mainVC = createVelocityContainer("coach_selection"); backLink = LinkFactory.createLinkBack(mainVC, this); + File solutionsDir = gtaManager.getSolutionsDirectory(courseEnv, gtaNode); + solutionMapperUri = registerMapper(ureq, new DownloadDocumentMapper(solutionsDir)); + solutionDownloadCmp = new DisplayOrDownloadComponent("download", null); + mainVC.put("solutionDownload", solutionDownloadCmp); + + downloadButton = LinkFactory.createButton("bulk.download.title", mainVC, this); + downloadButton.setTranslator(getTranslator()); + publisherData = gtaManager.getPublisherData(courseEnv, gtaNode); subsContext = gtaManager.getSubscriptionContext(courseEnv, gtaNode); if (subsContext != null) { @@ -129,6 +152,33 @@ public class GTACoachSelectionController extends BasicController { // } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + String type = entries.get(0).getOLATResourceable().getResourceableTypeName(); + Long key = entries.get(0).getOLATResourceable().getResourceableId(); + if("Identity".equalsIgnoreCase(type)) { + if(participantListCtrl != null && participantListCtrl.hasIdentityKey(key)) { + Identity selectedIdentity = securityManager.loadIdentityByKey(key); + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + doSelectParticipant(ureq, selectedIdentity).activate(ureq, subEntries, entries.get(0).getTransientState()); + } + } else if("BusinessGroup".equalsIgnoreCase(type)) { + if(groupListCtrl != null) { + BusinessGroup group = groupListCtrl.getBusinessGroup(key); + if(group != null) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + doSelectBusinessGroup(ureq, group).activate(ureq, subEntries, entries.get(0).getTransientState()); + } + } + } else if("Solution".equals(type) && entries.size() > 1) { + String path = BusinessControlFactory.getInstance().getPath(entries.get(1)); + String url = solutionMapperUri + "/" + path; + solutionDownloadCmp.triggerFileDownload(url); + } + } + @Override protected void event(UserRequest ureq, Controller source, Event event) { if(groupListCtrl == source) { @@ -154,6 +204,8 @@ public class GTACoachSelectionController extends BasicController { protected void event(UserRequest ureq, Component source, Event event) { if(backLink == source) { back(); + } else if(downloadButton == source) { + doBulkDownload(ureq); } } @@ -169,21 +221,39 @@ public class GTACoachSelectionController extends BasicController { } if (groupListCtrl != null) { groupListCtrl.updateModel(); - } } - private void doSelectBusinessGroup(UserRequest ureq, BusinessGroup group) { + private void doBulkDownload(UserRequest ureq) { + if (participantListCtrl != null) { + ArchiveOptions asOptions = new ArchiveOptions(); + asOptions.setIdentities(participantListCtrl.getAssessableIdentities()); + OLATResource ores = courseEnv.getCourseGroupManager().getCourseResource(); + ArchiveResource resource = new ArchiveResource(gtaNode, ores, asOptions, getLocale()); + ureq.getDispatchResult().setResultingMediaResource(resource); + } else if (groupListCtrl != null) { + OLATResource ores = courseEnv.getCourseGroupManager().getCourseResource(); + GroupBulkDownloadResource resource = new GroupBulkDownloadResource(gtaNode, ores, groupListCtrl.getCoachedGroups(), getLocale()); + ureq.getDispatchResult().setResultingMediaResource(resource); + } + } + + private Activateable2 doSelectBusinessGroup(UserRequest ureq, BusinessGroup group) { removeAsListenerAndDispose(coachingCtrl); - coachingCtrl = new GTACoachController(ureq, getWindowControl(), courseEnv, gtaNode, coachCourseEnv, group, true, true, false); + + WindowControl swControl = addToHistory(ureq, OresHelper.clone(group), null); + coachingCtrl = new GTACoachController(ureq, swControl, courseEnv, gtaNode, coachCourseEnv, group, true, true, false, false); listenTo(coachingCtrl); mainVC.put("selection", coachingCtrl.getInitialComponent()); + return coachingCtrl; } - private void doSelectParticipant(UserRequest ureq, Identity identity) { + private Activateable2 doSelectParticipant(UserRequest ureq, Identity identity) { removeAsListenerAndDispose(coachingCtrl); - coachingCtrl = new GTACoachController(ureq, getWindowControl(), courseEnv, gtaNode, coachCourseEnv, identity, true, true, false); + WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableInstance("Identity", identity.getKey()), null); + coachingCtrl = new GTACoachController(ureq, swControl, courseEnv, gtaNode, coachCourseEnv, identity, true, true, false, false); listenTo(coachingCtrl); mainVC.put("selection", coachingCtrl.getInitialComponent()); + return coachingCtrl; } } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java index 597e2e4faf22c75510d11f1cc2be44091eebdd7d..0e83fbaef726e5525be575cab87c1432fcbd7012 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java @@ -72,6 +72,7 @@ import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; import org.springframework.beans.factory.annotation.Autowired; @@ -317,12 +318,12 @@ public class GTACoachedGroupGradingController extends FormBasicController { if(assignedTask == null) { assignedTask = gtaManager.createTask(null, taskList, TaskProcess.graded, assessedGroup, null, gtaNode); } else { - assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.graded, gtaNode); + assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.graded, gtaNode, Role.coach); } } private void doReopenAssessment(UserRequest ureq) { - assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.grading, gtaNode); + assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.grading, gtaNode, Role.coach); fireEvent(ureq, Event.CHANGED_EVENT); } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java index 0d38eeeb878850b892db3b4218315ef36d5799f8..0fa915b4dd3d6ed54dafe61261f1d33d4922987b 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java @@ -20,6 +20,7 @@ package org.olat.course.nodes.gta.ui; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,11 +36,20 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; import org.olat.core.gui.components.stack.BreadcrumbPanel; 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.closablewrapper.CloseableModalController; +import org.olat.core.util.StringHelper; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskLight; +import org.olat.course.nodes.gta.TaskList; +import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.model.DueDate; import org.olat.course.nodes.gta.ui.CoachGroupsTableModel.CGCols; +import org.olat.course.nodes.gta.ui.component.SubmissionDateCellRenderer; +import org.olat.course.nodes.gta.ui.component.TaskStatusCellRenderer; import org.olat.course.nodes.gta.ui.events.SelectBusinessGroupEvent; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; @@ -58,7 +68,9 @@ public class GTACoachedGroupListController extends GTACoachedListController { private CoachGroupsTableModel tableModel; private final BreadcrumbPanel stackPanel; + private CloseableModalController cmc; private GTACoachController coachingCtrl; + private EditDueDatesController editDueDatesCtrl; private final List<BusinessGroup> coachedGroups; private final UserCourseEnvironment coachCourseEnv; @@ -75,6 +87,15 @@ public class GTACoachedGroupListController extends GTACoachedListController { initForm(ureq); updateModel(); } + + public BusinessGroup getBusinessGroup(Long key) { + for(BusinessGroup group:coachedGroups) { + if(group.getKey().equals(key)) { + return group; + } + } + return null; + } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { @@ -91,13 +112,22 @@ public class GTACoachedGroupListController extends GTACoachedListController { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.taskStatus.i18nKey(), CGCols.taskStatus.ordinal(), true, CGCols.taskStatus.name(), new TaskStatusCellRenderer(getTranslator()))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.submissionDate.i18nKey(), CGCols.submissionDate.ordinal(), + true, CGCols.submissionDate.name(), new SubmissionDateCellRenderer(getTranslator()))); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select")); + if(gtaManager.isDueDateEnabled(gtaNode)) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.duedates", translate("duedates"), "duedates")); + } tableModel = new CoachGroupsTableModel(columnsModel); tableEl = uifactory.addTableElement(getWindowControl(), "entries", tableModel, 10, false, getTranslator(), formLayout); tableEl.setShowAllRowsEnabled(true); tableEl.setAndLoadPersistedPreferences(ureq, "gta-coached-groups"); } + + public List<BusinessGroup> getCoachedGroups() { + return coachedGroups; + } protected void updateModel() { RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry(); @@ -112,7 +142,23 @@ public class GTACoachedGroupListController extends GTACoachedListController { List<CoachedGroupRow> rows = new ArrayList<>(coachedGroups.size()); for(BusinessGroup group:coachedGroups) { TaskLight task = groupToTasks.get(group.getKey()); - rows.add(new CoachedGroupRow(group, task)); + Date submissionDueDate = null; + if(task == null || task.getTaskStatus() == null || task.getTaskStatus() == TaskProcess.assignment) { + DueDate dueDate = gtaManager.getSubmissionDueDate(task, null, group, gtaNode, entry, true); + if(dueDate != null) { + submissionDueDate = dueDate.getDueDate(); + } + } + + Date syntheticSubmissionDate = null; + boolean hasSubmittedDocument = false; + if(task != null && task.getTaskStatus() != null && task.getTaskStatus() != TaskProcess.assignment && task.getTaskStatus() != TaskProcess.submit) { + syntheticSubmissionDate = getSyntheticSubmissionDate(task); + if(syntheticSubmissionDate != null) { + hasSubmittedDocument = this.hasSubmittedDocument(task); + } + } + rows.add(new CoachedGroupRow(group, task, submissionDueDate, syntheticSubmissionDate, hasSubmittedDocument)); } tableModel.setObjects(rows); @@ -123,6 +169,27 @@ public class GTACoachedGroupListController extends GTACoachedListController { protected void doDispose() { // } + + @Override + public void event(UserRequest ureq, Controller source, Event event) { + if(editDueDatesCtrl == source) { + if(event == Event.DONE_EVENT) { + updateModel(); + } + cmc.deactivate(); + cleanUp(); + } else if(source == cmc) { + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeAsListenerAndDispose(editDueDatesCtrl); + removeAsListenerAndDispose(cmc); + editDueDatesCtrl = null; + cmc = null; + } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { @@ -133,6 +200,8 @@ public class GTACoachedGroupListController extends GTACoachedListController { CoachedGroupRow row = tableModel.getObject(se.getIndex()); if("details".equals(cmd) || "select".equals(cmd)) { doSelect(ureq, row.getBusinessGroup()); + } else if("duedates".equals(cmd)) { + doEditDueDate(ureq, row); } } } @@ -145,7 +214,7 @@ public class GTACoachedGroupListController extends GTACoachedListController { } else { removeAsListenerAndDispose(coachingCtrl); - coachingCtrl = new GTACoachController(ureq, getWindowControl(), courseEnv, gtaNode, coachCourseEnv, businessGroup, true, true, true); + coachingCtrl = new GTACoachController(ureq, getWindowControl(), courseEnv, gtaNode, coachCourseEnv, businessGroup, true, true, true, false); listenTo(coachingCtrl); stackPanel.pushController(businessGroup.getName(), coachingCtrl); } @@ -155,4 +224,27 @@ public class GTACoachedGroupListController extends GTACoachedListController { protected void formOK(UserRequest ureq) { // } + + private void doEditDueDate(UserRequest ureq, CoachedGroupRow row) { + if(editDueDatesCtrl != null) return; + + Task task; + BusinessGroup assessedGroup = row.getBusinessGroup(); + RepositoryEntry entry = coachCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + if(row.getTask() == null) { + TaskProcess firstStep = gtaManager.firstStep(gtaNode); + TaskList taskList = gtaManager.getTaskList(entry, gtaNode); + task = gtaManager.createAndPersistTask(null, taskList, firstStep, assessedGroup, null, gtaNode); + } else { + task = gtaManager.getTask(row.getTask()); + } + + editDueDatesCtrl = new EditDueDatesController(ureq, getWindowControl(), task, null, assessedGroup, gtaNode, entry); + listenTo(editDueDatesCtrl); + + String title = translate("duedates.user", new String[] { StringHelper.escapeHtml(assessedGroup.getName()) }); + cmc = new CloseableModalController(getWindowControl(), "close", editDueDatesCtrl.getInitialComponent(), true, title, true); + listenTo(cmc); + cmc.activate(); + } } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedListController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedListController.java index e28e6a4fabd9f76139086ba2922266475957abfa..eedf6fc861738c05d3747213de8ee0dae5042390 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedListController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedListController.java @@ -19,6 +19,8 @@ */ package org.olat.course.nodes.gta.ui; +import java.util.Date; + import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; @@ -26,6 +28,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.TaskLight; import org.olat.course.run.environment.CourseEnvironment; import org.olat.modules.ModuleConfiguration; @@ -73,4 +76,28 @@ public abstract class GTACoachedListController extends FormBasicController { layoutCont.contextPut("gradingEnabled", grading); } } + + protected Date getSyntheticSubmissionDate(TaskLight task) { + Date date = task.getSubmissionDate(); + if(date == null || (task.getSubmissionRevisionsDate() != null && task.getSubmissionRevisionsDate().after(date))) { + date = task.getSubmissionRevisionsDate(); + } + if(date == null || (task.getCollectionDate() != null && task.getCollectionDate().after(date))) { + date = task.getCollectionDate(); + } + return date; + } + + public boolean hasSubmittedDocument(TaskLight task) { + Integer numOfDocs = task.getSubmissionNumOfDocs(); + Date date = task.getSubmissionDate(); + if(date == null || (task.getSubmissionRevisionsDate() != null && task.getSubmissionRevisionsDate().after(date))) { + date = task.getSubmissionRevisionsDate(); + numOfDocs = task.getSubmissionRevisionsNumOfDocs(); + } + if(date == null || (task.getCollectionDate() != null && task.getCollectionDate().after(date))) { + numOfDocs = task.getCollectionNumOfDocs(); + } + return numOfDocs == null ? false : numOfDocs.intValue() > 0; + } } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantGradingController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantGradingController.java index 1449359418bd2e36491436edbfcb9ec93c447160..ae4bff8a729421151398b2685098e17828894286 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantGradingController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantGradingController.java @@ -44,6 +44,7 @@ import org.olat.course.nodes.gta.TaskProcess; import org.olat.course.nodes.ms.MSCourseNodeRunController; import org.olat.course.run.scoring.AssessmentEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.modules.assessment.ui.event.AssessmentFormEvent; import org.olat.repository.RepositoryEntry; @@ -147,7 +148,7 @@ public class GTACoachedParticipantGradingController extends BasicController { } private void doReopenAssessment(UserRequest ureq) { - assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.grading, gtaNode); + assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.grading, gtaNode, Role.coach); fireEvent(ureq, Event.CHANGED_EVENT); } @@ -164,7 +165,7 @@ public class GTACoachedParticipantGradingController extends BasicController { TaskList taskList = gtaManager.createIfNotExists(courseEntry, gtaNode); assignedTask = gtaManager.createTask(null, taskList, TaskProcess.graded, null, assessedIdentity, gtaNode); } else { - assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.graded, gtaNode); + assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.graded, gtaNode, Role.coach); } fireEvent(ureq, Event.CHANGED_EVENT); } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java index 2db1d81c7e1e3484db3a2c3c84f1e03a0641b686..2f17f92779ff14b23de047cf616bda1463ee2cbb 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java @@ -20,14 +20,19 @@ package org.olat.course.nodes.gta.ui; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; +import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.BaseSecurityModule; import org.olat.basesecurity.GroupRoles; +import org.olat.basesecurity.IdentityRef; +import org.olat.basesecurity.model.IdentityRefImpl; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -41,7 +46,9 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionE import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer; import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer; 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.closablewrapper.CloseableModalController; import org.olat.core.id.Identity; import org.olat.core.id.Roles; import org.olat.core.id.UserConstants; @@ -49,8 +56,14 @@ import org.olat.core.util.StringHelper; import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskLight; +import org.olat.course.nodes.gta.TaskList; +import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.model.DueDate; import org.olat.course.nodes.gta.ui.CoachParticipantsTableModel.CGCols; +import org.olat.course.nodes.gta.ui.component.SubmissionDateCellRenderer; +import org.olat.course.nodes.gta.ui.component.TaskStatusCellRenderer; import org.olat.course.nodes.gta.ui.events.SelectIdentityEvent; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; @@ -74,11 +87,14 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle private FlexiTableElement tableEl; private CoachParticipantsTableModel tableModel; - private List<UserPropertiesRow> assessableIdentities; + private final UserCourseEnvironmentImpl coachCourseEnv; private final boolean isAdministrativeUser; private final List<UserPropertyHandler> userPropertyHandlers; + + private CloseableModalController cmc; + private EditDueDatesController editDueDatesCtrl; @Autowired private GTAManager gtaManager; @@ -87,6 +103,8 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle @Autowired private BaseSecurityModule securityModule; @Autowired + private BaseSecurityManager securityManager; + @Autowired private RepositoryService repositoryService; @Autowired private BusinessGroupService businessGroupService; @@ -99,19 +117,52 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle isAdministrativeUser = securityModule.isUserAllowedAdminProps(roles); userPropertyHandlers = userManager.getUserPropertyHandlersFor(GTACoachedGroupGradingController.USER_PROPS_ID, isAdministrativeUser); setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); - - CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager(); - UserCourseEnvironmentImpl coachCourseEnv = (UserCourseEnvironmentImpl)userCourseEnv; - - boolean admin = userCourseEnv.isAdmin(); + coachCourseEnv = (UserCourseEnvironmentImpl)userCourseEnv; - Set<Identity> duplicateKiller = new HashSet<>(); assessableIdentities = new ArrayList<>(); + collectIdentities(new Consumer<Identity>() { + @Override + public void accept(Identity participant) { + assessableIdentities.add(new UserPropertiesRow(participant, userPropertyHandlers, getLocale())); + } + }); + + initForm(ureq); + updateModel(); + } + + public boolean hasIdentityKey(Long identityKey) { + if(assessableIdentities != null) { + for(UserPropertiesRow row:assessableIdentities) { + if(row.getIdentityKey().equals(identityKey)) { + return true; + } + } + } + return false; + } + + public List<Identity> getAssessableIdentities() { + List<Identity> identities = new ArrayList<>(); + collectIdentities(new Consumer<Identity>() { + @Override + public void accept(Identity participant) { + identities.add(participant); + } + }); + return identities; + } + + private void collectIdentities(Consumer<Identity> participantCollector) { + Set<Identity> duplicateKiller = new HashSet<>(); + CourseGroupManager cgm = coachCourseEnv.getCourseEnvironment().getCourseGroupManager(); + boolean admin = coachCourseEnv.isAdmin(); + List<BusinessGroup> coachedGroups = admin ? cgm.getAllBusinessGroups() : coachCourseEnv.getCoachedGroups(); List<Identity> participants = businessGroupService.getMembers(coachedGroups, GroupRoles.participant.name()); for(Identity participant:participants) { if(!duplicateKiller.contains(participant)) { - assessableIdentities.add(new UserPropertiesRow(participant, userPropertyHandlers, getLocale())); + participantCollector.accept(participant); duplicateKiller.add(participant); } } @@ -122,14 +173,11 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle List<Identity> courseParticipants = repositoryService.getMembers(re, GroupRoles.participant.name()); for(Identity participant:courseParticipants) { if(!duplicateKiller.contains(participant)) { - assessableIdentities.add(new UserPropertiesRow(participant, userPropertyHandlers, getLocale())); + participantCollector.accept(participant); duplicateKiller.add(participant); } } } - - initForm(ureq); - updateModel(); } @Override @@ -169,7 +217,12 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.taskStatus.i18nKey(), CGCols.taskStatus.ordinal(), true, CGCols.taskStatus.name(), new TaskStatusCellRenderer(getTranslator()))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.submissionDate.i18nKey(), CGCols.submissionDate.ordinal(), + true, CGCols.submissionDate.name(), new SubmissionDateCellRenderer(getTranslator()))); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select")); + if(gtaManager.isDueDateEnabled(gtaNode)) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.duedates", translate("duedates"), "duedates")); + } tableModel = new CoachParticipantsTableModel(userPropertyHandlers, getLocale(), columnsModel); tableEl = uifactory.addTableElement(getWindowControl(), "entries", tableModel, 10, false, getTranslator(), formLayout); @@ -190,7 +243,24 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle List<CoachedIdentityRow> rows = new ArrayList<>(assessableIdentities.size()); for(UserPropertiesRow assessableIdentity:assessableIdentities) { TaskLight task = identityToTasks.get(assessableIdentity.getIdentityKey()); - rows.add(new CoachedIdentityRow(assessableIdentity, task)); + Date submissionDueDate = null; + if(task == null || task.getTaskStatus() == null || task.getTaskStatus() == TaskProcess.assignment) { + IdentityRef identityRef = new IdentityRefImpl(assessableIdentity.getIdentityKey()); + DueDate dueDate = gtaManager.getSubmissionDueDate(task, identityRef, null, gtaNode, entry, true); + if(dueDate != null) { + submissionDueDate = dueDate.getDueDate(); + } + } + + Date syntheticSubmissionDate = null; + boolean hasSubmittedDocument = false; + if(task != null && task.getTaskStatus() != null && task.getTaskStatus() != TaskProcess.assignment && task.getTaskStatus() != TaskProcess.submit) { + syntheticSubmissionDate = getSyntheticSubmissionDate(task); + if(syntheticSubmissionDate != null) { + hasSubmittedDocument = hasSubmittedDocument(task); + } + } + rows.add(new CoachedIdentityRow(assessableIdentity, task, submissionDueDate, syntheticSubmissionDate, hasSubmittedDocument)); } tableModel.setObjects(rows); @@ -202,6 +272,27 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle // } + @Override + public void event(UserRequest ureq, Controller source, Event event) { + if(editDueDatesCtrl == source) { + if(event == Event.DONE_EVENT) { + updateModel(); + } + cmc.deactivate(); + cleanUp(); + } else if(source == cmc) { + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeAsListenerAndDispose(editDueDatesCtrl); + removeAsListenerAndDispose(cmc); + editDueDatesCtrl = null; + cmc = null; + } + @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(tableEl == source) { @@ -209,7 +300,9 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle SelectionEvent se = (SelectionEvent)event; String cmd = se.getCommand(); CoachedIdentityRow row = tableModel.getObject(se.getIndex()); - if(StringHelper.containsNonWhitespace(cmd)) { + if("duedates".equals(cmd)) { + doEditDueDate(ureq, row); + } else if(StringHelper.containsNonWhitespace(cmd)) { fireEvent(ureq, new SelectIdentityEvent(row.getIdentity().getIdentityKey())); } } @@ -221,5 +314,28 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle protected void formOK(UserRequest ureq) { // } + + private void doEditDueDate(UserRequest ureq, CoachedIdentityRow row) { + if(editDueDatesCtrl != null) return; + + Task task; + Identity assessedIdentity = securityManager.loadIdentityByKey(row.getIdentity().getIdentityKey()); + RepositoryEntry entry = coachCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + if(row.getTask() == null) { + TaskProcess firstStep = gtaManager.firstStep(gtaNode); + TaskList taskList = gtaManager.getTaskList(entry, gtaNode); + task = gtaManager.createAndPersistTask(null, taskList, firstStep, null, assessedIdentity, gtaNode); + } else { + task = gtaManager.getTask(row.getTask()); + } -} + editDueDatesCtrl = new EditDueDatesController(ureq, getWindowControl(), task, assessedIdentity, null, gtaNode, entry); + listenTo(editDueDatesCtrl); + + String fullname = userManager.getUserDisplayName(assessedIdentity); + String title = translate("duedates.user", new String[] { fullname }); + cmc = new CloseableModalController(getWindowControl(), "close", editDueDatesCtrl.getInitialComponent(), true, title, true); + listenTo(cmc); + cmc.activate(); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAEditController.java index 64a4512a35fe1759a55fd534af7818bb4a09c62b..4eccde43d93e70ef4330bde872470402258f1619 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTAEditController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAEditController.java @@ -52,17 +52,20 @@ public class GTAEditController extends ActivateableTabbableDefaultController { public static final String PANE_TAB_WORKLOW = "pane.tab.workflow"; public static final String PANE_TAB_ASSIGNMENT = "pane.tab.assignment"; public static final String PANE_TAB_SUBMISSION = "pane.tab.submission"; + public static final String PANE_TAB_REVIEW_AND_CORRECTIONS = "pane.tab.review"; public static final String PANE_TAB_GRADING = "pane.tab.grading"; public static final String PANE_TAB_SOLUTIONS = "pane.tab.solutions"; public static final String PANE_TAB_HIGHSCORE = "pane.tab.highscore"; public static final String[] paneKeys = { PANE_TAB_ACCESSIBILITY, PANE_TAB_WORKLOW, PANE_TAB_ASSIGNMENT, - PANE_TAB_SUBMISSION, PANE_TAB_GRADING, PANE_TAB_SOLUTIONS + PANE_TAB_SUBMISSION, PANE_TAB_REVIEW_AND_CORRECTIONS, PANE_TAB_GRADING, + PANE_TAB_SOLUTIONS }; - private int workflowPos, assignmentPos, submissionPos, gradingPos, solutionsPos, highScoreTabPosition; + private int workflowPos, assignmentPos, submissionPos, revisionPos, gradingPos, solutionsPos, highScoreTabPosition; private TabbedPane myTabbedPane; private GTAWorkflowEditController workflowCtrl; + private GTARevisionAndCorrectionEditController revisionCtrl; private GTAAssignmentEditController assignmentCtrl; private GTASubmissionEditController submissionCtrl; private MSEditFormController manualAssessmentCtrl; @@ -99,6 +102,9 @@ public class GTAEditController extends ActivateableTabbableDefaultController { //submission submissionCtrl = new GTASubmissionEditController(ureq, getWindowControl(), config); listenTo(submissionCtrl); + //revision + revisionCtrl = new GTARevisionAndCorrectionEditController(ureq, getWindowControl(), config); + listenTo(revisionCtrl); //grading manualAssessmentCtrl = new MSEditFormController(ureq, getWindowControl(), config); listenTo(manualAssessmentCtrl); @@ -125,6 +131,7 @@ public class GTAEditController extends ActivateableTabbableDefaultController { workflowPos = tabbedPane.addTab(translate(PANE_TAB_WORKLOW), workflowCtrl.getInitialComponent()); assignmentPos = tabbedPane.addTab(translate(PANE_TAB_ASSIGNMENT), assignmentCtrl.getInitialComponent()); submissionPos = tabbedPane.addTab(translate(PANE_TAB_SUBMISSION), submissionCtrl.getInitialComponent()); + revisionPos = tabbedPane.addTab(translate(PANE_TAB_REVIEW_AND_CORRECTIONS), revisionCtrl.getInitialComponent()); gradingPos = tabbedPane.addTab(translate(PANE_TAB_GRADING), manualAssessmentCtrl.getInitialComponent()); solutionsPos = tabbedPane.addTab(translate(PANE_TAB_SOLUTIONS), solutionsCtrl.getInitialComponent()); highScoreTabPosition = myTabbedPane.addTab(translate(PANE_TAB_HIGHSCORE), highScoreNodeConfigController.getInitialComponent()); @@ -134,6 +141,7 @@ public class GTAEditController extends ActivateableTabbableDefaultController { private void updateEnabledDisabledTabs() { myTabbedPane.setEnabled(assignmentPos, config.getBooleanSafe(GTACourseNode.GTASK_ASSIGNMENT)); myTabbedPane.setEnabled(submissionPos, config.getBooleanSafe(GTACourseNode.GTASK_SUBMIT)); + myTabbedPane.setEnabled(revisionPos, config.getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION)); myTabbedPane.setEnabled(gradingPos, config.getBooleanSafe(GTACourseNode.GTASK_GRADING)); myTabbedPane.setEnabled(solutionsPos, config.getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)); myTabbedPane.setEnabled(highScoreTabPosition, config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD)); @@ -190,6 +198,15 @@ public class GTAEditController extends ActivateableTabbableDefaultController { listenTo(submissionCtrl); myTabbedPane.replaceTab(submissionPos, submissionCtrl.getInitialComponent()); } + } else if(revisionCtrl == source) { + if(event == Event.DONE_EVENT) { + fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); + } else if(event == Event.CANCELLED_EVENT) { + removeAsListenerAndDispose(revisionCtrl); + revisionCtrl = new GTARevisionAndCorrectionEditController(ureq, getWindowControl(), config); + listenTo(revisionCtrl); + myTabbedPane.replaceTab(revisionPos, revisionCtrl.getInitialComponent()); + } } else if(manualAssessmentCtrl == source) { if (event == Event.DONE_EVENT){ manualAssessmentCtrl.updateModuleConfiguration(config); diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java index 5d8a8c4a6f40a8733ac04f4edb72a49a5740b00a..fcc500d7f4f2bc7cd1a23b02c67430ebc00ad3ac 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java @@ -37,9 +37,13 @@ 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.closablewrapper.CloseableCalloutWindowController; +import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.id.Identity; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.io.SystemFilenameFilter; @@ -58,12 +62,14 @@ import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskHelper; import org.olat.course.nodes.gta.TaskHelper.FilesLocked; import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.model.DueDate; import org.olat.course.nodes.gta.model.TaskDefinition; import org.olat.course.nodes.gta.ui.events.SubmitEvent; import org.olat.course.nodes.gta.ui.events.TaskMultiUserEvent; import org.olat.course.nodes.ms.MSCourseNodeRunController; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; +import org.olat.modules.assessment.Role; import org.springframework.beans.factory.annotation.Autowired; /** @@ -72,15 +78,17 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class GTAParticipantController extends GTAAbstractController { +public class GTAParticipantController extends GTAAbstractController implements Activateable2 { - private Link submitButton, openGroupButton, changeGroupLink; + private Link submitButton, openGroupButton, changeGroupLink, resetTaskButton; + private CloseableModalController cmc; private MSCourseNodeRunController gradingCtrl; private SubmitDocumentsController submitDocCtrl; private DialogBoxController confirmSubmitDialog; private GTAAssignedTaskController assignedTaskCtrl; private GTAAvailableTaskController availableTaskCtrl; + private ConfirmResetTaskController confirmResetTaskCtrl; private CloseableCalloutWindowController chooserCalloutCtrl; private BusinessGroupChooserController businessGroupChooserCtrl; private GTAParticipantRevisionAndCorrectionsController revisionDocumentsCtrl; @@ -101,8 +109,12 @@ public class GTAParticipantController extends GTAAbstractController { @Override protected void initContainer(UserRequest ureq) { mainVC = createVelocityContainer("run"); - putInitialPanel(mainVC); + resetTaskButton = LinkFactory.createCustomLink("participant.reset.button", "reset", "participant.reset.button", Link.BUTTON, mainVC, this); + resetTaskButton.setElementCssClass("o_sel_course_gta_reset"); + resetTaskButton.setVisible(false); + + putInitialPanel(mainVC); initFlow() ; } @@ -326,8 +338,8 @@ public class GTAParticipantController extends GTAAbstractController { } private void doSubmitDocuments(UserRequest ureq, Task task) { - TaskProcess review = gtaManager.nextStep(TaskProcess.submit, gtaNode); - task = gtaManager.updateTask(task, review, gtaNode); + int numOfDocs = getNumberOfSubmittedDocuments(); + task = gtaManager.submitTask(task, gtaNode, numOfDocs, Role.user); showInfo("run.documents.successfully.submitted"); TaskMultiUserEvent event = new TaskMultiUserEvent(TaskMultiUserEvent.SUMBIT_TASK, @@ -371,6 +383,17 @@ public class GTAParticipantController extends GTAAbstractController { } } + private void doConfirmResetTask(UserRequest ureq, Task task) { + if(confirmResetTaskCtrl != null) return; + confirmResetTaskCtrl = new ConfirmResetTaskController(ureq, getWindowControl(), task, gtaNode, courseEnv); + listenTo(confirmResetTaskCtrl); + + String title = translate("participant.confirm.reset.task.title"); + cmc = new CloseableModalController(getWindowControl(), translate("close"), confirmResetTaskCtrl.getInitialComponent(), true, title); + listenTo(cmc); + cmc.activate(); + } + @Override protected Task stepReviewAndCorrection(UserRequest ureq, Task assignedTask) { assignedTask = super.stepReviewAndCorrection(ureq, assignedTask); @@ -409,7 +432,7 @@ public class GTAParticipantController extends GTAAbstractController { documentsContainer = gtaManager.getCorrectionContainer(courseEnv, gtaNode, getIdentity()); } - if(TaskHelper.hasDocuments(documentsDir)) { + if(!waiting && TaskHelper.hasDocuments(documentsDir)) { correctionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, "run.corrections.description", "bulk.review", "review"); listenTo(correctionsCtrl); @@ -493,7 +516,11 @@ public class GTAParticipantController extends GTAAbstractController { if(assignedTask == null || assignedTask.getTaskStatus() == TaskProcess.assignment || assignedTask.getTaskStatus() == TaskProcess.submit || assignedTask.getTaskStatus() == TaskProcess.review || assignedTask.getTaskStatus() == TaskProcess.correction || assignedTask.getTaskStatus() == TaskProcess.revision) { - mainVC.contextPut("solutionCssClass", ""); + if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_ALL, false)) { + setSolutions(ureq, assignedTask); + } else { + mainVC.contextPut("solutionCssClass", ""); + } } else if(assignedTask.getTaskStatus() == TaskProcess.solution) { mainVC.contextPut("solutionCssClass", "o_active"); setSolutions(ureq, assignedTask); @@ -519,7 +546,8 @@ public class GTAParticipantController extends GTAAbstractController { if(visible) { File documentsDir = gtaManager.getSolutionsDirectory(courseEnv, gtaNode); VFSContainer documentsContainer = gtaManager.getSolutionsContainer(courseEnv, gtaNode); - if(TaskHelper.hasDocuments(documentsDir)) { + if((availableDate != null && !availableDate.isRelative() && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_ALL, false)) + || TaskHelper.hasDocuments(documentsDir)) { solutionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, "run.solutions.description", "bulk.solutions", "solutions"); listenTo(solutionsCtrl); mainVC.put("solutions", solutionsCtrl.getInitialComponent()); @@ -576,6 +604,20 @@ public class GTAParticipantController extends GTAAbstractController { return assignedTask; } + @Override + protected void resetTask(UserRequest ureq, Task task) { + resetTaskButton.setUserObject(task); + + DueDate assignmentDueDate = getAssignementDueDate(task); + boolean allowed = task != null + && (StringHelper.containsNonWhitespace(task.getTaskName()) || (! StringHelper.containsNonWhitespace(task.getTaskName()) && task.getTaskStatus() == TaskProcess.submit)) + && (task.getTaskStatus() == TaskProcess.assignment || task.getTaskStatus() == TaskProcess.submit) + && task.getAllowResetDate() != null + && (assignmentDueDate == null || assignmentDueDate.getDueDate() == null || assignmentDueDate.getDueDate().after(new Date())) + && GTACourseNode.GTASK_ASSIGNEMENT_TYPE_MANUAL.equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_ASSIGNEMENT_TYPE)); + resetTaskButton.setVisible(allowed); + } + @Override protected void nodeLog() { if(businessGroupTask) { @@ -623,6 +665,34 @@ public class GTAParticipantController extends GTAAbstractController { // } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + String type = entries.get(0).getOLATResourceable().getResourceableTypeName(); + if("Correction".equalsIgnoreCase(type)) { + int revisionLoop = entries.get(0).getOLATResourceable().getResourceableId().intValue(); + if(revisionLoop == 0) { + if(correctionsCtrl != null) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + correctionsCtrl.activate(ureq, subEntries, null); + } + } else if(revisionDocumentsCtrl != null) { + revisionDocumentsCtrl.activate(ureq, entries, null); + } + } else if("Solution".equalsIgnoreCase(type)) { + if(solutionsCtrl != null) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + solutionsCtrl.activate(ureq, subEntries, null); + } + } else if("Assessment".equalsIgnoreCase(type)) { + if(gradingCtrl != null) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + gradingCtrl.activate(ureq, subEntries, null); + } + } + } + @Override protected void processEvent(TaskMultiUserEvent event) { if(TaskMultiUserEvent.SUMBIT_TASK.equals(event.getCommand())) { @@ -645,6 +715,8 @@ public class GTAParticipantController extends GTAAbstractController { } else if(submitButton == source) { Task assignedTask = submitDocCtrl.getAssignedTask(); doConfirmSubmit(ureq, assignedTask); + } else if(resetTaskButton == source) { + doConfirmResetTask(ureq, (Task)resetTaskButton.getUserObject()); } super.event(ureq, source, event); } @@ -679,6 +751,13 @@ public class GTAParticipantController extends GTAAbstractController { doSubmitDocuments(ureq, task); } cleanUpPopups(); + } else if(confirmResetTaskCtrl == source) { + if(event == Event.DONE_EVENT) { + cleanUpProcess(); + process(ureq); + } + cmc.deactivate(); + cleanUpPopups(); } else if(submitDocCtrl == source) { boolean hasUploadDocuments = submitDocCtrl.hasUploadDocuments(); if(event instanceof SubmitEvent) { @@ -692,6 +771,8 @@ public class GTAParticipantController extends GTAAbstractController { if(submitButton != null) { submitButton.setCustomEnabledLinkCSS(hasUploadDocuments ? "btn btn-primary" : "btn btn-default"); } + } else if(cmc == source) { + cleanUpPopups(); } super.event(ureq, source, event); } @@ -735,11 +816,15 @@ public class GTAParticipantController extends GTAAbstractController { private void cleanUpPopups() { removeAsListenerAndDispose(businessGroupChooserCtrl); + removeAsListenerAndDispose(confirmResetTaskCtrl); removeAsListenerAndDispose(confirmSubmitDialog); removeAsListenerAndDispose(chooserCalloutCtrl); + removeAsListenerAndDispose(cmc); businessGroupChooserCtrl = null; + confirmResetTaskCtrl = null; confirmSubmitDialog = null; chooserCalloutCtrl = null; + cmc = null; } private void doOpenBusinessGroup(UserRequest ureq) { @@ -759,4 +844,9 @@ public class GTAParticipantController extends GTAAbstractController { listenTo(chooserCalloutCtrl); chooserCalloutCtrl.activate(); } + + @Override + protected Role getDoer() { + return Role.user; + } } \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantRevisionAndCorrectionsController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantRevisionAndCorrectionsController.java index fceb72b07cb681d5d23c50b4ff362f814c133d6b..1ba44f5b0f3d7cbb4d2bc7dd97d17d1bf19e2717 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantRevisionAndCorrectionsController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantRevisionAndCorrectionsController.java @@ -21,7 +21,10 @@ package org.olat.course.nodes.gta.ui; import java.io.File; import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.olat.basesecurity.GroupRoles; import org.olat.core.gui.UserRequest; @@ -33,10 +36,13 @@ 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.controller.BasicController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.io.SystemFilenameFilter; @@ -57,6 +63,7 @@ import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; +import org.olat.modules.assessment.Role; import org.springframework.beans.factory.annotation.Autowired; /** @@ -65,14 +72,14 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class GTAParticipantRevisionAndCorrectionsController extends BasicController { +public class GTAParticipantRevisionAndCorrectionsController extends BasicController implements Activateable2 { private Link submitRevisionButton; private final VelocityContainer mainVC; private DialogBoxController confirmSubmitDialog; private SubmitDocumentsController uploadRevisionsCtrl; - private DirectoryController correctionsCtrl, revisionsCtrl; + private final Map<Integer,DirectoryController> revisionLoopToCorrectionsCtrl = new HashMap<>(); private Task assignedTask; private final boolean businessGroupTask; @@ -167,8 +174,11 @@ public class GTAParticipantRevisionAndCorrectionsController extends BasicControl documentsDir = gtaManager.getRevisedDocumentsDirectory(courseEnv, gtaNode, iteration, getIdentity()); documentsContainer = gtaManager.getRevisedDocumentsContainer(courseEnv, gtaNode, iteration, getIdentity()); } - uploadRevisionsCtrl = new SubmitDocumentsController(ureq, getWindowControl(), task, documentsDir, documentsContainer, -1, - gtaNode, courseEnv, assessedUserCourseEnv.isCourseReadOnly(), null, "document"); + + Date deadline = task == null ? null : task.getRevisionsDueDate(); + int maxDocs = gtaNode.getModuleConfiguration().getIntegerSafe(GTACourseNode.GTASK_MAX_REVISED_DOCS, -1); + uploadRevisionsCtrl = new SubmitDocumentsController(ureq, getWindowControl(), task, documentsDir, documentsContainer, maxDocs, + gtaNode, courseEnv, assessedUserCourseEnv.isCourseReadOnly(), deadline, "document"); listenTo(uploadRevisionsCtrl); mainVC.put("uploadRevisions", uploadRevisionsCtrl.getInitialComponent()); @@ -192,7 +202,7 @@ public class GTAParticipantRevisionAndCorrectionsController extends BasicControl boolean hasDocument = TaskHelper.hasDocuments(documentsDir); if(hasDocument) { - revisionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, + DirectoryController revisionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, "run.revised.description", "bulk.submitted.revisions", "revisions.zip"); listenTo(revisionsCtrl); mainVC.put(cmpName, revisionsCtrl.getInitialComponent()); @@ -213,14 +223,29 @@ public class GTAParticipantRevisionAndCorrectionsController extends BasicControl boolean hasDocument = TaskHelper.hasDocuments(documentsDir); if(hasDocument) { - correctionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, + DirectoryController correctionsCtrl = new DirectoryController(ureq, getWindowControl(), documentsDir, documentsContainer, "run.corrections.description", "bulk.review", "review"); listenTo(correctionsCtrl); mainVC.put(cmpName, correctionsCtrl.getInitialComponent()); + revisionLoopToCorrectionsCtrl.put(iteration, correctionsCtrl); } return hasDocument; } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.size() <= 1) return; + + String type = entries.get(0).getOLATResourceable().getResourceableTypeName(); + int revisionLoop = entries.get(0).getOLATResourceable().getResourceableId().intValue(); + if("Correction".equalsIgnoreCase(type)) { + if(revisionLoopToCorrectionsCtrl.containsKey(revisionLoop)) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + revisionLoopToCorrectionsCtrl.get(revisionLoop).activate(ureq, subEntries, null); + } + } + } + @Override protected void event(UserRequest ureq, Controller source, Event event) { if(uploadRevisionsCtrl == source) { @@ -288,7 +313,18 @@ public class GTAParticipantRevisionAndCorrectionsController extends BasicControl } private void doSubmitRevisions() { - assignedTask = gtaManager.updateTask(assignedTask, TaskProcess.correction, gtaNode); + File[] submittedDocuments; + int iteration = assignedTask.getRevisionLoop(); + if(GTAType.group.name().equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) { + File documentsDir = gtaManager.getRevisedDocumentsDirectory(courseEnv, gtaNode, iteration, assessedGroup); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + } else { + File documentsDir = gtaManager.getRevisedDocumentsDirectory(courseEnv, gtaNode, iteration, getIdentity()); + submittedDocuments = documentsDir.listFiles(new SystemFilenameFilter(true, false)); + } + + int numOfDocs = submittedDocuments == null ? 0 : submittedDocuments.length; + assignedTask = gtaManager.submitRevisions(assignedTask, gtaNode, numOfDocs, Role.user); gtaManager.log("Revision", "revision submitted", assignedTask, getIdentity(), getIdentity(), assessedGroup, courseEnv, gtaNode); TaskMultiUserEvent event = new TaskMultiUserEvent(TaskMultiUserEvent.SUBMIT_REVISION, @@ -302,10 +338,10 @@ public class GTAParticipantRevisionAndCorrectionsController extends BasicControl for(Identity identity:identities) { UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course); - gtaNode.incrementUserAttempts(userCourseEnv); + gtaNode.incrementUserAttempts(userCourseEnv, Role.user); } } else { - gtaNode.incrementUserAttempts(assessedUserCourseEnv); + gtaNode.incrementUserAttempts(assessedUserCourseEnv, Role.user); } } } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTARevisionAndCorrectionEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTARevisionAndCorrectionEditController.java new file mode 100644 index 0000000000000000000000000000000000000000..e7cd0a39c40d483ca6cb7c891e77072fdf0e9d42 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTARevisionAndCorrectionEditController.java @@ -0,0 +1,122 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.ui; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.TextElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +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.course.nodes.GTACourseNode; +import org.olat.modules.ModuleConfiguration; + +/** + * + * Initial date: 4 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class GTARevisionAndCorrectionEditController extends FormBasicController { + + private TextElement maxNumberOfDocsEl; + + private final ModuleConfiguration config; + + public GTARevisionAndCorrectionEditController(UserRequest ureq, WindowControl wControl, ModuleConfiguration config) { + super(ureq, wControl, LAYOUT_BAREBONE); + + this.config = config; + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + //configuration + FormLayoutContainer configCont = FormLayoutContainer.createDefaultFormLayout("config", getTranslator()); + configCont.setRootForm(mainForm); + configCont.setFormTitle(translate("editor.revisions.title")); + configCont.setFormContextHelp("Assessment#_task_abgabe"); + formLayout.add(configCont); + + int maxDocs = config.getIntegerSafe(GTACourseNode.GTASK_MAX_REVISED_DOCS, -1); + String maxVal = ""; + if(maxDocs > 0) { + maxVal = Integer.toString(maxDocs); + } + maxNumberOfDocsEl = uifactory.addTextElement("max.documents", "max.documents", 5, maxVal, configCont); + + //save + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonsCont.setRootForm(mainForm); + configCont.add(buttonsCont); + uifactory.addFormSubmitButton("save", buttonsCont); + uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + maxNumberOfDocsEl.clearError(); + String maxVal = maxNumberOfDocsEl.getValue(); + if(StringHelper.containsNonWhitespace(maxVal)) { + try { + int val = Integer.parseInt(maxVal); + if(val <= 0 || val > 12) { + maxNumberOfDocsEl.setErrorKey("error.number.format", null); + allOk &= false; + } + } catch (NumberFormatException e) { + //can happen + allOk &= false; + maxNumberOfDocsEl.setErrorKey("error.number.format", null); + } + } + + return allOk & super.validateFormLogic(ureq); + } + + @Override + protected void formOK(UserRequest ureq) { + String maxVal = maxNumberOfDocsEl.getValue(); + if(StringHelper.isLong(maxVal)) { + try { + int val = Integer.parseInt(maxVal); + config.setIntValue(GTACourseNode.GTASK_MAX_REVISED_DOCS, val); + } catch (NumberFormatException e) { + //can happen + } + } else { + config.remove(GTACourseNode.GTASK_MAX_REVISED_DOCS); + } + + fireEvent(ureq, Event.DONE_EVENT); + } +} diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java index 242da92eccbbefd997a788d6392f9c8a4e57b2f2..9fb75bed33df7429207514d216191d6aa9c80bb7 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java @@ -19,6 +19,8 @@ */ package org.olat.course.nodes.gta.ui; +import java.util.List; + import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; @@ -31,7 +33,11 @@ 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.controller.BasicController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.messages.MessageUIFactory; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.resource.OresHelper; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; import org.olat.course.nodes.gta.model.Membership; @@ -46,7 +52,7 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class GTARunController extends BasicController { +public class GTARunController extends BasicController implements Activateable2 { private GTAParticipantController runCtrl; private GTACoachSelectionController coachCtrl; @@ -77,14 +83,14 @@ public class GTARunController extends BasicController { segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); runLink = LinkFactory.createLink("run.run", mainVC, this); - segmentView.addSegment(runLink, true); + segmentView.addSegment(runLink, false); coachLink = LinkFactory.createLink("run.coach", mainVC, this); - segmentView.addSegment(coachLink, false); + segmentView.addSegment(coachLink, true); if(isManagementTabAvalaible(config)) { manageLink = LinkFactory.createLink("run.manage.coach", mainVC, this); segmentView.addSegment(manageLink, false); } - doOpenRun(ureq); + doOpenCoach(ureq); mainVC.put("segments", segmentView); putInitialPanel(mainVC); } else if(isManagementTabAvalaible(config)) { @@ -120,6 +126,37 @@ public class GTARunController extends BasicController { && (config.getBooleanSafe(GTACourseNode.GTASK_ASSIGNMENT) || config.getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)); } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + String type = entries.get(0).getOLATResourceable().getResourceableTypeName(); + if("coach".equalsIgnoreCase(type)) { + if(coachLink != null) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + doOpenCoach(ureq).activate(ureq, subEntries, entries.get(0).getTransientState()); + if(segmentView != null) { + segmentView.select(coachLink); + } + } + } else if("management".equalsIgnoreCase(type)) { + if(manageLink != null) { + doManage(ureq); + if(segmentView != null) { + segmentView.select(manageLink); + } + } + } else if("identity".equalsIgnoreCase(type)) { + if(getIdentity().getKey().equals(entries.get(0).getOLATResourceable().getResourceableId())) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + doOpenRun(ureq).activate(ureq, subEntries, entries.get(0).getTransientState()); + if(segmentView != null) { + segmentView.select(runLink); + } + } + } + } + @Override protected void event(UserRequest ureq, Component source, Event event) { if(source == segmentView) { @@ -143,25 +180,39 @@ public class GTARunController extends BasicController { // } - private void doOpenRun(UserRequest ureq) { + private Activateable2 doOpenRun(UserRequest ureq) { if(runCtrl == null) { createRun(ureq); + } else { + addToHistory(ureq, runCtrl); } - mainVC.put("segmentCmp", runCtrl.getInitialComponent()); + if(mainVC != null) { + mainVC.put("segmentCmp", runCtrl.getInitialComponent()); + } + return runCtrl; } - private void doOpenCoach(UserRequest ureq) { + private Activateable2 doOpenCoach(UserRequest ureq) { if(coachCtrl == null) { createCoach(ureq); + } else { + addToHistory(ureq, coachCtrl); } - mainVC.put("segmentCmp", coachCtrl.getInitialComponent()); + if(mainVC != null) { + mainVC.put("segmentCmp", coachCtrl.getInitialComponent()); + } + return coachCtrl; } private void doManage(UserRequest ureq) { if(manageCtrl == null) { createManage(ureq); + } else { + addToHistory(ureq, manageCtrl); + } + if(mainVC != null) { + mainVC.put("segmentCmp", manageCtrl.getInitialComponent()); } - mainVC.put("segmentCmp", manageCtrl.getInitialComponent()); } private GTAParticipantController createRun(UserRequest ureq) { @@ -175,14 +226,17 @@ public class GTARunController extends BasicController { private GTACoachSelectionController createCoach(UserRequest ureq) { removeAsListenerAndDispose(coachCtrl); - coachCtrl = new GTACoachSelectionController(ureq, getWindowControl(), userCourseEnv, gtaNode); + WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType("coach"), null); + coachCtrl = new GTACoachSelectionController(ureq, swControl, userCourseEnv, gtaNode); listenTo(coachCtrl); return coachCtrl; } private GTACoachManagementController createManage(UserRequest ureq) { removeAsListenerAndDispose(manageCtrl); - manageCtrl = new GTACoachManagementController(ureq, getWindowControl(), userCourseEnv, gtaNode); + + WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType("management"), null); + manageCtrl = new GTACoachManagementController(ureq, swControl, userCourseEnv, gtaNode); listenTo(manageCtrl); return manageCtrl; } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAWorkflowEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAWorkflowEditController.java index e6f169dd15b44b6e6baefb5258bdd637809dcf2e..3a20b1709fe021fc23c7d9d38663fc0eb9891551 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTAWorkflowEditController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAWorkflowEditController.java @@ -85,6 +85,7 @@ public class GTAWorkflowEditController extends FormBasicController { private FormLayoutContainer stepsCont, assignmentRelDeadlineCont, submissionRelDeadlineCont, solutionVisibleRelCont; private TextElement assignementDeadlineDaysEl, submissionDeadlineDaysEl, solutionVisibleRelDaysEl; private SingleSelection assignementDeadlineRelToEl, submissionDeadlineRelToEl, solutionVisibleRelToEl; + private MultipleSelectionElement solutionVisibleToAllEl; private final GTACourseNode gtaNode; private final ModuleConfiguration config; @@ -328,6 +329,7 @@ public class GTAWorkflowEditController extends FormBasicController { solutionVisibleAfterEl = uifactory.addDateChooser("visibleafter", "sample.solution.visible.after", solutionVisibleAfter, stepsCont); solutionVisibleAfterEl.setDateChooserTimeEnabled(true); solutionVisibleAfterEl.setVisible(sample && !useRelativeDates); + solutionVisibleAfterEl.addActionListener(FormEvent.ONCHANGE); //relative deadline String solutionPage = velocity_root + "/solution_relative_date.html"; @@ -361,6 +363,14 @@ public class GTAWorkflowEditController extends FormBasicController { solutionVisibleRelToEl.select(solutionKeysAndValues.getKeys()[0], true); } + boolean solutionVisibleRelToAll = config.getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_ALL, false); + String[] solutionVisibleToAllValues = new String[] { translate("sample.solution.visible.all") }; + solutionVisibleToAllEl = uifactory.addCheckboxesHorizontal("visibleall", null, stepsCont, onKeys, solutionVisibleToAllValues); + solutionVisibleToAllEl.setVisible(sample && !useRelativeDates && solutionVisibleAfter != null); + if(solutionVisibleRelToAll) { + solutionVisibleToAllEl.select(onKeys[0], true); + } + uifactory.addSpacerElement("s5", stepsCont, true); //grading @@ -514,11 +524,14 @@ public class GTAWorkflowEditController extends FormBasicController { if(relativeDates) { setRelativeDates(solutionVisibleRelDaysEl, GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER_RELATIVE, solutionVisibleRelToEl, GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER_RELATIVE_TO); + config.remove(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_ALL); } else { config.setDateValue(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER, solutionVisibleAfterEl.getDate()); + config.setBooleanEntry(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_ALL, solutionVisibleToAllEl.isAtLeastSelected(1)); } } else { config.remove(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_AFTER); + config.remove(GTACourseNode.GTASK_SAMPLE_SOLUTION_VISIBLE_ALL); } config.setBooleanEntry(GTACourseNode.GTASK_GRADING, gradingEl.isAtLeastSelected(1)); @@ -550,6 +563,8 @@ public class GTAWorkflowEditController extends FormBasicController { updateAssignmentDeadline(); updateSubmissionDeadline(); updateSolutionDeadline(); + } else if(solutionVisibleAfterEl == source) { + updateSolutionDeadline(); } else if (reviewEl == source) { updateRevisions(); } else if(chooseGroupButton == source) { @@ -583,6 +598,7 @@ public class GTAWorkflowEditController extends FormBasicController { solutionVisibleAfterEl.setVisible(solution && !useRelativeDate); solutionVisibleRelCont.setVisible(solution && useRelativeDate); updateDeadline(solutionVisibleRelToEl, false); + solutionVisibleToAllEl.setVisible(solution && !useRelativeDate && solutionVisibleAfterEl.getDate() != null); } private void updateDeadline(SingleSelection selectionEl, boolean excludeAssignment) { diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java index ce49553f89856e6d5a37310104862e677250450c..f46f057445557a375af94c49587dd60921f11330 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java @@ -67,6 +67,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -519,11 +520,11 @@ public class GroupAssessmentController extends FormBasicController { if(applyToAllEl.isAtLeastSelected(1)) { applyChangesForTheWholeGroup(rows, setAsDone, userVisible); } else { - applyChangesForEvenryMemberGroup(rows, setAsDone, userVisible); + applyChangesForEveryMemberGroup(rows, setAsDone, userVisible); } } - private void applyChangesForEvenryMemberGroup(List<AssessmentRow> rows, boolean setAsDone, boolean userVisible) { + private void applyChangesForEveryMemberGroup(List<AssessmentRow> rows, boolean setAsDone, boolean userVisible) { ICourse course = CourseFactory.loadCourse(courseEnv.getCourseResourceableId()); for(AssessmentRow row:rows) { @@ -552,7 +553,7 @@ public class GroupAssessmentController extends FormBasicController { } else { newScoreEval = new ScoreEvaluation(score, passed, null, userVisible, null, null); } - gtaNode.updateUserScoreEvaluation(newScoreEval, userCourseEnv, getIdentity(), false); + gtaNode.updateUserScoreEvaluation(newScoreEval, userCourseEnv, getIdentity(), false, Role.coach); if(withComment) { String comment = row.getComment(); @@ -591,7 +592,7 @@ public class GroupAssessmentController extends FormBasicController { } else { newScoreEval = new ScoreEvaluation(score, passed, null, userVisible, null, null); } - gtaNode.updateUserScoreEvaluation(newScoreEval, userCourseEnv, getIdentity(), false); + gtaNode.updateUserScoreEvaluation(newScoreEval, userCourseEnv, getIdentity(), false, Role.coach); } if(withComment) { diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GroupBulkDownloadResource.java b/src/main/java/org/olat/course/nodes/gta/ui/GroupBulkDownloadResource.java new file mode 100644 index 0000000000000000000000000000000000000000..4e42c89e4060bec5901c1f2d294a91826d146407 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/GroupBulkDownloadResource.java @@ -0,0 +1,154 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.ui; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.IOUtils; +import org.olat.basesecurity.GroupRoles; +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.id.Identity; +import org.olat.core.id.OLATResourceable; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.ExportUtil; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.core.util.io.ShieldOutputStream; +import org.olat.course.CourseFactory; +import org.olat.course.ICourse; +import org.olat.course.archiver.ScoreAccountingHelper; +import org.olat.course.nodes.AssessableCourseNode; +import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.TaskList; +import org.olat.group.BusinessGroup; +import org.olat.group.BusinessGroupService; + +/** + * + * Initial date: 3 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class GroupBulkDownloadResource implements MediaResource { + + private static final OLog log = Tracing.createLoggerFor(GroupBulkDownloadResource.class); + + private final Locale locale; + private final String encoding = "UTF-8"; + private final List<BusinessGroup> groups; + private final GTACourseNode courseNode; + private final OLATResourceable courseOres; + + public GroupBulkDownloadResource(GTACourseNode courseNode, OLATResourceable courseOres, + List<BusinessGroup> groups, Locale locale) { + this.groups = groups; + this.locale = locale; + this.courseNode = courseNode; + this.courseOres = courseOres; + } + + @Override + public boolean acceptRanges() { + return false; + } + + @Override + public String getContentType() { + return "application/zip"; + } + + @Override + public Long getSize() { + return null; + } + + @Override + public InputStream getInputStream() { + return null; + } + + @Override + public Long getLastModified() { + return null; + } + + @Override + public void prepare(HttpServletResponse hres) { + try { + hres.setCharacterEncoding(encoding); + } catch (Exception e) { + log.error("", e); + } + + String label = StringHelper.transformDisplayNameToFileSystemName(courseNode.getShortName()) + + "_" + Formatter.formatDatetimeWithMinutes(new Date()) + ".zip"; + String urlEncodedLabel = StringHelper.urlEncodeUTF8(label); + hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + urlEncodedLabel); + hres.setHeader("Content-Description", urlEncodedLabel); + + ZipOutputStream zout = null; + try { + zout = new ZipOutputStream(hres.getOutputStream()); + zout.setLevel(9); + ICourse course = CourseFactory.loadCourse(courseOres); + GTAManager gtaManager = CoreSpringFactory.getImpl(GTAManager.class); + + if(courseNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_GRADING)) { + List<Identity> assessableIdentities = CoreSpringFactory.getImpl(BusinessGroupService.class) + .getMembers(groups, GroupRoles.participant.name()); + String courseTitle = course.getCourseTitle(); + String fileName = ExportUtil.createFileNameWithTimeStamp(courseTitle, "xlsx"); + List<AssessableCourseNode> nodes = Collections.<AssessableCourseNode>singletonList(courseNode); + try { + zout.putNextEntry(new ZipEntry(fileName)); + ScoreAccountingHelper.createCourseResultsOverviewXMLTable(assessableIdentities, nodes, course, locale, new ShieldOutputStream(zout)); + zout.closeEntry(); + } catch (Exception e) { + log.error("", e); + } + } + + TaskList taskList = gtaManager.getTaskList(course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(), courseNode); + for(BusinessGroup businessGroup:groups) { + courseNode.archiveNodeData(course, businessGroup, taskList, "", zout); + } + } catch (Exception e) { + log.error("", e); + } finally { + IOUtils.closeQuietly(zout); + } + } + + @Override + public void release() { + // + } +} diff --git a/src/main/java/org/olat/course/nodes/gta/ui/NewSolutionController.java b/src/main/java/org/olat/course/nodes/gta/ui/NewSolutionController.java index 45283e387679b08c9616e35a9e48efa6275f78a7..c56951e1eed43e7b2ce08fff74015b77877e073f 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/NewSolutionController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/NewSolutionController.java @@ -67,6 +67,12 @@ public class NewSolutionController extends FormBasicController { formLayout.add(formButtons); uifactory.addFormSubmitButton("submit", "create", formButtons); uifactory.addFormCancelButton("cancel", formButtons, ureq, getWindowControl()); + + String jsPage = velocity_root + "/new_task_js.html"; + FormLayoutContainer jsCont = FormLayoutContainer.createCustomFormLayout("js", getTranslator(), jsPage); + jsCont.contextPut("titleId", titleEl.getFormDispatchId()); + jsCont.contextPut("filenameId", filenameEl.getFormDispatchId()); + formLayout.add(jsCont); } @Override diff --git a/src/main/java/org/olat/course/nodes/gta/ui/NewTaskController.java b/src/main/java/org/olat/course/nodes/gta/ui/NewTaskController.java index 07af0299e985400a2f16a8c8398dcbf90d0d7733..d1c2266b614ea5260d5ed2e4c7b29e80a8714040 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/NewTaskController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/NewTaskController.java @@ -69,6 +69,12 @@ public class NewTaskController extends FormBasicController { formLayout.add(formButtons); uifactory.addFormSubmitButton("submit", "create", formButtons); uifactory.addFormCancelButton("cancel", formButtons, ureq, getWindowControl()); + + String jsPage = velocity_root + "/new_task_js.html"; + FormLayoutContainer jsCont = FormLayoutContainer.createCustomFormLayout("js", getTranslator(), jsPage); + jsCont.contextPut("titleId", titleEl.getFormDispatchId()); + jsCont.contextPut("filenameId", filenameEl.getFormDispatchId()); + formLayout.add(jsCont); } @Override diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/coach.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/coach.html index 6d271355b47cc88cff1638cd25748a7870fb1d41..e93a9a127ea0fc649426dac600e9fc6d3f405c88 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_content/coach.html +++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/coach.html @@ -1,7 +1,3 @@ -#if($r.available("contextualSubscription")) - <div class="clearfix">$r.render("contextualSubscription")</div> -#end - #if($groupName && !$groupName.isEmpty()) <h4> <i class="o_icon o_icon_group"> </i> $r.escapeHtml($groupName) @@ -124,6 +120,9 @@ <div class="o_step $revisionCssClass"> <div class="o_bar"></div> <h4 class="o_title"> <a href="#o_step_revision_content" data-toggle="collapse" aria-expanded="$collapse_revision" #if(!$collapse_revision) class="collapsed" #end>$r.translate("run.revision")</a></h4> + #if($revisionDueDate) + <div class="o_meta">$r.translate("run.revision.due.date", $revisionDueDate)</div> + #end <div id="o_step_revision_content" class="o_content collapse #if($collapse_revision) in #end" aria-expanded="$collapse_revision"> #if($r.available("revisionDocs")) $r.render("revisionDocs") @@ -182,6 +181,11 @@ /* ]]> */</script> #end </div> +#if($r.visible("coach.reset.button")) +<div class="o_button_group"> + $r.render("coach.reset.button") +</div> +#end #if($userLog || $groupLog) <div class="o_box"> #o_togglebox_start("o_course_run_log" $r.translate("log.title")) diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/coach_selection.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/coach_selection.html index b77a68ce4564dab9a1a91d39d3a4bc6f0cd0a9ac..391b4852ad52177d707d7b0245040c6f77a66702 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_content/coach_selection.html +++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/coach_selection.html @@ -1,17 +1,33 @@ +<div class="o_gta_coach_selection"> #if($multipleGroupsWarning && !$multipleGroupsWarning.isEmpty()) <div class="o_warning">$r.xssScan($multipleGroupsWarning)</div> #end #if($r.available("selection")) - #if($r.available("list")) - $r.render("backLink") - #end - #if($r.available("contextualSubscription")) - $r.render("contextualSubscription") + #if($r.available("backLink") || $r.available("contextualSubscription")) + <div class="clearfix o_gta_coach_selection_bar"> + #if($r.available("backLink")) + $r.render("backLink") + #end + #if($r.available("contextualSubscription")) + $r.render("contextualSubscription") + #end + </div> #end + $r.render("selection") #elseif($r.available("list")) #if($r.available("contextualSubscription")) - <div class="clearfix">$r.render("contextualSubscription")</div> + <div class="o_button_group o_button_group_right"> + $r.render("bulk.download.title") + + <div style="display:inline-block;"> + $r.render("contextualSubscription") + </div> + </div> #end $r.render("list") +#end +</div> +#if($r.available("solutionDownload")) + $r.render("solutionDownload") #end \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/documents_readonly.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/documents_readonly.html index 7dc61ff6a75def1c88e1ca0fcf5cbadb8c5b450e..72d5a1ee0a68c3842e05367d792c6627d8484078 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_content/documents_readonly.html +++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/documents_readonly.html @@ -9,4 +9,7 @@ #foreach($docInfo in $linkNames) <li>$r.render($docInfo.linkName) #if($docInfo.uploadedBy)<small>$r.translate("uploaded.by",$docInfo.uploadedBy)</small>#end #if($r.isNotNull($docInfo.lastModified))<small>$r.translate("lastmodified",$docInfo.lastModified)</small>#end</li> #end -</ul> \ No newline at end of file +</ul> +#if($r.available("download")) + $r.render("download") +#end \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/new_task_js.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/new_task_js.html new file mode 100644 index 0000000000000000000000000000000000000000..14b5e898b37e8748863f695725929af8e572d01f --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/new_task_js.html @@ -0,0 +1,16 @@ +<script> +/* <![CDATA[ */ +jQuery(function() { + jQuery('#$titleId').on('keyup', function() { + var copy = jQuery('#$filenameId').attr('data-copy'); + if(copy != 'stop') { + var name = o_normalizeFilename(jQuery('#$titleId').val()); + jQuery('#$filenameId').val(name + ".html"); + } + }); + jQuery('#$filenameId').on('keyup', function() { + jQuery('#$filenameId').attr('data-copy', 'stop'); + }); +}); +/* ]]> */ +</script> \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/participant_reset_task.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/participant_reset_task.html new file mode 100644 index 0000000000000000000000000000000000000000..cd0f75f521f6388cc3365a0821dbeedcb9b60a02 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/participant_reset_task.html @@ -0,0 +1,6 @@ +<div><p>$msg</p></div> +<div class="o_button_group"> + $r.render("buttons") +</div> + + diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/run.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/run.html index 4e5c2747cbaf89d9b75340239336d66d66fd6c6b..a833e108950742e059db75ad42bc6c4995a46bcf 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_content/run.html +++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/run.html @@ -41,6 +41,15 @@ $r.render("availableTasks") #elseif($r.available("myAssignedTask")) $r.render("myAssignedTask") + #if($r.visible("participant.reset.button")) + <div class="o_button_group"> + $r.render("participant.reset.button") + </div> + #end + #elseif($r.visible("participant.reset.button")) + <div class="o_button_group"> + $r.render("participant.reset.button") + </div> #end </div> </div> @@ -118,6 +127,10 @@ <div class="o_step $revisionCssClass"> <div class="o_bar"></div> <h4 class="o_title"> <a href="#o_step_revision_content" data-toggle="collapse" aria-expanded="$collapse_revision" #if(!$collapse_revision) class="collapsed" #end>$r.translate("run.revision")</a></h4> + #if($revisionDueDate) + <div class="o_meta">$r.translate("run.revision.due.date", $revisionDueDate)</div> + #end + <div id="o_step_revision_content" class="o_content collapse #if($collapse_revision) in #end" aria-expanded="$collapse_revision"> #if($r.available("revisionDocs")) $r.render("revisionDocs") diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties index b1cee0a9d405ceae48f9aa4674e95cd7ecbbcc65..4395fde0308e20dac82fb93cee11f93d96c20a0f 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties @@ -1,9 +1,10 @@ -#Fri Sep 30 15:06:39 CEST 2016 +#Fri Aug 18 10:03:29 CEST 2017 add.solution=Musterl\u00F6sung hochladen add.task=Aufgabe hinzuf\u00FCgen assessment.group.tool=Gruppe bewerten assignment.config.title=Aufgabe zuweisen assignment.deadline=Zuweisung bis ... +assignment.duedate=$\:assignment.deadline before=vorher bulk.download.title=Alle abgegebenen Dokumente herunterladen bulk.review=Beurteilung herunterladen @@ -41,6 +42,9 @@ coach.feedback.documents.desc=Die hier eingestellten Dokumente werden f\u00FCr d coach.feedback.documents.title=Dokumente f\u00FCr Feedback vorbereiten coach.need.revision.button=Ben\u00F6tigt \u00DCberarbeitung coach.reopen=Neu er\u00F6ffnen +coach.reset.button=Daten von Aufgabe zur\u00FCcksetzen +coach.reset.task.confirm.text=Wollen Sie "{0}" erlauben seine Aufgabe zur\u00FCckzusetzen? +coach.reset.task.confirm.title=Daten von Aufgabe zur\u00FCcksetzen coach.reviewed.button=Abgabe akzeptieren coach.reviewed.confirm.text=Bitte best\u00E4tigen Sie dass die Abgabe akzeptiert wird. Die Aufgabe wird damit f\u00FCr den Benutzer beendet, und er erh\u00E4lt keine weitere \u00DCberarbeitungsm\u00F6glichkeit. coach.reviewed.confirm.title=Best\u00E4tigung\: Abgabe akzeptiert @@ -76,7 +80,11 @@ document.date=Datum document.open.editor=Dokument erstellen download.task=Aufgabe herunterladen download.task.infos={0} ({1} MB) +duedate.standard=Standard Datum\: {0} +duedates=Verl\u00E4ngern +duedates.user=Verl\u00E4ngern f\u00FCr "{0}" edit.task=Aufgabe bearbeiten +editor.revisions.title=R\u00FCckgabe Konfiguration editor.title=Abgabe Konfiguration embedded.editor=Abgabe mit OpenOLAT Texteditor enabled=eingeschaltet @@ -109,29 +117,56 @@ group.comment=Gruppe Kommentar group.passed=Gruppe bestanden group.score=Gruppe Punkte group.title=Leistungs\u00FCbersicht +highscore.forminfo=Die HighScore Funktionalit\u00E4t bezieht sich auf die einzelnen Mitglieder einer Gruppe. Ein Vergleich auf Ebene der Gruppen ist nicht m\u00F6glich. +info.task.reset.allowed=Die Aufgabe wurde zur\u00FCckgesetzt. Der Teilnehmer kann dies nun best\u00E4tigen. info.title=$org.olat.course.nodes.ms\:info.title -lastmodified= am {0} +lastmodified=am {0} log.title=\u00C4nderungsverlauf -mail.confirm.assignment.body=Zuweisung war erfolgreich +mail.confirm.assignment.body=Liebe(r) {0} {1}\n\nSie haben im Kurs "{2}" die Aufgabe "{3}" ausgew\u00E4hlt. Die Zuweisung war erfolgreich. mail.confirm.assignment.subject=Zuweisung mailto.group=E-Mail an Gruppe mailto.user=E-Mail an Benutzer max.documents=Max. Anzahl von Dokumenten -notifications.correction=Neue Korrektur "{0}" von "{1}" -notifications.header=Gruppenaufgabe in Kurs "{0}" -notifications.revision.group=Neue \u00DCberarbeitungen "{0}" von "{2}" f\u00FCr die Gruppe "{1}" hochgeladen -notifications.revision.individual=Neue \u00DCberarbeitungen "{0}" von "{1}" -notifications.solution=Neue Musterl\u00F6sung "{0}" -notifications.submission.group=Neue abgegebene Dokumente "{0}" von "{2}" f\u00FCr Gruppe "{1}" hochgeladen -notifications.submission.individual=Neue abgegebene Dokumente "{0}" von "{1}" +no.submission=Nicht abgegeben +notifications.accepted=Ihre Aufgabe "{0}" im Kurs "{1}" wurde akzeptiert. +notifications.assessment.doc=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" stehen bereit Bewertungsdokumente zum Download\: "{2}". +notifications.assessment.passed=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" haben Sie eine Bewertung erhalten. Sie haben {3}. +notifications.assessment.passed.false=nicht bestanden +notifications.assessment.passed.true=bestanden +notifications.assessment.score=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" haben Sie eine Bewertung erhalten. Ihre Punktzahl betr\u00E4gt {2} Punkte. +notifications.assessment.score.notpassed=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" haben Sie eine Bewertung erhalten. Ihre Punktzahl betr\u00E4gt {2} Punkte und Sie haben {3}. +notifications.assessment.score.passed=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" haben Sie eine Bewertung erhalten. Ihre Punktzahl betr\u00E4gt {2} Punkte und Sie haben {3}. +notifications.correction=F\u00FCr Ihre Aufgabe "{0}" im Kurs "{1}" wurde eine \u00DCberarbeitung angefordert. +notifications.correction.doc=Sie haben ein Feedback f\u00FCr die Aufgabe "{0}" im Kurs "{1}" von {3} erhalten\: "{2}". +notifications.correction.duedate=$\:notifications.correction Die \u00DCberarbeitungsfrist wurde auf den {2} gesetzt. +notifications.group.header=Gruppenaufgabe in Kurs "{0}" +notifications.group.header.task=Gruppenaufgabe "{0}" in Kurs "{1}" +notifications.individual.header=Aufgabe in Kurs "{0}" +notifications.individual.header.task=Aufgabe "{0}" in Kurs "{1}" +notifications.revision.group=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" wurde eine neue \u00DCberarbeitungen f\u00FCr die Gruppe "{2}" abgegeben. +notifications.revision.group.doc=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" wurde eine neue \u00DCberarbeitungen "{2}" f\u00FCr die Gruppe "{3}" hochgeladen. +notifications.revision.individual=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" wurde eine neue \u00DCberarbeitungen von "{2}" abgegeben. +notifications.revision.individual.doc=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" wurde eine neue \u00DCberarbeitungen "{2}" von "{3}" hochgeladen. +notifications.solution=Im Kurs "{0}" steht die folgende Musterl\u00F6sung zum Download bereit\: "{1}". +notifications.solution.task=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" steht die folgende Musterl\u00F6sung zum Download bereit\: "{2}". +notifications.submission.group=Die Aufgabe "{0}" im Kurs "{1}" wurde f\u00FCr Gruppe "{2}" abgegeben. +notifications.submission.group.doc=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" wurde ein neues Dokument "{2}" von "{3}" f\u00FCr Gruppe "{4}" hochgeladen. +notifications.submission.individual=Die Aufgabe "{0}" im Kurs "{1}" wurde von "{2}" abgegeben. +notifications.submission.individual.doc=F\u00FCr die Aufgabe "{0}" im Kurs "{1}" wurde ein neues Dokument "{2}" von "{3}" hochgeladen. open.group=Gruppe \u00F6ffnen pane.tab.accessibility=Zugang pane.tab.assignment=Aufgabenstellung pane.tab.grading=Bewertung +pane.tab.highscore=HighScore +pane.tab.review=R\u00FCckgabe und Feedback pane.tab.solutions=Musterl\u00F6sung pane.tab.submission=Abgabe pane.tab.workflow=Workflow -pane.tab.highscore=HighScore +participant.confirm.reset.task.nok=Nein, ich behalte meine Aufgabe +participant.confirm.reset.task.ok=Ja, Aufgabe zur\u00FCcksetzen +participant.confirm.reset.task.text=Ihnen wurde von {0} erlaubt, Ihre Aufgabe "{1}" zur\u00FCckzusetzen. Alle Dokumente, welche Sie bereits hochgeladen haben, werden unwiderruflich gel\u00F6scht. +participant.confirm.reset.task.title=Aufgabe zur\u00FCcksetzen +participant.reset.button=Daten zur\u00FCcksetzen passed.false=$org.olat.course.assessment\:passed.false passed.true=$org.olat.course.assessment\:passed.true preview=$org.olat.course.nodes.ta\:form.task.preview @@ -152,7 +187,7 @@ process.review.explanation=Der Betreuer begutachtet die abgegebene L\u00F6sung. process.revision=\u00DCberarbeitung process.revision.explanation=Der Benutzer \u00FCberarbeitet die Aufgabe. process.solution=L\u00F6sung -process.solution.explanation=Der Benutzer hat die Musterl\u00F6sung erhalten. Bei verf\u00FCgbarer Bewertung kann der Betreuer nun die Aufgabe bewerten. +process.solution.explanation=Der Benutzer hat die Musterl\u00F6sung erhalten order wird sie am vordefinierten Datum erhalten. Bei verf\u00FCgbarer Bewertung kann der Betreuer nun die Aufgabe bewerten. process.submission=Abgabe process.submission.explanation=Der Benutzer bearbeitet gerade die Aufgabe. relative.dates=Relatives Datum @@ -167,6 +202,7 @@ review.and.correction=R\u00FCckgabe und Feedback review.enabled=R\u00FCckgabe von korrigierten Arbeiten und Feedback aktivieren revision.enabled=Abgabe von \u00DCberarbeitungen durch Teilnehmer nach Korrektur, aktivierbar durch Betreuer revision.period=\u00DCberarbeitung +revisions.duedate=\u00DCberarbeitung bis... run.assignment.due.date=Zuweisung Termin\: {0} run.assignment.title=Zuweisung Aufgabenstellung run.coach=Korrigieren @@ -184,6 +220,7 @@ run.review.waiting=Ihr Betreuer begutachtet nun die abgegebene Arbeit. Sie werde run.revised.description=Die folgenden \u00FCberarbeiteten Dokumente wurden von Ihnen eingereicht\: run.revised.nofiles=Die \u00DCberarbeitung wurde ohne Dokumente abgegeben. run.revision=\u00DCberarbeitung +run.revision.due.date=\u00DCberarbeitung Termin\: {0} run.revision.period.description=$\:run.corrections.rejected Erstellen Sie ein \u00FCberarbeitetes Dokument oder laden Sie eines hoch. run.run=Aufgabe run.solution=Musterl\u00F6sung @@ -209,18 +246,21 @@ run.submitted.nofiles=Die Abgabe erfolgte ohne Dokumente. sample.solution=Musterl\u00F6sungen sample.solution.enabled=Musterl\u00F6sungen f\u00FCr Teilnehmer bereitstellen sample.solution.visible.after=Sichtbar nach ... +sample.solution.visible.all=Musterl\u00F6sung nach Erreichen des MusterL\u00F6sung-Datums f\u00FCr alle sichtbar, inklusive jene, die keine Aufgabe abgegeben haben. sampling=Typ der Ziehung sampling.reuse=Aufgabe wird mehreren Benutzern / Gruppe zugewiesen sampling.unique=Aufgabe wird genau einem Benutzer / Gruppe zugewiesen save.done=Speichern als vervollst\u00E4ndigt selected.group=Die Gruppe f\u00FCr diese Aufgabe ist\: <i class\="o_icon o_icon_group"> </i> "{0}" +solution.duedate=Musterl\u00F6sung ab... solution.file=Datei solution.list.description=W\u00E4hlen Sie "$\:add.solution" oder "$\:create.solution" um eine Musterl\u00F6sung hinzuzuf\u00FCgen, oder "$\:replace" oder "$org.olat.core\:edit" um eine bestehende Musterl\u00F6sung zu bearbeiten. Bitte beachten Sie dass Musterl\u00F6sungen keiner spezifischen Aufgabe zugewiesen werden. -solution.list.title=Musterl\u00F6sungen hochladen +solution.list.title=Musterl\u00F6sung solution.title=Titel submission=Abgabe submission.add.title=Dokument hinzuf\u00FCgen submission.confirmation=Hiermit wird best\u00E4tigt, dass $first $last ($email) $numberOfFiles Datei(en) ($filename) am $date um $time hochgeladen hat. +submission.duedate=$\:submit.deadline submission.email.confirmation=Diesen Text zus\u00E4tzlich als E-Mail versenden. submission.enabled=Abgabe von L\u00F6sungen f\u00FCr Teilnehmer aktivieren submission.mail.subject=Best\u00E4tigungs-E-Mail @@ -234,12 +274,14 @@ submit.submit.title=Schritt 2\: Dokumente an Betreuer \u00FCbermitteln table.header.author=Autor table.header.comment=Kommentar table.header.details.gta=$org.olat.course.nodes.ta\:table.header.details.ta +table.header.duedates=Fristen table.header.edit=Aktion table.header.group.name=Gruppe table.header.group.step=Schritt table.header.group.taskName=Aufgabe table.header.passed=Bestanden table.header.score=Punkte +table.header.submissionDate=Abgabedatum table.header.uploaded.by=Hochgeladen von task.alreadyChosen=$org.olat.course.nodes.ta\:task.chosen task.assigned.description=Die folgende Aufgabe wurde Ihnen zugewiesen\: @@ -267,8 +309,8 @@ task.type.title=Aufgabentyp upload.document=Dokument hochladen uploaded.by=hochgeladen von {0} user.visibility=$org.olat.course.assessment.ui.tool\:user.visibility -user.visibility.visible=$org.olat.course.assessment.ui.tool\:user.visibility.visible user.visibility.hidden=$org.olat.course.assessment.ui.tool\:user.visibility.hidden +user.visibility.visible=$org.olat.course.assessment.ui.tool\:user.visibility.visible wait.for.solutions=Die Musterl\u00F6sung wird zum angegebenen Zeitpunkt freigegeben. warning.group.pick.task=Dies ist eine Gruppenaufgabe\! Die hier getroffene Auswahl ist f\u00FCr alle Mitglieder der Gruppe "{0}" g\u00FCltig\! Stellen Sie sicher, dass diese Auswahl zuvor innerhalb Ihrer Gruppe diskutiert wurde\! Nur ein Gruppenmitglied kann die Gruppenaufgabe ausw\u00E4hlen. warning.group.submit=Dies ist eine Gruppenaufgabe\! Das abgegebene Dokument ist f\u00FCr alle Mitglieder der Gruppe "{0}" g\u00FCltig\! Stellen Sie sicher dass diese L\u00F6sung zuvor innerhalb Ihrer Gruppe diskutiert wurde\! Nur ein Gruppenmitglied kann eine L\u00F6sung im Namen aller Gruppenmitglieder abgeben. @@ -281,4 +323,3 @@ warning.tasks.in.process.delete.title=$\:warning.tasks.in.process.title warning.tasks.in.process.text=Es gibt bereits Benutzer die den Aufgabenprozess gestartet haben. \u00C4nderungen an der Workflow-Konfiguration kann f\u00FCr diese Benutzer zu Problemen f\u00FChren. Informationen dazu finden Sie im <a href\="{0}" target\="_blank"><i class\='o_icon o_icon_help'> </i> Handbuch</a>. warning.tasks.in.process.title=Aufgabenprozess bereits gestartet warning.tasks.submitted=Sie k\u00F6nnen diese Aufgabe nicht mehr bearbeiten, sie wurde bereits abgegeben. -highscore.forminfo=Die HighScore Funktionalität bezieht sich auf die einzelnen Mitglieder einer Gruppe. Ein Vergleich auf Ebene der Gruppen ist nicht möglich. diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties index 1e743bff3528866535f2b9418a1272761da2af49..436e44a116c606e2e80c3c3cff99bd88d11600e4 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties @@ -1,16 +1,17 @@ -#Wed Jan 11 13:33:58 CET 2017 -add.solution=Add solution -add.task=Add task +#Fri Aug 18 10:03:18 CEST 2017 +add.solution=Upload solution +add.task=Upload assignment assessment.group.tool=Grade group assignment.config.title=Task assignment configuration assignment.deadline=Assignment deadline +assignment.duedate=$\:assignment.deadline before=beforehand bulk.download.title=Download all submitted files bulk.review=Download review bulk.revisions=Download revised documents bulk.solutions=Download solutions bulk.submitted.documents=Download submitted documents -bulk.submitted.revisions=Download submitted corrections +bulk.submitted.revisions=Download corrections change.group=Change active group change.group.description=You are participating in multiple groups. choose.areas=Select areas @@ -18,11 +19,11 @@ choose.groups=Select groups choosed.areas=Areas choosed.groups=Groups coach.assessment=Grade -coach.back.to.submission=Re-open submission +coach.back.to.submission=Reopen submission coach.back.to.submission.confirm.text=Are you sure you wish to re-open the task submission for "{0}"? -coach.back.to.submission.confirm.title=Re-open submission -coach.back.to.submission.desc=This action allows you to reset the submission status if a participant accidentally closed the submission step. -coach.close.revision.button=Revision accepted +coach.back.to.submission.confirm.title=Reopen submission +coach.back.to.submission.desc=This action allows you to reset the submission status if a participant has submitted by accident. +coach.close.revision.button=Accept revision coach.collect.confirm.desc=In case a participant forgot to finalize the submission process, coaches can manually collect documents of a participant. coach.collect.confirm.text=You are about to close the submission for "{0}". Please make sure all required documents were submitted before clicking "OK". coach.collect.confirm.title=Collect document(s) @@ -35,13 +36,16 @@ coach.corrections.description=You have returned the following documents. coach.corrections.rejected=The submission has been rejected for revision. coach.corrections.waiting=The submission is waiting to be reviewed coach.document=Documents -coach.document.open.editor=Open editor +coach.document.open.editor=Create document coach.documents.successfully.reviewed=Reviewed\! -coach.feedback.documents.desc=Uploaded documents are visible to the participants as soon as you have either accepted the submission as is, or requested a revision +coach.feedback.documents.desc=Uploaded documents are visible to the participants as soon as you have either accepted the submission or requested a revision. coach.feedback.documents.title=Prepare feedback documents coach.need.revision.button=Needs revision coach.reopen=Reopen -coach.reviewed.button=Submission accepted +coach.reset.button=Reset data of task +coach.reset.task.confirm.text=Do you want to allow "{0}" to reset its task? +coach.reset.task.confirm.title=Reset data of task +coach.reviewed.button=Accept submission coach.reviewed.confirm.text=Please confirm your acceptance of the submitted documents. The task is now closed for the user, and there is no revision option available. coach.reviewed.confirm.title=Confirm acceptance of submitted documents coach.revisions.confirm.text=Please confirm the request for a revision. The user is now allowed to submit more documents. @@ -50,10 +54,10 @@ coach.revisions.confirm.title=Revision needed coach.revisions.description=You have received the following revised documents coach.revisions.nofiles=The revision was submitted without documents coach.submit.corrections.to.revision.button=$\:coach.need.revision.button -coach.submitted.documents.description=These documents have been submitted +coach.submitted.documents.description=These documents have been submitted\: coach.submitted.nofiles=The submission was done without documents coach.task.assigned.description=The following task has been assigned -coach.verdict.desc=Submitted documents can be either accepted or rejected for revision. Once the submitted documents are accepted, the submission process is closed. +coach.verdict.desc=Submitted documents can either be accepted or rejected. Once the submitted documents are accepted, the submission process is closed. coach.verdict.title=Give feedback coach.waiting.assignment=Waiting for assignment coach.waiting.assignment.description=The task has not been assigned yet. The submission and reviewing process can only be started when the task has been assigned first. @@ -68,15 +72,19 @@ create=Create create.areas=Create learning area create.groups=Create group create.solution=Create solution -create.task=Create task +create.task=Create assignment days.after=days after details=Details document=Submitted documents document.date=Date -document.open.editor=Open editor +document.open.editor=Create document download.task=Download task download.task.infos={0} ({1} MB) +duedate.standard=Standard date\: {0} +duedates=Extend +duedates.user=Extend for "{0}" edit.task=Edit task +editor.revisions.title=Revision configuration editor.title=Submission configuration embedded.editor=Submit with OpenOLAT text editor enabled=enabled @@ -109,29 +117,56 @@ group.comment=Group comment group.passed=Group passed group.score=Group score group.title=Score summary +highscore.forminfo=The high-score feature refers to the members of a group. A comparison on group level is not available. +info.task.reset.allowed=The task has been reset. The participant can confirm it now. info.title=$org.olat.course.nodes.ms\:info.title -lastmodified= at {0} +lastmodified=at {0} log.title=Change log -mail.confirm.assignment.body=Assignment was successful +mail.confirm.assignment.body=Dear {0} {1}\n\nYou have choosed the following assignment "{3}" in course "{2}". The assignment was successful. mail.confirm.assignment.subject=Assignment mailto.group=Mail to group mailto.user=Mail to user max.documents=Max. number of documents -notifications.correction=New correction "{0}" of "{1}" -notifications.header=Group task in course "{0}" -notifications.revision.group=New revisions "{0}" of "{2}" uploaded for group "{1}" -notifications.revision.individual=New revisions "{0}" of "{1}" -notifications.solution=New sample solutions "{0}" -notifications.submission.group=New documents "{0}" von "{2}" submitted for group "{1}" -notifications.submission.individual=New submitted documents "{0}" of "{1}" +no.submission=No submission +notifications.accepted=Your task "{0}" in the course "{1}" has been accepted. +notifications.assessment.doc=You received a grading document for the task "{0}" in the course "{1}"\: "{2}". +notifications.assessment.passed=You received a grade for the task "{0}" in the course "{1}". You have {3}. +notifications.assessment.passed.false=failed +notifications.assessment.passed.true=passed +notifications.assessment.score=You received a grade for the task "{0}" in the course "{1}". Your score is {2}. +notifications.assessment.score.notpassed=You received a grade for the task "{0}" in the course "{1}". You haven't passed with a score of {2}. +notifications.assessment.score.passed=You received a grade for the task "{0}" in the course "{1}". You have passed with a score of {2}. +notifications.correction=You have received feedback for the task "{0}" in the course "{1}". +notifications.correction.doc=You have received feedback for the task "{0}" in the course "{1}" by {3}\: "{2}". +notifications.correction.duedate=$\:notifications.correction The deadline for the revision is set to the {2}. +notifications.group.header=Group task in course "{0}" +notifications.group.header.task=Group task "{0}" in course "{1}" +notifications.individual.header=Task in course "{0}" +notifications.individual.header.task=Task "{0}" in course "{1}" +notifications.revision.group=For the task "{0}" in course "{1}" was a new revision submitted for the group "{2}". +notifications.revision.group.doc=For the task "{0}" in course "{1}" was a new revision "{2}" submitted for the group "{3}". +notifications.revision.individual=For the task "{0}" in course "{1}" was a new revision submitted by "{2}". +notifications.revision.individual.doc=For the task "{0}" in course "{1}" was a new revision "{2}" submitted by "{3}". +notifications.solution=In the course "{0}" the following sample solution is available for download\: "{1}". +notifications.solution.task=For the task "{0}" in the course "{1}" the following sample solution is available for download\: "{2}". +notifications.submission.group=The task "{0}" in course "{1}" was submitted for the group "{2}". +notifications.submission.group.doc=\=For the task "{0}" in course "{1}" was a new document "{2}" submitted by "{3}" for the group "{4}". +notifications.submission.individual=The task "{0}" in course "{1}" was submitted by "{2}". +notifications.submission.individual.doc=For the task "{0}" in course "{1}" was a new document "{2}" submitted by "{3}". open.group=Open group pane.tab.accessibility=Access pane.tab.assignment=Assignment pane.tab.grading=Grading +pane.tab.highscore=HighScore +pane.tab.review=Revisions and feedback pane.tab.solutions=Sample solutions pane.tab.submission=Submission pane.tab.workflow=Workflow -pane.tab.highscore=HighScore +participant.confirm.reset.task.nok=No, I keep the task +participant.confirm.reset.task.ok=Yes, the task can be reset +participant.confirm.reset.task.text=You are allowed by {0} to reset your "{1}". All documents you already downloaded will be deleted. +participant.confirm.reset.task.title=Reset +participant.reset.button=Reset task passed.false=$org.olat.course.assessment\:passed.false passed.true=$org.olat.course.assessment\:passed.true preview=$org.olat.course.nodes.ta\:form.task.preview @@ -139,7 +174,7 @@ preview.disabled=$org.olat.course.nodes.ta\:form.task.without.preview preview.enabled=$org.olat.course.nodes.ta\:form.task.with.preview process.action.explanation=Action needed process.assignment=Assignment -process.assignment.explanation=The user is selecting a task +process.assignment.explanation=The user is selecting a task. process.correction=Correction process.correction.explanation=The coach is reviewing the revised documents. process.graded=Graded @@ -152,7 +187,7 @@ process.review.explanation=The coach is reviewing the submitted documents. process.revision=Revision process.revision.explanation=The user is revising his solution. process.solution=Solution -process.solution.explanation=The user has now access to the sample solution. The coach is able to grade the task, if available. +process.solution.explanation=The user now has access to the sample solution or will get at the predefined date. The coach can now grade the submission (if enabled). process.submission=Submission process.submission.explanation=The user is working on the assigned task. relative.dates=Relative dates @@ -166,36 +201,38 @@ replace.document=Replace document review.and.correction=Return and feedback review.enabled=Enable return box for reviews and feedback revision.enabled=Enable drop box for revisions by participants, can be set by coach -revision.period=Revision phase -run.assignment.due.date=Due date\: {0} +revision.period=Revision +revisions.duedate=Revision until... +run.assignment.due.date=Deadline\: {0} run.assignment.title=Task assignment -run.coach=Correct +run.coach=Submissions run.coach.corrections.description=You have set the following correction request. run.corrections.description=Your coach attached the following files for you\: -run.corrections.rejected=$\:coach.corrections.rejected +run.corrections.rejected=Your submission has been rejected. run.documents.successfully.submitted=Your document(s) have been successfully submitted. run.grading=Grading -run.manage.coach=Manage +run.manage.coach=Edit tasks and sample solutions run.pick.task.description=Please select a task from the list below. run.review=Return and feedback run.review.closed=Your coach has accepted the submitted work for grading. run.review.description=Your coach is now reviewing your submitted documents. You will get notified when a reviewed or corrected version is available. run.review.waiting=Your coach is now reviewing the submitted work. You will get notified when a reviewed or corrected version is available. -run.revised.description=The following revised documents have been submitted by you\: +run.revised.description=You have submitted the following revised documents\: run.revised.nofiles=The revision was submitted without documents -run.revision=Revision phase -run.revision.period.description=$\:run.corrections.rejected Create or upload a revised document. +run.revision=Revision +run.revision.due.date=Revision deadline\: {0} +run.revision.period.description=$\:run.corrections.rejected Please create or upload a revised document. run.run=Task run.solution=Sample solution run.solution.available.date={0} run.solutions.description=The following sample solutions are available for download\: -run.submit=Submit +run.submit=Task submission run.submit.button=Final task submission run.submit.confirm=Please confirm the submission for this task. The submission of the task is final and can not be undone. run.submit.confirm.group=$\:run.submit.confirm<br/>This is a group task\! The submitted document is valid for all members of the group "{0}"\! run.submit.confirm.warning=You have not yet uploaded / created a document. Do you still wish to submit? The submission of the task is final and can not be undone. <br/> The drop box is closed. You will not be able to upload any documents. run.submit.confirm.warning.group=$\:run.submit.confirm.warning<br/>This is a group task\! The submitted document is valid for all members of the group "{0}"\! -run.submit.due.date=Due date\: {0} +run.submit.due.date=Deadline\: {0} run.submit.individual.description.all=Submit your solution by either uploading a document you created on your computer or use the editor to write your solution right here. run.submit.individual.description.editor=Submit your solution by using the editor to write your solution right here. run.submit.individual.description.upload=Submit your solution by uploading a document you created on your computer. @@ -209,37 +246,42 @@ run.submitted.nofiles=The submission was done without documents sample.solution=Sample solution sample.solution.enabled=Provide sample solutions for participants sample.solution.visible.after=Visible after... +sample.solution.visible.all=Sample solutions visible for all after the date is reached, inclusive the one which don't have submitted their task. sampling=Type of sampling sampling.reuse=Your task will be assigned to more than one user / group sampling.unique=Your task will be assigned to only one single user / group save.done=Save as done selected.group=The group for this task is\: <i class\="o_icon o_icon_group"> </i> "{0}" +solution.duedate=Solution until... solution.file=File solution.list.description=Select "$\:add.solution" or "$\:create.solution" to add a solution or "$\:replace" or "$org.olat.core\:edit" to modify an existing solution. Please note that solutions are not assigned to a particular task. -solution.list.title=Upload sample solutions +solution.list.title=Sample solutions solution.title=Title submission=Submission submission.add.title=Add document submission.confirmation=The submission of $numberOfFiles file(s) ($filename) for $first $last ($email) at $date, $time has been confirmed. +submission.duedate=$\:submit.deadline submission.email.confirmation=Send text additionally as email submission.enabled=Enable solution drop box for participants submission.mail.subject=OpenOLAT-confirmation-E-Mail submission.nofile=No file uploaded submission.text=Text after handing in submit.deadline=Submission deadline -submit.documents.desc=Before submitting a task, documents must be either created or uploaded. These documents are not yet submitted and therefore not visible for the coach. +submit.documents.desc=Please create or upload the documents with your solutions to the task. These documents are not yet submitted and therefore not visible to the coach. submit.documents.title=Step 1\: Prepare documents -submit.submit.desc=In order to submit documents and thus make them visible for coaches, you need to confirm the submission by clicking the button below. +submit.submit.desc=To make your solutions visible for coaches, you need to confirm the submission by clicking the button below. submit.submit.title=Step 2\: Submit documents table.header.author=Author table.header.comment=Comment table.header.details.gta=$org.olat.course.nodes.ta\:table.header.details.ta +table.header.duedates=Deadlines table.header.edit=Action table.header.group.name=Group table.header.group.step=Step table.header.group.taskName=Task table.header.passed=Passed table.header.score=Points +table.header.submissionDate=Submission date table.header.uploaded.by=Uploaded by task.alreadyChosen=$org.olat.course.nodes.ta\:task.chosen task.assigned.description=The following task has been assigned to you\: @@ -255,8 +297,8 @@ task.execution=Task execution task.execution.group=as a group task.execution.individual=individual task.file=File -task.list.description=Select "$\:add.task" to add a new task, "$\:create.task" to create a new task using the HTML editor or "$org.olat.core\:edit" or "$\:replace" to modify an existing task. If all users work on the same task, create a single task. -task.list.title=Tasks +task.list.description=Select "$\:add.task" to add a new assignment, "$\:create.task" to create a new assignment using the HTML editor or "$org.olat.core\:edit" or "$\:replace" to modify an existing assignment. If all users work on the same assignment, create a single assignment. +task.list.title=Assignment task.steps.description=Select which elements in the task workflow are enabled and set optional due dates for the workflow management. task.steps.title=Workflow steps task.successfully.assigned=The task was successfully assigned to you. @@ -267,18 +309,17 @@ task.type.title=Task type upload.document=Upload document uploaded.by=uploaded by {0} user.visibility=$org.olat.course.assessment.ui.tool\:user.visibility -user.visibility.visible=$org.olat.course.assessment.ui.tool\:user.visibility.visible user.visibility.hidden=$org.olat.course.assessment.ui.tool\:user.visibility.hidden +user.visibility.visible=$org.olat.course.assessment.ui.tool\:user.visibility.visible wait.for.solutions=The sample solution will be displayed at the date specified above. warning.group.pick.task=This is a group task\! The selection made here is valid for all members of the group "{0}"\! Make sure you discussed this selection within the group prior to selecting a task\! Only one member of the group can select the task for the group. warning.group.submit=This is a group task\! The submitted document is valid for all members of the group "{0}"\! Make sure you discussed this solution document prior to uploading it here\! Only one member of the group can submit a solution on behalf of all group members. warning.group.task=This is a group task\! The task assignment, submission of documents and grading are performed as a group. Contact your group peers on how to proceed on deciding for a task and to collaboratively solve the task. -warning.no.task.choosed=It\u00A0seems\u00A0that\u00A0due\u00A0to\u00A0a\u00A0change in the course element configuration, you\u00A0weren't\u00A0able\u00A0to\u00A0choose a\u00A0task\u00A0for\u00A0this\u00A0task element. -warning.no.task.choosed.coach=It\u00A0seems\u00A0that\u00A0due\u00A0to\u00A0a\u00A0change in the course element configuration, the assignee\u00A0wasn't\u00A0able\u00A0to\u00A0choose a\u00A0task\u00A0for\u00A0this\u00A0task element. +warning.no.task.choosed=It seems that due to a change in the course element configuration, you weren't able to choose a task for this task element. +warning.no.task.choosed.coach=It seems that due to a change in the course element configuration, the assignee wasn't able to choose a task for this task element. warning.submit.documents.edited=You cannot submit the task. The document "{1}" is currently being edited by "{0}". warning.tasks.in.process.delete.text=Do you really wan to delete this task? There are already users who have started the task process. It could result in problems for these users. warning.tasks.in.process.delete.title=$\:warning.tasks.in.process.title warning.tasks.in.process.text=There are already users who have started the task process. Changing the workflow configuration could result in problems for these users. Please refer to the <a href\="{0}" target\="_blank"><i class\='o_icon o_icon_help'> </i> manual</a> for more information. warning.tasks.in.process.title=Task already started warning.tasks.submitted=You cannot edit this task anymore, it has already been submitted. -highscore.forminfo=The high-score feature refers to the members of a group. A comparison on group level is not available. \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties index 2746cb83bf0eb573ac8445e33275c07a8f7d030d..9f24e8fe1474ff7ec14c5364d8f0ce33cbe62e27 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties @@ -1,9 +1,10 @@ -#Thu Mar 09 17:30:34 CET 2017 +#Fri Aug 18 10:05:36 CEST 2017 add.solution=T\u00E9l\u00E9chargez une solution add.task=Ajouter un devoir assessment.group.tool=Evaluer les groupes assignment.config.title=Attribution des devoirs assignment.deadline=Attribution jusqu'au +assignment.duedate=$\:assignment.deadline before=avant bulk.download.title=T\u00E9l\u00E9charger tous les documents que vous avez soumis bulk.review=T\u00E9l\u00E9charger la critique @@ -41,6 +42,9 @@ coach.feedback.documents.desc=Les documents t\u00E9l\u00E9charg\u00E9s sont visi coach.feedback.documents.title=Pr\u00E9parer les document du feedback coach.need.revision.button=N\u00E9cessite une r\u00E9\u00E9criture coach.reopen=R\u00E9ouvrir +coach.reset.button=R\u00E9initialiser les donn\u00E9es du devoir +coach.reset.task.confirm.text=Voulez-vous autoriser "{0}" \u00E0 r\u00E9initialiser son devoir? Il pourra ainsi choisir une nouvelle affectation. +coach.reset.task.confirm.title=R\u00E9initialiser les donn\u00E9es du devoir coach.reviewed.button=Evaluer coach.reviewed.confirm.text=Veuillez confirmer que les documents remis ont \u00E9t\u00E9 accept\u00E9s. Le devoir est donc termin\u00E9 pour l'utilisateur, qui n'aura plus d'occasion de le r\u00E9viser. coach.reviewed.confirm.title=Confirmation\: accepter le document soumis @@ -76,7 +80,11 @@ document.date=Date document.open.editor=R\u00E9diger un document download.task=T\u00E9l\u00E9charger les devoirs download.task.infos={0} ({1} MB) +duedate.standard=Date par d\u00E9faut\: {0} +duedates=Prolonger +duedates.user=Prolongation pour "{0}" edit.task=Editer le devoir +editor.revisions.title=Configuration des corrections editor.title=Configuration du d\u00E9p\u00F4t de documents embedded.editor=Soumettre avec l'\u00E9diteur de texte d'OpenOLAT enabled=activ\u00E9 @@ -110,29 +118,55 @@ group.passed=R\u00E9ussi pour le groupe group.score=Points pour le groupe group.title=Aper\u00E7u des performances highscore.forminfo=La fonction HighScore se r\u00E9f\u00E8re aux membres d'un groupe individuellement. Une comparaison entre groupe n'est pas disponible. +info.task.reset.allowed=Le devoir pourra \u00EAtre r\u00E9initialis\u00E9. Le participant doit encore le confirmer. info.title=$org.olat.course.nodes.ms\:info.title lastmodified=le {0} log.title=Historique des modifications -mail.confirm.assignment.body=Affectation du devoir est r\u00E9ussi. +mail.confirm.assignment.body=Cher, ch\u00E8re {0} {1}\n\nVous avez choisi le devoir "{3}" du cours "{2}". Die Zuweisung war erfolgreich. L'affectation du devoir est r\u00E9ussi. mail.confirm.assignment.subject=Affectation mailto.group=Courriel au groupe mailto.user=Courriel au utilisateur max.documents=Nombre maximum de documents -notifications.correction=Nouvelles corrections "{0}" de "{1}" -notifications.header=Devoirs de groupe du cours "{0}" -notifications.revision.group=De nouveaux remaniements "{0}" de "{2}" pour le groupe "{1}" ont \u00E9t\u00E9 t\u00E9l\u00E9charg\u00E9s. -notifications.revision.individual=De nouveaux remaniements "{0}" de "{1}" -notifications.solution=Nouvelle solution "{0}" -notifications.submission.group=De nouveaux documents "{0}" ont \u00E9t\u00E9 d\u00E9pos\u00E9s par "{1}" pour le groupe "{1}". -notifications.submission.individual=De nouveaux documents "{0}" d\u00E9pos\u00E9s par "{1}" +no.submission=Pas remis +notifications.accepted=Votre devoir "{0}" pour le cours "{1}" a \u00E9t\u00E9 accept\u00E9. +notifications.assessment.doc=Vous pouvez t\u00E9l\u00E9charger un document d'\u00E9valuation pour le devoir "{0}"dans le cours "{1}"\: "{2}". +notifications.assessment.passed=Vous avez re\u00E7u une \u00E9valuation pour le devoir "{0}" du cours "{1}". Vous avez {3}. +notifications.assessment.passed.false=pas r\u00E9ussi +notifications.assessment.passed.true=r\u00E9ussi +notifications.assessment.score=Vous avez re\u00E7u une \u00E9valuation pour le devoir "{0}" du cours "{1}". Votre score est de {2} points. +notifications.assessment.score.notpassed=Vous avez re\u00E7u une \u00E9valuation pour le devoir "{0}" du cours "{1}". Vous avez {3} avec un score de {2} points. +notifications.assessment.score.passed=Vous avez re\u00E7u une \u00E9valuation pour le devoir "{0}" du cours "{1}". Vous avez {3} avec un score de {2} points. +notifications.correction=Une r\u00E9vision a \u00E9t\u00E9 demand\u00E9e pour votre devoir "{0}" du cours "{1}". +notifications.correction.doc=Vous avez re\u00E7u un feedback de {3} pour le devoir "{0}" du cours "{1}"\: "{2}". +notifications.correction.duedate=$\:notifications.correction Le d\u00E9lai de r\u00E9vision a \u00E9t\u00E9 prolong\u00E9 au {2}. +notifications.group.header=Devoir de groupe du cours "{0}" +notifications.group.header.task=Devoir de groupe "{0}" du cours "{1}" +notifications.individual.header=Devoir du cours "{0}" +notifications.individual.header.task=Devoir "{0}" du cours "{1}" +notifications.revision.group=Une nouvelle r\u00E9vision du devoir "{0}" pour le cours "{1}" a \u00E9t\u00E9 remise par le groupe "{2}". +notifications.revision.group.doc=Un document pour une nouvelle r\u00E9vision du devoir "{0}" pour le cours "{1}" par le groupe "{3}" peut \u00EAtre t\u00E9l\u00E9charg\u00E9. +notifications.revision.individual=Une nouvelle r\u00E9vision du devoir "{0}" pour le cours "{1}" a \u00E9t\u00E9 remise par "{2}". +notifications.revision.individual.doc=Un nouveau document pour la r\u00E9vision du devoir "{0}" pour le cours "{1}" a \u00E9t\u00E9 t\u00E9l\u00E9vers\u00E9 par "{3}". +notifications.solution=Une solution pour le cours "{0}" peut \u00EAtre t\u00E9l\u00E9charg\u00E9\: "{1}". +notifications.solution.task=Une solution pour le devoir "{0}" du cours "{1}" peut \u00EAtre t\u00E9l\u00E9charg\u00E9e\: "{2}". +notifications.submission.group=Le devoir "{0}" pour le cours "{1}" a \u00E9t\u00E9 remis par le groupe "{2}". +notifications.submission.group.doc=Un document pour le devoir "{0}" du cours "{1}" a \u00E9t\u00E9 t\u00E9l\u00E9vers\u00E9 par le groupe "{4}"\: {2}. +notifications.submission.individual=Le devoir "{0}" du cours "{1}" a \u00E9t\u00E9 remis par "{2}". +notifications.submission.individual.doc=Un nouveau document a \u00E9t\u00E9 remis par "{3}" pour le devoir "{0}" du cours "{1}". open.group=Ouvrir le groupe pane.tab.accessibility=Acc\u00E8s pane.tab.assignment=Affectation pane.tab.grading=Evaluation pane.tab.highscore=HighScore +pane.tab.review=Evaluation et corrections pane.tab.solutions=Solution mod\u00E8le pane.tab.submission=D\u00E9p\u00F4t pane.tab.workflow=Flux de travail +participant.confirm.reset.task.nok=Non, je garde mon devoir +participant.confirm.reset.task.ok=Oui, je r\u00E9initialise le devoir +participant.confirm.reset.task.text=Vous avez \u00E9t\u00E9 autoris\u00E9 par {0} \u00E0 r\u00E9initialiser le devoir "{1}". Tous les documents que vous avez d\u00E9j\u00E0 t\u00E9l\u00E9charg\u00E9s seront effac\u00E9s d\u00E9finitivement. +participant.confirm.reset.task.title=R\u00E9initialiser le devoir +participant.reset.button=R\u00E9initialiser les donn\u00E9es passed.false=$org.olat.course.assessment\:passed.false passed.true=$org.olat.course.assessment\:passed.true preview=$org.olat.course.nodes.ta\:form.task.preview @@ -153,7 +187,7 @@ process.review.explanation=Le coach corrige un document process.revision=Remaniements process.revision.explanation=L'utilisateur r\u00E9vise un document. process.solution=Solution -process.solution.explanation=L'utilisateur a acc\u00E8s \u00E0 la solution. Le coach peut d\u00E9sormais \u00E9valuer les devoirs si activ\u00E9. +process.solution.explanation=L'utilisateur a acc\u00E8s \u00E0 la solution ou y aura acc\u00E8s \u00E0 la date pr\u00E9d\u00E9finie. Le coach peut d\u00E9sormais \u00E9valuer les devoirs si activ\u00E9. process.submission=D\u00E9p\u00F4t process.submission.explanation=L'utilisateur travaille au devoir. relative.dates=Dates relatives @@ -168,6 +202,7 @@ review.and.correction=Remaniements and corrections review.enabled=activ\u00E9 revision.enabled=sera d\u00E9termin\u00E9e par le coach revision.period=P\u00E9riode de r\u00E9\u00E9criture +revisions.duedate=Date d'\u00E9ch\u00E9ance de r\u00E9vision run.assignment.due.date=D\u00E9lai pour l'affectation\: {0} run.assignment.title=Affectation d'un devoir run.coach=Corriger @@ -185,6 +220,7 @@ run.review.waiting=Votre coach \u00E9value les documents que vous lui avez trans run.revised.description=Vous avez transmis les documents remani\u00E9s suivants\: run.revised.nofiles=La r\u00E9vision a \u00E9t\u00E9 soumise sans le moindre document run.revision=P\u00E9riode de remaniement +run.revision.due.date=D\u00E9lai de r\u00E9vision\: {0} run.revision.period.description=Votre coach a ajout\u00E9 une p\u00E9riode de r\u00E9vision. Cr\u00E9er un document remani\u00E9 ou t\u00E9l\u00E9chargez-en un. run.run=Devoir run.solution=Solutions @@ -210,11 +246,13 @@ run.submitted.nofiles=Le devoir a \u00E9t\u00E9 soumis sans le moindre document. sample.solution=Solutions sample.solution.enabled=activ\u00E9 sample.solution.visible.after=Visible apr\u00E8s le +sample.solution.visible.all=Rendre accessible les solutions pour tous d\u00E8s que le d\u00E9lai pour les solutions a \u00E9t\u00E9 atteint, pour les utilisateurs qui n'ont pas remis leur devoir \u00E9galement. sampling=Type d'affectation sampling.reuse=La t\u00E2che est affect\u00E9e \u00E0 plusieurs groupes / utilisateurs sampling.unique=La t\u00E2che est affect\u00E9e \u00E0 un seul groupe / utilisateur save.done=Sauver comme compl\u00E9t\u00E9 selected.group=Le groupe actif pour ce devoir\: <i class\="o_icon o_icon_group"> </i> "{0}" +solution.duedate=Solution depuis le... solution.file=Document solution.list.description=Cliquez sur "T\u00E9l\u00E9chargez une solution" pour ajouter une solution mod\u00E8le, ou "Editer" pour \u00E9diter une solution existante. Remarquez que les solutions mod\u00E8les ne sont pas affect\u00E9es \u00E0 un devoir sp\u00E9cifique. solution.list.title=T\u00E9l\u00E9charger les solutions @@ -222,6 +260,7 @@ solution.title=Titre submission=D\u00E9p\u00F4t submission.add.title=Ajouter un document submission.confirmation=Nous confirmons que $first $last ($email) a bien t\u00E9l\u00E9charger $numberOfFiles fichier(s) ($filename) le $date \u00E0 $time. +submission.duedate=$\:submit.deadline submission.email.confirmation=Envoyer aussi le texte par courriel submission.enabled=activ\u00E9 submission.mail.subject=Courriel de confirmation OpenOLAT @@ -235,12 +274,14 @@ submit.submit.title=Etape 2\: d\u00E9poser les documents table.header.author=Auteur table.header.comment=Commentaire table.header.details.gta=$org.olat.course.nodes.ta\:table.header.details.ta +table.header.duedates=D\u00E9lais table.header.edit=Action table.header.group.name=Groupe table.header.group.step=Etape table.header.group.taskName=Devoir table.header.passed=R\u00E9ussi table.header.score=Points +table.header.submissionDate=Date de remise table.header.uploaded.by=T\u00E9l\u00E9charger par {0} task.alreadyChosen=$org.olat.course.nodes.ta\:task.chosen task.assigned.description=Le devoir suivant vous a \u00E9t\u00E9 affect\u00E9\: diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_it.properties index 9fa475155bbfc1ed2dca1da1ff7cbf7988397c8d..fb6f1a00a44ca3414d7ba9a82be0d6f0df1d150f 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_it.properties @@ -118,13 +118,6 @@ mail.confirm.assignment.subject=Assegnazione mailto.group=E-mail al gruppo mailto.user=E-mail all'utente max.documents=Numero massimo di documenti -notifications.correction=Nuova correzione "{0}" di "{1}" -notifications.header=Compito di gruppo nel corso "{0}" -notifications.revision.group=Nuove revisioni "{0}" di "{2}" caricate per il gruppo "{1}" -notifications.revision.individual=Nuove revisioni "{0}" di "{1}" -notifications.solution=Nuova soluzione "{0}" -notifications.submission.group=Nuovi documenti "{0}" di "{2}" consegnati per il gruppo "{1}" -notifications.submission.individual=Nuovi documenti consegnati "{0}" di "{1}" open.group=Aprire il gruppo pane.tab.accessibility=Accesso pane.tab.assignment=Assegnazione diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pl.properties index 6b3776df2b36cdb91370ecf2d21ba2efcc113187..3be48f06b752cd72df9f69829c36fa9a9b679e78 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pl.properties @@ -114,13 +114,6 @@ mail.confirm.assignment.subject=Zadanie mailto.group=E-mail do grupy mailto.user=E-mail do uczestnika max.documents=Max. liczba dokument\u00F3w -notifications.correction=New correction "{0}" of "{1}" -notifications.header=Zadanie grupowe w kursie "{0}" -notifications.revision.group=New revisions "{0}" of "{2}" uploaded for group "{1}" -notifications.revision.individual=New revisions "{0}" of "{1}" -notifications.solution=Nowe przyk\u0142adowe rozwi\u0105zanie dla "{0}" -notifications.submission.group=New documents "{0}" out of "{2}" submitted for group "{1}" -notifications.submission.individual=New submitted documents "{0}" of "{1}" open.group=Open group pane.tab.accessibility=Dost\u0119p pane.tab.assignment=Assignment diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pt_BR.properties index ce1170b59d782dd06374338387d9ec6bab8dd073..c4bc05d538b0b2a37a305bb73ce2c7a409147982 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,9 +1,10 @@ -#Thu Mar 16 22:27:05 CET 2017 +#Tue Sep 05 23:35:34 CEST 2017 add.solution=Adicionar solu\u00E7\u00E3o add.task=Adicionar tarefa assessment.group.tool=S\u00E9rie do grupo assignment.config.title=Configura\u00E7\u00E3o de atribui\u00E7\u00E3o de tarefa assignment.deadline=Prazo para atribui\u00E7\u00E3o +assignment.duedate=$\:assignment.deadline before=antecipadamente bulk.download.title=Baixar todos os arquivos enviados bulk.review=Baixar revis\u00E3o @@ -41,6 +42,9 @@ coach.feedback.documents.desc=Documentos enviados s\u00E3o vis\u00EDveis para os coach.feedback.documents.title=Prepare documentos de feedback coach.need.revision.button=Requer revis\u00E3o coach.reopen=Reabrir +coach.reset.button=Resetar dados da tarefa +coach.reset.task.confirm.text=Deseja permitir que "{0}" reajuste sua tarefa? +coach.reset.task.confirm.title=Resetar dados da tarefa coach.reviewed.button=Apresenta\u00E7\u00E3o aceita coach.reviewed.confirm.text=Por favor, confirme a sua aceita\u00E7\u00E3o dos documentos apresentados. A tarefa est\u00E1 agora fechada para o usu\u00E1rio, e n\u00E3o h\u00E1 op\u00E7\u00E3o de revis\u00E3o dispon\u00EDveis. coach.reviewed.confirm.title=Confirmar a aceita\u00E7\u00E3o dos documentos apresentados @@ -76,7 +80,11 @@ document.date=Data document.open.editor=Abrir editor de solu\u00E7\u00E3o download.task=Baixar tarefa download.task.infos={0} ({1} MB) +duedate.standard=Data padr\u00E3o\: {0} +duedates=Ampliar +duedates.user=Ampliar por \u201C{0}\u201D edit.task=Editar tarefa +editor.revisions.title=Configura\u00E7\u00E3o da revis\u00E3o editor.title=Configura\u00E7\u00E3o de envio/apresenta\u00E7\u00E3o embedded.editor=Enviar com editor de texto OpenOLAT enabled=ativado @@ -110,6 +118,7 @@ group.passed=Grupo passou group.score=Pontua\u00E7\u00E3o do grupo group.title=Resumo da pontua\u00E7\u00E3o highscore.forminfo=A caracter\u00EDstica "HighScore" refere-se aos membros de um grupo. Uma compara\u00E7\u00E3o no n\u00EDvel do grupo n\u00E3o est\u00E1 dispon\u00EDvel. +info.task.reset.allowed=A tarefa foi reiniciada. O participante pode confirm\u00E1-lo agora. info.title=$org.olat.course.nodes.ms\:info.title lastmodified=em {0} log.title=Registro de altera\u00E7\u00F5es @@ -118,21 +127,46 @@ mail.confirm.assignment.subject=Atribui\u00E7\u00E3o mailto.group=Email para o grupo mailto.user=Email para o usu\u00E1rio max.documents=N\u00FAmero m\u00E1ximo de documentos -notifications.correction=Nova corre\u00E7\u00E3o "{0}" of "{1}" -notifications.header=Tarefa de Grupo no curso "{0}" -notifications.revision.group=Novas revis\u00F5es "{0}" de "{2}" enviadas para o grupo "{1}" -notifications.revision.individual=Novas revis\u00F5es "{0}" de "{1}" -notifications.solution=Nova solu\u00E7\u00F5es de amostra "{0}" -notifications.submission.group=Novos documentos "{0}" de "{2}" apresentados para o grupo "{1}" -notifications.submission.individual=Novos documentos enviados "{0}" of "{1}" +no.submission=Sem envio +notifications.accepted=Sua tarefa "{0}" no curso "{1}" foi aceita. +notifications.assessment.doc=Voc\u00EA recebeu um documento de classifica\u00E7\u00E3o para a tarefa "{0}" no curso "{1}"\: "{2}". +notifications.assessment.passed=Voc\u00EA recebeu uma nota para a tarefa "{0}" no curso "{1}". Voc\u00EA tem {3}. +notifications.assessment.passed.false=Falhou +notifications.assessment.passed.true=Passou +notifications.assessment.score=Voc\u00EA recebeu uma nota para a tarefa "{0}" no curso "{1}". Sua pontua\u00E7\u00E3o \u00E9 {2}. +notifications.assessment.score.notpassed=Voc\u00EA recebeu uma nota para a tarefa "{0}" no curso "{1}". Voc\u00EA n\u00E3o passou com uma pontua\u00E7\u00E3o de {2}. +notifications.assessment.score.passed=Voc\u00EA recebeu uma nota para a tarefa "{0}" no curso "{1}". Voc\u00EA passou com uma pontua\u00E7\u00E3o de {2}. +notifications.correction=Voc\u00EA recebeu coment\u00E1rios para a tarefa "{0}" no curso "{1}". +notifications.correction.doc=Voc\u00EA recebeu coment\u00E1rios para a tarefa "{0}" no curso "{1}" por {3}\: "{2}". +notifications.correction.duedate=$\:notifications.correction O prazo para a revis\u00E3o est\u00E1 definido para o {2}. +notifications.group.header=Tarefa em grupo no curso "{0}" +notifications.group.header.task=Tarefa em grupo "{0}" no curso "{1}" +notifications.individual.header=Tarefa no curso \u201C{0}\u201D +notifications.individual.header.task=Tarefa \u201C{0}\u201D no curso \u201C{1}\u201D +notifications.revision.group=Para a tarefa "{0}" no curso "{1}" uma nova revis\u00E3o foi enviada para o grupo "{2}". +notifications.revision.group.doc=Para a tarefa "{0}" no curso "{1}" uma nova revis\u00E3o "{2}" foi enviada para o grupo "{3}". +notifications.revision.individual=Para a tarefa "{0}" no curso "{1}" uma nova revis\u00E3o foi enviada por "{2}". +notifications.revision.individual.doc=Para a tarefa "{0}" no curso "{1}" uma nova revis\u00E3o "{2}" foi enviada por "{3}". +notifications.solution=No curso "{0}", a seguinte solu\u00E7\u00E3o de amostra est\u00E1 dispon\u00EDvel para download\: "{1}". +notifications.solution.task=Para a tarefa "{0}" no curso "{1}", a seguinte solu\u00E7\u00E3o de exemplo est\u00E1 dispon\u00EDvel para download\: "{2}". +notifications.submission.group=A tarefa "{0}" no curso "{1}" foi enviada para o grupo "{2}". +notifications.submission.group.doc=Para a tarefa "{0}" em curso "{1}" foi um novo documento "{2}" enviado por "{3}" para o grupo "{4}". +notifications.submission.individual=A tarefa "{0}" no curso "{1}" foi enviada por "{2}". +notifications.submission.individual.doc=Para a tarefa "{0}" no curso "{1}" um novo documento "{2}" foi enviado por "{3}". open.group=Abrir grupo pane.tab.accessibility=Acesso pane.tab.assignment=Atribui\u00E7\u00E3o pane.tab.grading=Classifica\u00E7\u00E3o pane.tab.highscore=Pontua\u00E7\u00E3o Alta (HighScore) +pane.tab.review=Revis\u00F5es e feedback pane.tab.solutions=Solu\u00E7\u00F5es de amostra pane.tab.submission=Apresenta\u00E7\u00E3o pane.tab.workflow=Workflow +participant.confirm.reset.task.nok=N\u00E3o, eu mantenho a tarefa +participant.confirm.reset.task.ok=Sim, a tarefa pode ser redefinida +participant.confirm.reset.task.text=Voc\u00EA est\u00E1 autorizado por {0} para redefinir seu "{1}". Todos os documentos que voc\u00EA j\u00E1 baixou ser\u00E3o exclu\u00EDdos. +participant.confirm.reset.task.title=Resetar +participant.reset.button=Resetar tarefa passed.false=$org.olat.course.assessment\:passed.false passed.true=$org.olat.course.assessment\:passed.true preview=$org.olat.course.nodes.ta\:form.task.preview @@ -168,6 +202,7 @@ review.and.correction=Retorno e Feedback review.enabled=Ativar op\u00E7\u00E3o de retorno para revis\u00F5es e feedback revision.enabled=Ativar caixa suspensa para revis\u00F5es por parte dos participantes, pode ser definido pelo treinador. revision.period=Fase de revis\u00E3o +revisions.duedate=Revis\u00E3o at\u00E9... run.assignment.due.date=Data de vencimento\: {0} run.assignment.title=Atribui\u00E7\u00E3o de tarefas run.coach=Correto @@ -185,6 +220,7 @@ run.review.waiting=Seu treinador est\u00E1 revendo o trabalho apresentado. Voc\u run.revised.description=Os seguintes documentos revistos foram apresentados por voc\u00EA\: run.revised.nofiles=A revis\u00E3o foi apresentada sem documentos run.revision=Fase de revis\u00E3o +run.revision.due.date=Prazo para revis\u00E3o\: {0} run.revision.period.description=$\:run.corrections.rejected Criar ou fazer upload de um documento revisado. run.run=Tarefa run.solution=solu\u00E7\u00E3o de amostra @@ -210,11 +246,13 @@ run.submitted.nofiles=A apresenta\u00E7\u00E3o foi feita sem documentos sample.solution=Solu\u00E7\u00E3o de amostra sample.solution.enabled=Forne\u00E7a amostra de solu\u00E7\u00F5es para os participantes sample.solution.visible.after=Vis\u00EDvel ap\u00F3s... +sample.solution.visible.all=Amostra de solu\u00E7\u00F5es vis\u00EDveis para todos ap\u00F3s a data, inclusive para quem n\u00E3o enviou a tarefa. sampling=Tipo de amostragem sampling.reuse=Sua tarefa ser\u00E1 atribu\u00EDda a mais de um usu\u00E1rio / grupo sampling.unique=Sua tarefa ser\u00E1 atribu\u00EDda a apenas um \u00FAnico usu\u00E1rio / grupo save.done=Salvar como conclu\u00EDdo selected.group=O grupo para esta tarefa \u00E9\: <i class\="o_icon o_icon_group"> </i> "{0}" +solution.duedate=Solu\u00E7\u00E3o at\u00E9... solution.file=Arquivo solution.list.description=Selecione "$\:add.solution" ou "$\:create.solution" para adicionar uma solu\u00E7\u00E3o ou "$\:replace" ou "$org.olat.core\:edit" para modificar uma solu\u00E7\u00E3o existente. Por favor, note que as solu\u00E7\u00F5es n\u00E3o s\u00E3o atribu\u00EDdos a uma determinada tarefa. solution.list.title=Envie as solu\u00E7\u00F5es de amostra @@ -222,6 +260,7 @@ solution.title=T\u00EDtulo submission=Apresenta\u00E7\u00E3o submission.add.title=Adicionar documento submission.confirmation=A apresenta\u00E7\u00E3o do arquivo "$filename" por $first $last ($email) em $date foi confirmada. +submission.duedate=$\:submit.deadline submission.email.confirmation=Envie texto, adicionalmente, como e-mail submission.enabled=Ativar menu suspenso de solu\u00E7\u00F5es para os participantes submission.mail.subject=Confirma\u00E7\u00E3o-E-Mail-OpenOLAT @@ -235,12 +274,14 @@ submit.submit.title=Passo 2\: Submeter documentos table.header.author=Autor table.header.comment=Comente table.header.details.gta=$org.olat.course.nodes.ta\:table.header.details.ta +table.header.duedates=Prazos table.header.edit=A\u00E7\u00E3o table.header.group.name=Grupo table.header.group.step=Passo table.header.group.taskName=Tarefa table.header.passed=Passou table.header.score=Pontos +table.header.submissionDate=Data para envio table.header.uploaded.by=Enviado por {0} task.alreadyChosen=$org.olat.course.nodes.ta\:task.chosen task.assigned.description=A tarefa seguinte foi atribu\u00EDda a voc\u00EA\: diff --git a/src/main/java/org/olat/course/nodes/gta/ui/DescriptionWithTooltipCellRenderer.java b/src/main/java/org/olat/course/nodes/gta/ui/component/DescriptionWithTooltipCellRenderer.java similarity index 98% rename from src/main/java/org/olat/course/nodes/gta/ui/DescriptionWithTooltipCellRenderer.java rename to src/main/java/org/olat/course/nodes/gta/ui/component/DescriptionWithTooltipCellRenderer.java index 449b82bae4cfd68aa7bb10eebd91d230a0713f35..b7629fbbcbd1319d7d4b5d34396fa9f3a721ceef 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/DescriptionWithTooltipCellRenderer.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/component/DescriptionWithTooltipCellRenderer.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.course.nodes.gta.ui; +package org.olat.course.nodes.gta.ui.component; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/org/olat/course/nodes/gta/ui/component/DownloadDocumentMapper.java b/src/main/java/org/olat/course/nodes/gta/ui/component/DownloadDocumentMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..40a472e86c3dc3c683a0dbdb08f212c8dcda5bca --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/component/DownloadDocumentMapper.java @@ -0,0 +1,56 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.ui.component; + +import java.io.File; + +import javax.servlet.http.HttpServletRequest; + +import org.olat.core.dispatcher.mapper.Mapper; +import org.olat.core.gui.media.FileMediaResource; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.gui.media.NotFoundMediaResource; + +/** + * + * Initial date: 9 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class DownloadDocumentMapper implements Mapper { + + private final File documentDir; + + public DownloadDocumentMapper(File documentDir) { + this.documentDir = documentDir; + } + + @Override + public MediaResource handle(String relPath, HttpServletRequest request) { + if(relPath != null && relPath.startsWith("/")) { + relPath = relPath.substring(1, relPath.length()); + } + File document = new File(documentDir, relPath); + if(document.exists() && document.getParentFile().equals(documentDir)) { + return new FileMediaResource(document, true); + } + return new NotFoundMediaResource(relPath); + } +} diff --git a/src/main/java/org/olat/course/nodes/gta/ui/PassedCellRenderer.java b/src/main/java/org/olat/course/nodes/gta/ui/component/PassedCellRenderer.java similarity index 97% rename from src/main/java/org/olat/course/nodes/gta/ui/PassedCellRenderer.java rename to src/main/java/org/olat/course/nodes/gta/ui/component/PassedCellRenderer.java index 53af0b7623c416e7d24a87f029ac3ca85e2c5016..d4fcd6ea84472ae012efd483051e43abbc438e87 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/PassedCellRenderer.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/component/PassedCellRenderer.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.course.nodes.gta.ui; +package org.olat.course.nodes.gta.ui.component; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; diff --git a/src/main/java/org/olat/course/nodes/gta/ui/component/SubmissionDateCellRenderer.java b/src/main/java/org/olat/course/nodes/gta/ui/component/SubmissionDateCellRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..4fa9042b5ffd02fafeb404a722c657ac68f67e43 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/component/SubmissionDateCellRenderer.java @@ -0,0 +1,83 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.gta.ui.component; + +import java.util.Date; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.core.util.Formatter; +import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.ui.CoachedElementRow; + +/** + * + * Initial date: 3 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class SubmissionDateCellRenderer implements FlexiCellRenderer { + + private final Formatter formatter; + private final Translator translator; + + public SubmissionDateCellRenderer(Translator translator) { + this.translator = translator; + formatter = Formatter.getInstance(translator.getLocale()); + } + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, + URLBuilder ubu, Translator trans) { + + Object object = source.getFlexiTableElement().getTableDataModel().getObject(row); + if(object instanceof CoachedElementRow) { + CoachedElementRow ciRow = (CoachedElementRow)object; + TaskProcess status = ciRow.getTaskStatus(); + if(status == null || status == TaskProcess.assignment || status == TaskProcess.submit) { + //do nothing + } else { + Date date = ciRow.getSyntheticSubmissionDate(); + if(date != null) { + if(ciRow.getHasSubmittedDocuments()) { + target.append(formatter.formatDate(date)); + } else { + target.append(translator.translate("no.submission")); + } + } + } + } + } + + public static Date cascading(CoachedElementRow ciRow) { + Date date = ciRow.getSubmissionDate(); + if(date == null || (ciRow.getSubmissionRevisionsDate() != null && ciRow.getSubmissionRevisionsDate().after(date))) { + date = ciRow.getSubmissionRevisionsDate(); + } + if(date == null || (ciRow.getCollectionDate() != null && ciRow.getCollectionDate().after(date))) { + date = ciRow.getCollectionDate(); + } + return date; + } +} diff --git a/src/main/java/org/olat/course/nodes/gta/ui/TaskStatusCellRenderer.java b/src/main/java/org/olat/course/nodes/gta/ui/component/TaskStatusCellRenderer.java similarity index 98% rename from src/main/java/org/olat/course/nodes/gta/ui/TaskStatusCellRenderer.java rename to src/main/java/org/olat/course/nodes/gta/ui/component/TaskStatusCellRenderer.java index d3b9da6e2a8bee28b9b446a1ee23ac91cc6b03f7..1cb297a55809245d495efb017d8e5a5caaf539bc 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/TaskStatusCellRenderer.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/component/TaskStatusCellRenderer.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.course.nodes.gta.ui; +package org.olat.course.nodes.gta.ui.component; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; diff --git a/src/main/java/org/olat/course/nodes/info/InfoPeekViewController.java b/src/main/java/org/olat/course/nodes/info/InfoPeekViewController.java index 8e25a60a2773be2ad6e49889a99324f0767c2835..225d0551255f4558e53fa43c0e00ccc589ad14ee 100644 --- a/src/main/java/org/olat/course/nodes/info/InfoPeekViewController.java +++ b/src/main/java/org/olat/course/nodes/info/InfoPeekViewController.java @@ -25,9 +25,8 @@ import java.util.List; import java.util.Locale; import org.apache.commons.lang.StringEscapeUtils; -import org.olat.commons.info.manager.InfoMessageFrontendManager; -import org.olat.commons.info.model.InfoMessage; -import org.olat.core.CoreSpringFactory; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.table.BaseTableDataModelWithoutFilter; @@ -51,6 +50,7 @@ import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseModule; import org.olat.course.nodes.InfoCourseNode; import org.olat.course.run.userview.UserCourseEnvironment; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -67,6 +67,9 @@ public class InfoPeekViewController extends BasicController { private final InfoCourseNode courseNode; private TableController tableController; + + @Autowired + private InfoMessageFrontendManager infoService; public InfoPeekViewController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, InfoCourseNode courseNode) { @@ -96,8 +99,7 @@ public class InfoPeekViewController extends BasicController { tableController.addColumnDescriptor(new CustomRenderColumnDescriptor("peekview.title", 0, null, ureq.getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new InfoNodeRenderer())); - String resSubPath = this.courseNode.getIdent(); - InfoMessageFrontendManager infoService = CoreSpringFactory.getImpl(InfoMessageFrontendManager.class); + String resSubPath = courseNode.getIdent(); List<InfoMessage> infos = infoService.loadInfoMessageByResource(ores, resSubPath, null, null, null, 0, 5); InfosTableModel model = new InfosTableModel(infos); diff --git a/src/main/java/org/olat/course/nodes/info/InfoRunController.java b/src/main/java/org/olat/course/nodes/info/InfoRunController.java index 89278a096a943f5bebb27fcde164049a837cd40d..ad828dd2404132438ea45e8b63630dddadc4637c 100644 --- a/src/main/java/org/olat/course/nodes/info/InfoRunController.java +++ b/src/main/java/org/olat/course/nodes/info/InfoRunController.java @@ -24,16 +24,15 @@ import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; -import org.olat.commons.info.manager.InfoMessageFrontendManager; +import org.olat.basesecurity.GroupRoles; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoSubscriptionManager; import org.olat.commons.info.manager.MailFormatter; -import org.olat.commons.info.model.InfoMessage; import org.olat.commons.info.notification.InfoSubscription; -import org.olat.commons.info.notification.InfoSubscriptionManager; import org.olat.commons.info.ui.InfoDisplayController; import org.olat.commons.info.ui.InfoSecurityCallback; import org.olat.commons.info.ui.SendInfoMailFormatter; import org.olat.commons.info.ui.SendSubscriberMailOption; -import org.olat.core.CoreSpringFactory; import org.olat.core.commons.services.notifications.PublisherData; import org.olat.core.commons.services.notifications.SubscriptionContext; import org.olat.core.commons.services.notifications.ui.ContextualSubscriptionController; @@ -56,10 +55,9 @@ import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.nodes.InfoCourseNode; import org.olat.course.run.userview.NodeEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; -import org.olat.group.BusinessGroupService; import org.olat.modules.ModuleConfiguration; import org.olat.repository.RepositoryManager; -import org.olat.repository.RepositoryService; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -77,27 +75,28 @@ public class InfoRunController extends BasicController { private ContextualSubscriptionController subscriptionController; private final String businessPath; - private final InfoCourseNode courseNode; - private final ModuleConfiguration config; + + @Autowired + private RepositoryManager repositoryManager; + @Autowired private InfoSubscriptionManager subscriptionManager; public InfoRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, NodeEvaluation ne, InfoCourseNode courseNode) { super(ureq, wControl); - - this.courseNode = courseNode; - this.config = courseNode.getModuleConfiguration(); + ModuleConfiguration config = courseNode.getModuleConfiguration(); Long resId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); - ICourse course = CourseFactory.loadCourse(resId); - String resSubPath = this.courseNode.getIdent(); + + String resSubPath = courseNode.getIdent(); OLATResourceable infoResourceable = new InfoOLATResourceable(resId); businessPath = normalizeBusinessPath(wControl.getBusinessControl().getAsString()); + ICourse course = CourseFactory.loadCourse(resId); + CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager(); //manage opt-out subscription UserSession usess = ureq.getUserSession(); if(!usess.getRoles().isGuestOnly()) { - subscriptionManager = InfoSubscriptionManager.getInstance(); SubscriptionContext subContext = subscriptionManager.getInfoSubscriptionContext(infoResourceable, resSubPath); PublisherData pdata = subscriptionManager.getInfoPublisherData(infoResourceable, businessPath); if(InfoCourseNodeEditController.getAutoSubscribe(config)) { @@ -116,28 +115,23 @@ public class InfoRunController extends BasicController { } else { Identity identity = getIdentity(); Roles roles = usess.getRoles(); - CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager(); - boolean institutionalManager = RepositoryManager.getInstance().isInstitutionalRessourceManagerFor(identity, roles, cgm.getCourseEntry()); - boolean courseAdmin = cgm.isIdentityCourseAdministrator(identity); - - canAdd = courseAdmin - || ne.isCapabilityAccessible(InfoCourseNode.EDIT_CONDITION_ID) - || institutionalManager - || roles.isOLATAdmin(); - canAdmin = courseAdmin - || ne.isCapabilityAccessible(InfoCourseNode.ADMIN_CONDITION_ID) - || institutionalManager - || roles.isOLATAdmin(); + boolean isAdmin = roles.isOLATAdmin() + || cgm.isIdentityCourseAdministrator(identity) + || repositoryManager.isInstitutionalRessourceManagerFor(identity, roles, cgm.getCourseEntry()); + + canAdd = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.EDIT_CONDITION_ID); + canAdmin = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.ADMIN_CONDITION_ID); } InfoSecurityCallback secCallback = new InfoCourseSecurityCallback(getIdentity(), canAdd, canAdmin); - RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class); infoDisplayController = new InfoDisplayController(ureq, wControl, config, secCallback, infoResourceable, resSubPath, businessPath); - infoDisplayController.addSendMailOptions(new SendSubscriberMailOption(infoResourceable, resSubPath, CoreSpringFactory.getImpl(InfoMessageFrontendManager.class))); - infoDisplayController.addSendMailOptions(new SendMembersMailOption(course.getCourseEnvironment().getCourseGroupManager().getCourseResource(), - RepositoryManager.getInstance(), repositoryService, CoreSpringFactory.getImpl(BusinessGroupService.class))); + infoDisplayController.addSendMailOptions(new SendSubscriberMailOption(infoResourceable, resSubPath, getLocale())); + infoDisplayController.addSendMailOptions(new SendMembersMailOption(cgm.getCourseEntry(), GroupRoles.owner, translate("wizard.step1.send_option.owner"))); + infoDisplayController.addSendMailOptions(new SendMembersMailOption(cgm.getCourseEntry(), GroupRoles.coach, translate("wizard.step1.send_option.coach"))); + infoDisplayController.addSendMailOptions(new SendMembersMailOption(cgm.getCourseEntry(), GroupRoles.participant, translate("wizard.step1.send_option.participant"))); + MailFormatter mailFormatter = new SendInfoMailFormatter(course.getCourseTitle(), businessPath, getTranslator()); infoDisplayController.setSendMailFormatter(mailFormatter); listenTo(infoDisplayController); diff --git a/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java b/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java index 68045c2f53d283d06fe2772aa1bdf4732719e570..1133893d1216a5de7c9b547812e6b91857dc893a 100644 --- a/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java +++ b/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java @@ -23,19 +23,15 @@ package org.olat.course.nodes.info; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Set; import org.olat.basesecurity.GroupRoles; import org.olat.commons.info.ui.SendMailOption; -import org.olat.core.gui.translator.Translator; +import org.olat.core.CoreSpringFactory; import org.olat.core.id.Identity; -import org.olat.core.util.Util; import org.olat.group.BusinessGroupService; import org.olat.repository.RepositoryEntry; -import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryService; -import org.olat.resource.OLATResource; /** * @@ -48,38 +44,38 @@ import org.olat.resource.OLATResource; */ public class SendMembersMailOption implements SendMailOption { - private final OLATResource courseResource; - private final RepositoryManager rm; - private final RepositoryService repositoryService; - private final BusinessGroupService businessGroupService; + private final String label; + private final GroupRoles role; + private final RepositoryEntry repositoryEntry; - public SendMembersMailOption(OLATResource courseResource, RepositoryManager rm, RepositoryService repositoryService, BusinessGroupService businessGroupService) { - this.courseResource = courseResource; - this.rm = rm; - this.repositoryService = repositoryService; - this.businessGroupService = businessGroupService; + public SendMembersMailOption(RepositoryEntry repositoryEntry, GroupRoles role, String label) { + this.role = role; + this.label = label; + this.repositoryEntry = repositoryEntry; } @Override public String getOptionKey() { - return "send-mail-course-members"; + return "send-mail-course-members-" + role.name(); } @Override - public String getOptionTranslatedName(Locale locale) { - Translator translator = Util.createPackageTranslator(SendMembersMailOption.class, locale); - return translator.translate("wizard.step1.send_option.member"); + public String getOptionName() { + return label; } @Override public List<Identity> getSelectedIdentities() { - RepositoryEntry repositoryEntry = rm.lookupRepositoryEntry(courseResource, true); + Set<Identity> identities = new HashSet<Identity>(); + if(role == GroupRoles.coach || role == GroupRoles.participant) { + List<Identity> members = CoreSpringFactory.getImpl(BusinessGroupService.class) + .getMembersOf(repositoryEntry, role == GroupRoles.coach, role == GroupRoles.participant); + identities.addAll(members); + } - List<Identity> members = businessGroupService.getMembersOf(repositoryEntry, true, true); - Set<Identity> identities = new HashSet<Identity>(members); - List<Identity> reMembers = repositoryService.getMembers(repositoryEntry, GroupRoles.participant.name(), GroupRoles.coach.name(), GroupRoles.owner.name()); + List<Identity> reMembers = CoreSpringFactory.getImpl(RepositoryService.class) + .getMembers(repositoryEntry, role.name()); identities.addAll(reMembers); - - return new ArrayList<Identity>(identities); + return new ArrayList<>(identities); } } diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_de.properties index 365c9347c77bcd5329e6d5f615332354bf53100c..43042c7409ca225ebaf1219bad14c6e3b4a13cff 100644 --- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_de.properties @@ -20,7 +20,9 @@ pane.tab.infos_config.auto_subscribe.on=Diese Mitteilungen bei Ansicht automatis peekview.title=Title peekview.more=mehr... peekview.noInfos=Keine Mitteilungen -wizard.step1.send_option.member=Mitglieder, Gruppenbetreuer und Kursbesitzer +wizard.step1.send_option.participant=Teilnehmer +wizard.step1.send_option.coach=Betreuer +wizard.step1.send_option.owner=Kursbesitzer diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_en.properties index 2a82e9884e32bc9c63e5a5635d99dbc04099f79a..617278a2e9a491ca9ddf4cb6555536b439649d61 100644 --- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_en.properties @@ -20,4 +20,6 @@ peekview.more=more... peekview.noInfos=No notifications peekview.title=Title title_info=Notifications -wizard.step1.send_option.member=Members, group tutors, and course owners +wizard.step1.send_option.participant=Participants +wizard.step1.send_option.coach=Tutors +wizard.step1.send_option.owner=Course owners diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_fr.properties index 0999a110d4980681d8d3366f95f271c14183ad93..47f5cb49fca24e507ec54a9fb127d2a3c2016670 100644 --- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_fr.properties @@ -20,4 +20,6 @@ peekview.more=plus... peekview.noInfos=Aucune communication peekview.title=Titre title_info=Communications -wizard.step1.send_option.member=Membres, tuteurs de groupes et propri\u00E9taires de cours +wizard.step1.send_option.participant=Participants +wizard.step1.send_option.coach=Tuteurs +wizard.step1.send_option.owner=Propri\u00E9taires de cours diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_it.properties index cf86794682dea3e1dcd549ff62c5cd723d409a36..1f0a8ae15c3e2520bf5516519f81294c767c1b35 100644 --- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_it.properties @@ -20,4 +20,4 @@ peekview.more=di pi\u00F9... peekview.noInfos=Nessuna comunicazione peekview.title=Titolo title_info=Comunicazioni -wizard.step1.send_option.member=Membri, tutori di gruppi e proprietari di corsi + diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_jp.properties index 115c432b64f22c83af86d76b6c4d9122b31434c3..02da21e410a1619a926f07db444436cdeb133338 100644 --- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_jp.properties +++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_jp.properties @@ -19,5 +19,4 @@ pane.tab.infos_config.title=$\:pane.tab.infos_config peekview.more=\u3055\u3089\u306B ... peekview.noInfos=\u901A\u77E5\u306A\u3057 peekview.title=\u30BF\u30A4\u30C8\u30EB -title_info=\u901A\u77E5 -wizard.step1.send_option.member=\u30E1\u30F3\u30D0\u30FC\u3001\u30B0\u30EB\u30FC\u30D7\u30C1\u30E5\u30FC\u30BF\u30FC\u304A\u3088\u3073\u30B3\u30FC\u30B9\u30AA\u30FC\u30CA\u30FC +title_info=\u901A\u77E5 \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_nl_NL.properties index 7e00f0cb026cd9f46defa203e9384e1d3cf53316..3514fd80bb9f2a798536ce879c9d03e893d61319 100644 --- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_nl_NL.properties +++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_nl_NL.properties @@ -19,5 +19,4 @@ pane.tab.infos_config.title=$\:pane.tab.infos_config peekview.more=meer... peekview.noInfos=Geen mededelingen peekview.title=Titel -title_info=Mededelingen -wizard.step1.send_option.member=Leden, groepsdocenten en cursuseigenaars +title_info=Mededelingen \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pl.properties index 4c8bd95655a6a6ba091d83a2bcf00b9d54716c94..0b270d1fac9ebc3bffb95eca6a70d1383666b8e3 100644 --- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pl.properties @@ -19,5 +19,4 @@ pane.tab.infos_config.title=$\:pane.tab.infos_config peekview.more=wi\u0119cej... peekview.noInfos=Brak powiadomie\u0144 peekview.title=Tytu\u0142 -title_info=Powiadomienia -wizard.step1.send_option.member=Cz\u0142onkowie, nauczyciele w grupach i w\u0142a\u015Bciciele kurs\u00F3w +title_info=Powiadomienia \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pt_BR.properties index b93a116462418a04995de942bf6ab0f07d0ab2a8..b294787ceb39958559120bd243910369649bca5f 100644 --- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pt_BR.properties @@ -1,11 +1,11 @@ -#Thu Sep 08 16:42:37 CEST 2011 +#Tue Sep 05 23:25:46 CEST 2017 auto_subscribe=Inscrever-se automaticamente condition.accessibility.title=Ler notifica\u00E7\u00F5es condition.admin.title=Gerenciar as notifica\u00E7\u00F5es condition.editable.title=Criar notifica\u00E7\u00F5es -mail.body.title=Notifica\u00E7\u00E3o do curso {0} mail.body.from=Escrito por {0} em {1} mail.body.more=Informa\u00E7\u00F5es adicionais +mail.body.title=Notifica\u00E7\u00E3o do curso {0} pane.tab.accessibility=Acesso pane.tab.infos_config=Configura\u00E7\u00E3o de notifica\u00E7\u00E3o pane.tab.infos_config.all=Tudo @@ -20,4 +20,6 @@ peekview.more=mais... peekview.noInfos=Sem notifica\u00E7\u00F5es peekview.title=T\u00EDtulo title_info=Notifica\u00E7\u00F5es -wizard.step1.send_option.member=Membros, tutores de grupo, e os propriet\u00E1rios de curso +wizard.step1.send_option.coach=Tutores +wizard.step1.send_option.owner=Propriet\u00E1rios +wizard.step1.send_option.participant=Participantes diff --git a/src/main/java/org/olat/course/nodes/iq/IQPreviewController.java b/src/main/java/org/olat/course/nodes/iq/IQPreviewController.java index cc285dbc592c2ae88c9cd222d2c92104f111d666..b451ca60f6ce4c30e974be94e1c82360ad2a5667 100644 --- a/src/main/java/org/olat/course/nodes/iq/IQPreviewController.java +++ b/src/main/java/org/olat/course/nodes/iq/IQPreviewController.java @@ -34,6 +34,7 @@ import org.olat.core.gui.control.controller.BasicController; import org.olat.course.nodes.IQTESTCourseNode; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.assessment.Role; /** * Description: <br> @@ -79,7 +80,7 @@ public class IQPreviewController extends BasicController { boolean passed = score >= (cutValue == null ? 0 : cutValue.floatValue()); ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), new Boolean(passed)); boolean incrementUserAttempts = true; - cn.updateUserScoreEvaluation(sceval, userCourseEnv, ureq.getIdentity(), incrementUserAttempts); + cn.updateUserScoreEvaluation(sceval, userCourseEnv, ureq.getIdentity(), incrementUserAttempts, Role.user); getWindowControl().setInfo(translate("preview.points.set")); } } diff --git a/src/main/java/org/olat/course/nodes/iq/IQRunController.java b/src/main/java/org/olat/course/nodes/iq/IQRunController.java index 6182d38a1c2900f60a3b9c5a552590f618293e00..5326b3bb09bc89ee98c0d3c112ede2f9b2860c8b 100644 --- a/src/main/java/org/olat/course/nodes/iq/IQRunController.java +++ b/src/main/java/org/olat/course/nodes/iq/IQRunController.java @@ -92,6 +92,7 @@ import org.olat.ims.qti.process.ImsRepositoryResolver; import org.olat.instantMessaging.InstantMessagingService; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.modules.iq.IQDisplayController; import org.olat.modules.iq.IQManager; @@ -483,7 +484,16 @@ public class IQRunController extends BasicController implements GenericEventList Document doc = iqManager.getResultsReportingFromFile(ureq.getIdentity(), type, assessmentID); //StringBuilder resultsHTML = LocalizedXSLTransformer.getInstance(ureq.getLocale()).renderResults(doc); String summaryConfig = (String)modConfig.get(IQEditController.CONFIG_KEY_SUMMARY); - int summaryType = AssessmentInstance.getSummaryType(summaryConfig); + int summaryType = AssessmentInstance.SUMMARY_NONE; + try { + summaryType = AssessmentInstance.getSummaryType(summaryConfig); + } catch (Exception e) { + // cannot change AssessmentInstance: fallback if the the configuration is inherited from a QTI 2.1 configuration + if(StringHelper.containsNonWhitespace(summaryConfig)) { + summaryType = AssessmentInstance.SUMMARY_DETAILED; + } + logError("", e); + } String resultsHTML = iqManager.transformResultsReporting(doc, ureq.getLocale(), summaryType); myContent.contextPut("displayreporting", resultsHTML); myContent.contextPut("resreporting", resultsHTML); @@ -518,7 +528,7 @@ public class IQRunController extends BasicController implements GenericEventList ScoreEvaluation sceval = new ScoreEvaluation(ac.getScore(), ac.isPassed(), assessmentStatus, userVisibility, fullyAssed, ai.getAssessID()); AssessableCourseNode acn = (AssessableCourseNode)courseNode; // assessment nodes are assessable - acn.updateUserScoreEvaluation(sceval, userCourseEnv, getIdentity(), true); + acn.updateUserScoreEvaluation(sceval, userCourseEnv, getIdentity(), true, Role.user); // Mark publisher for notifications Long courseId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); @@ -534,10 +544,10 @@ public class IQRunController extends BasicController implements GenericEventList // although this is not an assessable node we still use the assessment // manager since this one uses caching AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager(); - am.incrementNodeAttempts(courseNode, getIdentity(), userCourseEnv); + am.incrementNodeAttempts(courseNode, getIdentity(), userCourseEnv, Role.user); } else if(type.equals(AssessmentInstance.QMD_ENTRY_TYPE_SELF)){ AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager(); - am.incrementNodeAttempts(courseNode, getIdentity(), userCourseEnv); + am.incrementNodeAttempts(courseNode, getIdentity(), userCourseEnv, Role.user); } } diff --git a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java index fc5be993b87b5984dd89db682d7f3dc3040bc35c..9e7538794fc1c06e23c0dc52c059b590859c6d14 100644 --- a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java +++ b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java @@ -89,6 +89,7 @@ import org.olat.ims.qti21.ui.ResourcesMapper; import org.olat.instantMessaging.InstantMessagingService; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.repository.RepositoryEntry; import org.olat.user.UserManager; @@ -570,8 +571,11 @@ public class QTI21AssessmentRunController extends BasicController implements Gen displayCtrl = new AssessmentTestDisplayController(ureq, bwControl, this, testEntry, courseRe, courseNode.getIdent(), deliveryOptions, overrideOptions, true, false, false); listenTo(displayCtrl); - if(displayCtrl.isTerminated()) { - //do nothing + if(displayCtrl.isEnded()) { + if(!displayCtrl.isResultsVisible()) { + doExitAssessment(ureq, null, true); + initAssessment(ureq); + } } else { // in case displayController was unable to initialize, a message was set by displayController // this is the case if no more attempts or security check was unsuccessfull @@ -638,7 +642,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen /** * Remove the runtime from the GUI stack only. * @param ureq - * @param event + * @param event The event which triggered the method (optional) * @param testEnded true if the test was ended and not suspended or cancelled (use to control increment of attempts) */ private void doExitAssessment(UserRequest ureq, Event event, boolean testEnded) { @@ -662,7 +666,9 @@ public class QTI21AssessmentRunController extends BasicController implements Gen incrementAttempts.set(true); } - fireEvent(ureq, event); + if(event != null) { + fireEvent(ureq, event); + } } @Override @@ -722,7 +728,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen ScoreEvaluation sceval = new ScoreEvaluation(score, pass, assessmentStatus, visibility, Boolean.TRUE, assessmentId); boolean increment = incrementAttempts.getAndSet(false); - ((IQTESTCourseNode)courseNode).updateUserScoreEvaluation(sceval, userCourseEnv, getIdentity(), increment); + ((IQTESTCourseNode)courseNode).updateUserScoreEvaluation(sceval, userCourseEnv, getIdentity(), increment, Role.user); if(increment) { ThreadLocalUserActivityLogger.log(QTI21LoggingAction.QTI_CLOSE_IN_COURSE, getClass()); } @@ -731,7 +737,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen } else if(courseNode instanceof SelfAssessableCourseNode) { boolean increment = incrementAttempts.getAndSet(false); if(increment) { - ((SelfAssessableCourseNode)courseNode).incrementUserAttempts(userCourseEnv); + ((SelfAssessableCourseNode)courseNode).incrementUserAttempts(userCourseEnv, Role.user); } } } diff --git a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_fr.properties index 0f71128e4453845676bfdf8895279f2815d978e8..2fbccdc6e2b99ac6befd4f90b57823c787695460 100644 --- a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Thu Jun 08 21:31:30 CEST 2017 +#Thu Jul 06 20:47:43 CEST 2017 Intro.self=Pressez sur D\u00E9marrer pour commencer l'auto-test. Intro.surv=Pressez sur D\u00E9marrer pour commencer avec le questionnaire. Intro.test=Pressez sur D\u00E9marrer pour commencer le test. @@ -122,6 +122,7 @@ qti.form.showfeedbacks=Montrer le feedback qti.form.summary=Aper\u00E7u r\u00E9sultats qti.form.summary.compact=Compact (sans solutions) qti.form.summary.detailed=D\u00E9taill\u00E9 (avec solutions) +qti.form.summary.help=L'option permet de choisir le niveau de d\u00E9tails du rapport des r\u00E9sultats du test. qti.form.summary.metadata=R\u00E9sum\u00E9 du test qti.form.summary.none=Aucune entr\u00E9e n\u00E9cessaire qti.form.summary.questions=Question, sans r\u00E9ponse diff --git a/src/main/java/org/olat/course/nodes/members/MembersConfigForm.java b/src/main/java/org/olat/course/nodes/members/MembersConfigForm.java index a55b3d082eba6267bac9620b08f9874e926057db..142eaee0abde15553c7b099a40df3c61158dc4f0 100755 --- a/src/main/java/org/olat/course/nodes/members/MembersConfigForm.java +++ b/src/main/java/org/olat/course/nodes/members/MembersConfigForm.java @@ -25,20 +25,14 @@ import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; -import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; -import org.olat.core.gui.components.form.flexible.impl.IFormFragmentController; -import org.olat.core.gui.components.form.flexible.impl.IFormFragmentHost; import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit; 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.translator.Translator; -import org.olat.core.util.Util; -import org.olat.course.editor.formfragments.MembersSelectorFormFragment; import org.olat.course.nodes.MembersCourseNode; +import org.olat.course.nodes.members.ui.group.MembersSelectorFormFragment; import org.olat.course.run.userview.UserCourseEnvironment; -import org.olat.modules.IModuleConfiguration; import org.olat.modules.ModuleConfiguration; /** @@ -49,20 +43,17 @@ import org.olat.modules.ModuleConfiguration; * * @autohr dfurrer, dirk.furrer@frentix.com, http://www.frentix.com */ -public class MembersConfigForm extends FormBasicController { +public class MembersConfigForm extends MembersSelectorFormFragment { private static final String[] onKeys = new String[] { "on" }; private static final String[] onValues = new String[] { "" }; private static final String[] emailFctKeys = new String[]{ MembersCourseNode.EMAIL_FUNCTION_ALL, MembersCourseNode.EMAIL_FUNCTION_COACH_ADMIN }; - private final ModuleConfiguration config; private MultipleSelectionElement showOwners; private SingleSelection emailFunctionEl; private SingleSelection downloadFunctionEl; - private final MembersSelectorFormFragment membersFragment; - - private FormSubmit subm; + private FormSubmit submitButton; /** * Form constructor @@ -74,48 +65,93 @@ public class MembersConfigForm extends FormBasicController { * @param withCancel * true: cancel button is rendered, false: no cancel button */ - protected MembersConfigForm(UserRequest ureq, WindowControl wControl, UserCourseEnvironment euce, - ModuleConfiguration config) { - super(ureq, wControl); - this.config = config; - membersFragment = new MembersSelectorFormFragment(euce.getCourseEditorEnv()); - registerFormFragment(membersFragment); // register with parent for proper lifecycle handling - initForm(ureq); - validateFormLogic(ureq); + protected MembersConfigForm(UserRequest ureq, WindowControl wControl, + UserCourseEnvironment euce, ModuleConfiguration config) { + super(ureq, wControl, euce.getCourseEditorEnv(), config); } @Override - public void storeFormData(UserRequest ureq) { - config.setBooleanEntry(MembersCourseNode.CONFIG_KEY_SHOWOWNER, showOwners.isSelected(0)); - membersFragment.storeConfiguration(ureq, IModuleConfiguration.fragment("members", config)); + protected String getConfigKeyCoachesGroup() { + return MembersCourseNode.CONFIG_KEY_COACHES_GROUP; + } + + @Override + protected String getConfigKeyCoachesArea() { + return MembersCourseNode.CONFIG_KEY_COACHES_AREA; + } + + @Override + protected String getConfigKeyCoachesGroupIds() { + return MembersCourseNode.CONFIG_KEY_COACHES_GROUP_ID; } @Override - protected boolean validateFormLogic(UserRequest ureq) { - boolean isOK = true; + protected String getConfigKeyCoachesAreaIds() { + return MembersCourseNode.CONFIG_KEY_COACHES_AREA_IDS; + } - return isOK - & membersFragment.validateFormLogic(ureq) - & super.validateFormLogic(ureq); + @Override + protected String getConfigKeyCoachesCourse() { + return MembersCourseNode.CONFIG_KEY_COACHES_COURSE; + } + + @Override + protected String getConfigKeyCoachesAll() { + return MembersCourseNode.CONFIG_KEY_COACHES_ALL; + } + + @Override + protected String getConfigKeyParticipantsGroup() { + return MembersCourseNode.CONFIG_KEY_PARTICIPANTS_GROUP; } + @Override + protected String getConfigKeyParticipantsArea() { + return MembersCourseNode.CONFIG_KEY_PARTICIPANTS_AREA; + } + + @Override + protected String getConfigKeyParticipantsGroupIds() { + return MembersCourseNode.CONFIG_KEY_PARTICIPANTS_GROUP_ID; + } + + @Override + protected String getConfigKeyParticipantsAreaIds() { + return MembersCourseNode.CONFIG_KEY_PARTICIPANTS_AREA_ID; + } + + @Override + protected String getConfigKeyParticipantsCourse() { + return MembersCourseNode.CONFIG_KEY_PARTICIPANTS_COURSE; + } + + @Override + protected String getConfigKeyParticipantsAll() { + return MembersCourseNode.CONFIG_KEY_PARTICIPANTS_ALL; + } + + @Override + public void storeConfiguration(ModuleConfiguration config) { + config.setBooleanEntry(MembersCourseNode.CONFIG_KEY_SHOWOWNER, showOwners.isSelected(0)); + super.storeConfiguration(config); + } + @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { // set Formtitle and infobar setFormTitle("pane.tab.membersconfig"); setFormInfo("members.info"); setFormContextHelp("Communication and Collaboration#_teilnehmerliste"); + formLayout.setElementCssClass("o_sel_cmembers_settings"); // Read Configuration boolean showOwnerConfig = config.getBooleanSafe(MembersCourseNode.CONFIG_KEY_SHOWOWNER); // Generate widgets showOwners = uifactory.addCheckboxesHorizontal("members.owners", formLayout, onKeys, onValues); - showOwners.addActionListener(FormEvent.ONCLICK); // include existing fragment - IModuleConfiguration membersFrag = IModuleConfiguration.fragment("members", config); - membersFragment.initFormFragment(ureq, this, this, membersFrag); + super.initForm(formLayout, listener, ureq); // select initial state according to config showOwners.select("on", showOwnerConfig); @@ -143,53 +179,22 @@ public class MembersConfigForm extends FormBasicController { downloadFunctionEl.select(MembersCourseNode.EMAIL_FUNCTION_ALL, true); } - subm = uifactory.addFormSubmitButton("save", formLayout); + submitButton = uifactory.addFormSubmitButton("save", formLayout); update(); } - @Override - protected void doDispose() { - membersFragment.dispose(); - } - - @Override - protected void formOK(UserRequest ureq) { - fireEvent(ureq, Event.DONE_EVENT); - } - //method to check if the of of the checkboxes needs to be disabled in order to ensure a valid configuration //in the rare case of an invalid config all checkboxes are enabled - private void update() { - membersFragment.refreshContents(); - - flc.setDirty(true); - } - @Override - public IFormFragmentHost getFragmentHostInterface() { - return new IFormFragmentHost() { - final Translator parent = MembersConfigForm.this.getTranslator(); - final Translator delegate = Util.createPackageTranslator(MembersSelectorFormFragment.class, parent.getLocale(), parent); - final IFormFragmentController adapter = IFormFragmentController.fragmentControllerAdapter(MembersConfigForm.this, canSubmit -> { - subm.setEnabled(canSubmit); - }); - - @Override - public Translator getFragmentTranslator() { - return delegate; - } - - @Override - public IFormFragmentController getFragmentController() { - return adapter; - } - }; + protected void update() { + super.update(); + flc.setDirty(true); } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { - membersFragment.processFormEvent(ureq, source, event); + super.formInnerEvent(ureq, source, event); if(showOwners == source) { // || showCoaches == source || showParticipants == source) { config.setBooleanEntry(MembersCourseNode.CONFIG_KEY_SHOWOWNER, showOwners.isSelected(0)); @@ -217,4 +222,8 @@ public class MembersConfigForm extends FormBasicController { update(); } + @Override + protected void setFormCanSubmit(boolean enable) { + submitButton.setEnabled(enable); + } } diff --git a/src/main/java/org/olat/course/nodes/members/MembersCourseNodeEditController.java b/src/main/java/org/olat/course/nodes/members/MembersCourseNodeEditController.java index cc81014a2c157b66908b8892424b29a213910024..72993d2215dd1e39536757f600b691ce2d9af422 100644 --- a/src/main/java/org/olat/course/nodes/members/MembersCourseNodeEditController.java +++ b/src/main/java/org/olat/course/nodes/members/MembersCourseNodeEditController.java @@ -21,7 +21,6 @@ package org.olat.course.nodes.members; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.tabbedpane.TabbedPane; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.ControllerEventListener; @@ -49,7 +48,7 @@ public class MembersCourseNodeEditController extends ActivateableTabbableDefault private TabbedPane myTabbedPane; - private FormBasicController membersConfigForm; + private MembersConfigForm membersConfigForm; public MembersCourseNodeEditController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment euce, ModuleConfiguration config) { super(ureq,wControl); @@ -83,7 +82,6 @@ public class MembersCourseNodeEditController extends ActivateableTabbableDefault public void event(UserRequest urequest, Controller source, Event event) { super.event(urequest, source, event); if(source == membersConfigForm && event == Event.DONE_EVENT) { - membersConfigForm.storeFormData(urequest); fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT); } } diff --git a/src/main/java/org/olat/course/nodes/members/MembersCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/members/MembersCourseNodeRunController.java index 76d5433a2ff3774a49b85a9b078a5348cfb8c6b4..ce2f9da3c0fca6c9aee3ad3886813a2418608954 100644 --- a/src/main/java/org/olat/course/nodes/members/MembersCourseNodeRunController.java +++ b/src/main/java/org/olat/course/nodes/members/MembersCourseNodeRunController.java @@ -37,7 +37,6 @@ import org.olat.course.nodes.MembersCourseNode; import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroupService; -import org.olat.modules.IModuleConfiguration; import org.olat.modules.ModuleConfiguration; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; @@ -85,8 +84,6 @@ public class MembersCourseNodeRunController extends BasicController { String downloadFct = config.getStringValue(MembersCourseNode.CONFIG_KEY_DOWNLOAD_FUNCTION, MembersCourseNode.EMAIL_FUNCTION_COACH_ADMIN); boolean canDownload = MembersCourseNode.EMAIL_FUNCTION_ALL.equals(downloadFct) || userCourseEnv.isAdmin() || userCourseEnv.isCoach(); - IModuleConfiguration membersFrag = IModuleConfiguration.fragment("members", config); - if(showOwners) { RepositoryEntry courseRepositoryEntry = courseEnv.getCourseGroupManager().getCourseEntry(); owners = MembersHelpers.getOwners(repositoryService, courseRepositoryEntry); @@ -95,21 +92,21 @@ public class MembersCourseNodeRunController extends BasicController { } boolean showCoaches = false; - if(membersFrag.anyTrue(MembersCourseNode.CONFIG_KEY_COACHES_ALL, MembersCourseNode.CONFIG_KEY_COACHES_COURSE) - || membersFrag.hasAnyOf(MembersCourseNode.CONFIG_KEY_COACHES_GROUP, MembersCourseNode.CONFIG_KEY_COACHES_AREA)) { + if(config.anyTrue(MembersCourseNode.CONFIG_KEY_COACHES_ALL, MembersCourseNode.CONFIG_KEY_COACHES_COURSE) + || config.hasAnyOf(MembersCourseNode.CONFIG_KEY_COACHES_GROUP, MembersCourseNode.CONFIG_KEY_COACHES_AREA)) { CourseGroupManager cgm = courseEnv.getCourseGroupManager(); - MembersHelpers.addCoaches(membersFrag, cgm, businessGroupService, coaches); + MembersHelpers.addCoaches(config, cgm, businessGroupService, coaches); showCoaches = true; } boolean showParticipants = false; - if(membersFrag.anyTrue(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_ALL, MembersCourseNode.CONFIG_KEY_PARTICIPANTS_COURSE) - || membersFrag.hasAnyOf(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_GROUP, MembersCourseNode.CONFIG_KEY_PARTICIPANTS_AREA)) { + if(config.anyTrue(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_ALL, MembersCourseNode.CONFIG_KEY_PARTICIPANTS_COURSE) + || config.hasAnyOf(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_GROUP, MembersCourseNode.CONFIG_KEY_PARTICIPANTS_AREA)) { CourseGroupManager cgm = courseEnv.getCourseGroupManager(); - MembersHelpers.addParticipants(membersFrag, cgm, businessGroupService, participants); + MembersHelpers.addParticipants(config, cgm, businessGroupService, participants); showParticipants = true; } @@ -122,14 +119,11 @@ public class MembersCourseNodeRunController extends BasicController { putInitialPanel(membersDisplayRunController.getInitialComponent()); } - @Override protected void event(UserRequest ureq, Component source, Event event) { // } - - @Override protected void doDispose() { // nothing to dispose diff --git a/src/main/java/org/olat/course/nodes/members/MembersHelpers.java b/src/main/java/org/olat/course/nodes/members/MembersHelpers.java index decdbe1f021ed19c1527a82432d5644806054db2..204fff6b698b2ea104a41b7842be1f11d583affe 100644 --- a/src/main/java/org/olat/course/nodes/members/MembersHelpers.java +++ b/src/main/java/org/olat/course/nodes/members/MembersHelpers.java @@ -30,7 +30,7 @@ import org.olat.core.util.StringHelper; import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.nodes.MembersCourseNode; import org.olat.group.BusinessGroupService; -import org.olat.modules.IModuleConfiguration; +import org.olat.modules.ModuleConfiguration; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; @@ -52,11 +52,11 @@ public class MembersHelpers { // ----------------------------------------------------- - public static void addCoaches(IModuleConfiguration moduleConfiguration, CourseGroupManager cgm, BusinessGroupService bgs, List<Identity> list) { + public static void addCoaches(ModuleConfiguration moduleConfiguration, CourseGroupManager cgm, BusinessGroupService bgs, List<Identity> list) { if(moduleConfiguration.has(MembersCourseNode.CONFIG_KEY_COACHES_GROUP)) { - String coachGroupNames = moduleConfiguration.val(MembersCourseNode.CONFIG_KEY_COACHES_GROUP); - List<Long> coachGroupKeys = moduleConfiguration.val(MembersCourseNode.CONFIG_KEY_COACHES_GROUP_ID); + String coachGroupNames = moduleConfiguration.getStringValue(MembersCourseNode.CONFIG_KEY_COACHES_GROUP); + List<Long> coachGroupKeys = moduleConfiguration.getList(MembersCourseNode.CONFIG_KEY_COACHES_GROUP_ID, Long.class); if(coachGroupKeys == null && StringHelper.containsNonWhitespace(coachGroupNames)) { coachGroupKeys = bgs.toGroupKeys(coachGroupNames, cgm.getCourseEntry()); } @@ -64,8 +64,8 @@ public class MembersHelpers { } if(moduleConfiguration.has(MembersCourseNode.CONFIG_KEY_COACHES_AREA)) { - String coachAreaNames = moduleConfiguration.val(MembersCourseNode.CONFIG_KEY_COACHES_AREA); - List<Long> coachAreaKeys = moduleConfiguration.val(MembersCourseNode.CONFIG_KEY_COACHES_AREA_IDS); + String coachAreaNames = moduleConfiguration.getStringValue(MembersCourseNode.CONFIG_KEY_COACHES_AREA); + List<Long> coachAreaKeys = moduleConfiguration.getList(MembersCourseNode.CONFIG_KEY_COACHES_AREA_IDS, Long.class); if(coachAreaKeys == null && StringHelper.containsNonWhitespace(coachAreaNames)) { coachAreaKeys = bgs.toGroupKeys(coachAreaNames, cgm.getCourseEntry()); } @@ -113,11 +113,11 @@ public class MembersHelpers { // ----------------------------------------------------- - public static void addParticipants(IModuleConfiguration moduleConfiguration, CourseGroupManager cgm, BusinessGroupService bgs, List<Identity> list) { + public static void addParticipants(ModuleConfiguration moduleConfiguration, CourseGroupManager cgm, BusinessGroupService bgs, List<Identity> list) { if(moduleConfiguration.has(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_GROUP)) { - String participantGroupNames = moduleConfiguration.val(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_GROUP); - List<Long> participantGroupKeys = moduleConfiguration.val(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_GROUP_ID); + String participantGroupNames = moduleConfiguration.getStringValue(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_GROUP); + List<Long> participantGroupKeys = moduleConfiguration.getList(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_GROUP_ID, Long.class); if(participantGroupKeys == null && StringHelper.containsNonWhitespace(participantGroupNames)) { participantGroupKeys = bgs.toGroupKeys(participantGroupNames, cgm.getCourseEntry()); } @@ -125,8 +125,8 @@ public class MembersHelpers { } if(moduleConfiguration.has(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_AREA)) { - String participantAreaNames = moduleConfiguration.val(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_AREA); - List<Long> participantAreaKeys = moduleConfiguration.val(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_AREA_ID); + String participantAreaNames = moduleConfiguration.getStringValue(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_AREA); + List<Long> participantAreaKeys = moduleConfiguration.getList(MembersCourseNode.CONFIG_KEY_PARTICIPANTS_AREA_ID, Long.class); if(participantAreaKeys == null && StringHelper.containsNonWhitespace(participantAreaNames)) { participantAreaKeys = bgs.toGroupKeys(participantAreaNames, cgm.getCourseEntry()); } diff --git a/src/main/java/org/olat/course/nodes/members/MembersPeekViewController.java b/src/main/java/org/olat/course/nodes/members/MembersPeekViewController.java index 0c36666a49001366cfff9335f0406529abc0a7bf..a905877408055c3981f84ef261d562b367332c1e 100644 --- a/src/main/java/org/olat/course/nodes/members/MembersPeekViewController.java +++ b/src/main/java/org/olat/course/nodes/members/MembersPeekViewController.java @@ -40,7 +40,6 @@ import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroupService; -import org.olat.modules.IModuleConfiguration; import org.olat.modules.ModuleConfiguration; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; @@ -105,12 +104,9 @@ public class MembersPeekViewController extends BasicController { }); putInitialPanel(tableController.getInitialComponent()); - } protected void readFormData(ModuleConfiguration config) { - IModuleConfiguration membersFrag = IModuleConfiguration.fragment("members", config); - CourseGroupManager cgm = courseEnv.getCourseGroupManager(); @@ -118,10 +114,10 @@ public class MembersPeekViewController extends BasicController { List<Identity> owners = MembersHelpers.getOwners(repositoryService, courseRepositoryEntry); List<Identity> coaches = new ArrayList<>(); - MembersHelpers.addCoaches(membersFrag, cgm, businessGroupService, coaches); + MembersHelpers.addCoaches(config, cgm, businessGroupService, coaches); List<Identity> participants = new ArrayList<>(); - MembersHelpers.addParticipants(membersFrag, cgm, businessGroupService, participants); + MembersHelpers.addParticipants(config, cgm, businessGroupService, participants); Set<Long> duplicateCatcher = new HashSet<Long>(); List<Identity> filteredOwners = owners.stream() @@ -154,9 +150,9 @@ public class MembersPeekViewController extends BasicController { }) .collect(Collectors.toList()); - entries.add(new Row(translate("members.owners"), Integer.toString(filteredOwners.size()))); - entries.add(new Row(translate("members.coaches"), Integer.toString(filteredCoaches.size()))); - entries.add(new Row(translate("members.participants"), Integer.toString(filteredParticipants.size()))); + entries.add(new Row(translate("members.owners"), Integer.toString(filteredOwners.size()))); + entries.add(new Row(translate("members.coaches"), Integer.toString(filteredCoaches.size()))); + entries.add(new Row(translate("members.participants"), Integer.toString(filteredParticipants.size()))); } @Override @@ -170,8 +166,8 @@ public class MembersPeekViewController extends BasicController { } private static class Row { - String col1; - String col2; + private String col1; + private String col2; public Row(String col1, String col2) { this.col1 = col1; this.col2 = col2; diff --git a/src/main/java/org/olat/course/nodes/members/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/nodes/members/_i18n/LocalStrings_pt_BR.properties index f9bd2b0e0f08476f9541f486354662581d818fca..470db21c3fa6dc612941ad853fc45ed9180a5353 100644 --- a/src/main/java/org/olat/course/nodes/members/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/nodes/members/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Fri Jun 23 14:52:13 CEST 2017 +#Tue Sep 05 23:35:35 CEST 2017 add.member=Adicionar already.all.selected=Voc\u00EA j\u00E1 escolheu todos usu\u00E1rios coaches=Treinadores do Curso diff --git a/src/main/java/org/olat/course/editor/formfragments/MembersSelectorFormFragment.java b/src/main/java/org/olat/course/nodes/members/ui/group/MembersSelectorFormFragment.java similarity index 64% rename from src/main/java/org/olat/course/editor/formfragments/MembersSelectorFormFragment.java rename to src/main/java/org/olat/course/nodes/members/ui/group/MembersSelectorFormFragment.java index 4cb74f9071eaae0a7167eae378d9a70fcd8217ac..8cde17b8c72caa926dc744cdefe3be6f31575252 100644 --- a/src/main/java/org/olat/course/editor/formfragments/MembersSelectorFormFragment.java +++ b/src/main/java/org/olat/course/nodes/members/ui/group/MembersSelectorFormFragment.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.course.editor.formfragments; +package org.olat.course.nodes.members.ui.group; import java.util.ArrayList; import java.util.List; @@ -25,18 +25,18 @@ import java.util.List; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; -import org.olat.core.gui.components.form.flexible.FormUIFactory; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.SelectionElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; -import org.olat.core.gui.components.form.flexible.impl.BasicFormFragment; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; -import org.olat.core.gui.components.form.flexible.impl.IFormFragment; 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.closablewrapper.CloseableModalController; import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; import org.olat.course.condition.AreaSelectionController; import org.olat.course.condition.GroupSelectionController; import org.olat.course.editor.CourseEditorEnv; @@ -44,7 +44,7 @@ import org.olat.group.BusinessGroupService; import org.olat.group.BusinessGroupShort; import org.olat.group.area.BGArea; import org.olat.group.area.BGAreaManager; -import org.olat.modules.IModuleConfiguration; +import org.olat.modules.ModuleConfiguration; import org.springframework.beans.factory.annotation.Autowired; /** @@ -52,26 +52,8 @@ import org.springframework.beans.factory.annotation.Autowired; * * <p>Initial date: May 6, 2016<br> * @author lmihalkovic, http://www.frentix.com - * @see IFormFragment */ -public class MembersSelectorFormFragment extends BasicFormFragment { - - public static final String CONFIG_KEY_COACHES_GROUP = "GroupCoaches"; - public static final String CONFIG_KEY_COACHES_AREA = "AreaCoaches"; - public static final String CONFIG_KEY_COACHES_GROUP_ID = "GroupCoachesIds"; - public static final String CONFIG_KEY_COACHES_AREA_IDS = "AreaCoachesIds"; - public static final String CONFIG_KEY_COACHES_COURSE = "CourseCoaches"; - public static final String CONFIG_KEY_COACHES_ALL = "CoachesAll"; - - public static final String CONFIG_KEY_PARTICIPANTS_GROUP = "GroupParticipants"; - public static final String CONFIG_KEY_PARTICIPANTS_AREA = "AreaParticipants"; - public static final String CONFIG_KEY_PARTICIPANTS_GROUP_ID = "GroupParticipantsIds"; - public static final String CONFIG_KEY_PARTICIPANTS_AREA_ID = "AreaParticipantsIds"; - public static final String CONFIG_KEY_PARTICIPANTS_COURSE = "CourseParticipants"; - public static final String CONFIG_KEY_PARTICIPANTS_ALL = "ParticipantsAll"; - - - private final CourseEditorEnv cev; +public abstract class MembersSelectorFormFragment extends FormBasicController { // Coaches private SelectionElement wantCoaches; @@ -99,49 +81,58 @@ public class MembersSelectorFormFragment extends BasicFormFragment { // Popup form private CloseableModalController cmc; - - @Autowired private BGAreaManager areaManager; @Autowired private BusinessGroupService businessGroupService; + + private final CourseEditorEnv cev; + protected final ModuleConfiguration config; - public MembersSelectorFormFragment(CourseEditorEnv cev) { + public MembersSelectorFormFragment(UserRequest ureq, WindowControl wControl, + CourseEditorEnv cev, ModuleConfiguration config) { + super(ureq, wControl, Util.createPackageTranslator(MembersSelectorFormFragment.class, ureq.getLocale())); this.cev = cev; + this.config = config; + initForm(ureq); + validateFormLogic(ureq); } @Override - protected void initFormFragment(FormItemContainer formLayout, Controller listener, UserRequest ureq, IModuleConfiguration config) { - FormUIFactory uifactory = uifactory(); - - // ---------------------------------------------------------------------- -// Boolean ownerSelection = config.getBooleanSafe(CONFIG_KEY_OWNERS); - Boolean coacheSelection = config.getBooleanSafe(CONFIG_KEY_COACHES_ALL) || config.getBooleanSafe(CONFIG_KEY_COACHES_COURSE) || config.get(CONFIG_KEY_COACHES_GROUP) != null || config.get(CONFIG_KEY_COACHES_AREA) != null; + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + + Boolean coacheSelection = config.getBooleanSafe(getConfigKeyCoachesAll()) + || config.getBooleanSafe(getConfigKeyCoachesCourse()) + || config.get(getConfigKeyCoachesGroup()) != null + || config.get(getConfigKeyCoachesArea()) != null; - // COACHES: from course or groups wantCoaches = uifactory.addCheckboxesHorizontal("coaches", "message.want.coaches", formLayout, new String[]{"xx"},new String[]{null}); - wantCoaches.setTranslator(host.getFragmentTranslator()); - if(coacheSelection != null && coacheSelection) wantCoaches.select("xx", true); - + if(coacheSelection != null && coacheSelection) { + wantCoaches.select("xx", true); + } wantCoaches.addActionListener(FormEvent.ONCLICK); - coachesChoice = uifactory.addRadiosVertical( - "coachesChoice", null, formLayout, + coachesChoice = uifactory.addRadiosVertical("coachesChoice", null, formLayout, new String[]{"all", "course", "group"}, - new String[]{host.getFragmentTranslator().translate("form.message.coaches.all"), host.getFragmentTranslator().translate("form.message.coaches.course"), host.getFragmentTranslator().translate("form.message.coaches.group")} + new String[]{ translate("form.message.coaches.all"), translate("form.message.coaches.course"), translate("form.message.coaches.group")} ); - if(config.getBooleanSafe(CONFIG_KEY_COACHES_ALL)) coachesChoice.select("all", true); - if(config.getBooleanSafe(CONFIG_KEY_COACHES_COURSE)) coachesChoice.select("course", true); - if(config.get(CONFIG_KEY_COACHES_GROUP) != null || config.get(CONFIG_KEY_COACHES_AREA) != null) coachesChoice.select("group", true); + if(config.getBooleanSafe(getConfigKeyCoachesAll())) { + coachesChoice.select("all", true); + } + if(config.getBooleanSafe(getConfigKeyCoachesCourse())) { + coachesChoice.select("course", true); + } + if(config.get(getConfigKeyCoachesGroup()) != null || config.get(getConfigKeyCoachesArea()) != null) { + coachesChoice.select("group", true); + } coachesChoice.addActionListener(FormEvent.ONCLICK); coachesChoice.setVisible(false); chooseGroupCoachesLink = uifactory.addFormLink("groupCoachesChoose", formLayout, "btn btn-default o_xsmall o_form_groupchooser"); - chooseGroupCoachesLink.setTranslator(host.getFragmentTranslator()); chooseGroupCoachesLink.setIconLeftCSS("o_icon o_icon-fw o_icon_group"); chooseGroupCoachesLink.setVisible(false); chooseGroupCoachesLink.setLabel("form.message.group", null); @@ -152,23 +143,20 @@ public class MembersSelectorFormFragment extends BasicFormFragment { chooseGroupCoachesLink.setElementCssClass("o_omit_margin"); String groupCoachesInitVal; - @SuppressWarnings("unchecked") - List<Long> groupCoachesKeys = (List<Long>)config.get(CONFIG_KEY_COACHES_GROUP_ID); + List<Long> groupCoachesKeys = config.getList(getConfigKeyCoachesGroupIds(), Long.class); if(groupCoachesKeys == null) { - groupCoachesInitVal = config.getAs(CONFIG_KEY_COACHES_GROUP); + groupCoachesInitVal = config.getStringValue(getConfigKeyCoachesGroup()); groupCoachesKeys = businessGroupService.toGroupKeys(groupCoachesInitVal, cev.getCourseGroupManager().getCourseEntry()); } groupCoachesInitVal = getGroupNames(groupCoachesKeys); easyGroupCoachSelectionList = uifactory.addStaticTextElement("groupCoaches", null, groupCoachesInitVal, formLayout); - easyGroupCoachSelectionList.setTranslator(host.getFragmentTranslator()); easyGroupCoachSelectionList.setUserObject(groupCoachesKeys); easyGroupCoachSelectionList.setVisible(false); easyGroupCoachSelectionList.setElementCssClass("text-muted"); chooseAreasCoachesLink = uifactory.addFormLink("areaCoachesChoose", formLayout, "btn btn-default o_xsmall o_form_areachooser"); - chooseAreasCoachesLink.setTranslator(host.getFragmentTranslator()); chooseAreasCoachesLink.setIconLeftCSS("o_icon o_icon-fw o_icon_courseareas"); chooseAreasCoachesLink.setLabel("form.message.area", null); chooseAreasCoachesLink.setElementCssClass("o_omit_margin"); @@ -177,42 +165,47 @@ public class MembersSelectorFormFragment extends BasicFormFragment { } String areaCoachesInitVal; - @SuppressWarnings("unchecked") - List<Long> areaCoachesKeys = (List<Long>)config.get(CONFIG_KEY_COACHES_AREA_IDS); + List<Long> areaCoachesKeys = config.getList(getConfigKeyCoachesAreaIds(), Long.class); if(areaCoachesKeys == null) { - areaCoachesInitVal = (String)config.get(CONFIG_KEY_COACHES_AREA); + areaCoachesInitVal = (String)config.get(getConfigKeyCoachesArea()); areaCoachesKeys = areaManager.toAreaKeys(areaCoachesInitVal, cev.getCourseGroupManager().getCourseResource()); } areaCoachesInitVal = getAreaNames(areaCoachesKeys); easyAreaCoachSelectionList = uifactory.addStaticTextElement("areaCoaches", null, areaCoachesInitVal, formLayout); - easyAreaCoachSelectionList.setTranslator(host.getFragmentTranslator()); easyAreaCoachSelectionList.setUserObject(areaCoachesKeys); easyAreaCoachSelectionList.setVisible(false); easyAreaCoachSelectionList.setElementCssClass("text-muted"); // PARTICIPANTS: from course or groups - Boolean particiapntSelection = config.getBooleanSafe(CONFIG_KEY_PARTICIPANTS_ALL) || config.getBooleanSafe(CONFIG_KEY_PARTICIPANTS_COURSE) || config.get(CONFIG_KEY_PARTICIPANTS_GROUP) != null || config.get(CONFIG_KEY_PARTICIPANTS_AREA) != null; + Boolean particiapntSelection = config.getBooleanSafe(getConfigKeyParticipantsAll()) + || config.getBooleanSafe(getConfigKeyParticipantsCourse()) + || config.get(getConfigKeyParticipantsGroup()) != null + || config.get(getConfigKeyParticipantsArea()) != null; wantParticipants = uifactory.addCheckboxesHorizontal("participants", "message.want.participants", formLayout, new String[]{"xx"},new String[]{null}); - wantParticipants.setTranslator(host.getFragmentTranslator()); if(particiapntSelection != null && particiapntSelection) wantParticipants.select("xx", true); wantParticipants.addActionListener(FormEvent.ONCLICK); participantsChoice = uifactory.addRadiosVertical( "participantsChoice", null, formLayout, - new String[]{"all", "course", "group"}, - new String[]{host.getFragmentTranslator().translate("form.message.participants.all"), host.getFragmentTranslator().translate("form.message.participants.course"), host.getFragmentTranslator().translate("form.message.participants.group")} + new String[]{ "all", "course", "group" }, + new String[]{ translate("form.message.participants.all"), translate("form.message.participants.course"), translate("form.message.participants.group")} ); - if(config.getBooleanSafe(CONFIG_KEY_PARTICIPANTS_ALL)) participantsChoice.select("all", true); - if(config.getBooleanSafe(CONFIG_KEY_PARTICIPANTS_COURSE)) participantsChoice.select("course", true); - if(config.get(CONFIG_KEY_PARTICIPANTS_GROUP) != null || config.get(CONFIG_KEY_PARTICIPANTS_AREA) != null) participantsChoice.select("group", true); + if(config.getBooleanSafe(getConfigKeyParticipantsAll())) { + participantsChoice.select("all", true); + } + if(config.getBooleanSafe(getConfigKeyParticipantsCourse())) { + participantsChoice.select("course", true); + } + if(config.get(getConfigKeyParticipantsGroup()) != null || config.get(getConfigKeyParticipantsArea()) != null) { + participantsChoice.select("group", true); + } participantsChoice.addActionListener(FormEvent.ONCLICK); participantsChoice.setVisible(false); chooseGroupParticipantsLink = uifactory.addFormLink("groupParticipantsChoose", formLayout, "btn btn-default o_xsmall o_form_groupchooser"); - chooseGroupParticipantsLink.setTranslator(host.getFragmentTranslator()); chooseGroupParticipantsLink.setIconLeftCSS("o_icon o_icon-fw o_icon_group"); chooseGroupParticipantsLink.setVisible(false); chooseGroupParticipantsLink.setLabel("form.message.group", null); @@ -223,23 +216,20 @@ public class MembersSelectorFormFragment extends BasicFormFragment { } String groupParticipantsInitVal; - @SuppressWarnings("unchecked") - List<Long> groupParticipantsKeys = (List<Long>)config.get(CONFIG_KEY_PARTICIPANTS_GROUP_ID); + List<Long> groupParticipantsKeys = config.getList(getConfigKeyParticipantsGroupIds(), Long.class); if(groupParticipantsKeys == null) { - groupParticipantsInitVal = (String)config.get(CONFIG_KEY_PARTICIPANTS_GROUP); + groupParticipantsInitVal = (String)config.get(getConfigKeyParticipantsGroup()); groupParticipantsKeys = businessGroupService.toGroupKeys(groupParticipantsInitVal, cev.getCourseGroupManager().getCourseEntry()); } groupParticipantsInitVal = getGroupNames(groupParticipantsKeys); easyGroupParticipantsSelectionList = uifactory.addStaticTextElement("groupParticipants", null, groupParticipantsInitVal, formLayout); - easyGroupParticipantsSelectionList.setTranslator(host.getFragmentTranslator()); easyGroupParticipantsSelectionList.setUserObject(groupParticipantsKeys); easyGroupParticipantsSelectionList.setVisible(false); easyGroupParticipantsSelectionList.setElementCssClass("text-muted"); chooseAreasParticipantsLink = uifactory.addFormLink("areaParticipantsChoose", formLayout, "btn btn-default o_xsmall o_form_areachooser"); - chooseAreasParticipantsLink.setTranslator(host.getFragmentTranslator()); chooseAreasParticipantsLink.setIconLeftCSS("o_icon o_icon-fw o_icon_courseareas"); chooseAreasParticipantsLink.setVisible(false); chooseAreasParticipantsLink.setLabel("form.message.area", null); @@ -250,31 +240,22 @@ public class MembersSelectorFormFragment extends BasicFormFragment { } String areaParticipantsInitVal; - @SuppressWarnings("unchecked") - List<Long> areaParticipantsKeys = (List<Long>)config.get(CONFIG_KEY_PARTICIPANTS_AREA_ID); + List<Long> areaParticipantsKeys = config.getList(getConfigKeyParticipantsAreaIds(), Long.class); if(areaParticipantsKeys == null) { - areaParticipantsInitVal = (String)config.get(CONFIG_KEY_PARTICIPANTS_AREA); + areaParticipantsInitVal = (String)config.get(getConfigKeyParticipantsArea()); areaParticipantsKeys = areaManager.toAreaKeys(areaParticipantsInitVal, cev.getCourseGroupManager().getCourseResource()); } areaParticipantsInitVal = getAreaNames(areaParticipantsKeys); easyAreaParticipantsSelectionList = uifactory.addStaticTextElement("areaParticipants", null, areaParticipantsInitVal, formLayout); - easyAreaParticipantsSelectionList.setTranslator(host.getFragmentTranslator()); easyAreaParticipantsSelectionList.setUserObject(areaParticipantsKeys); easyAreaParticipantsSelectionList.setVisible(false); easyAreaParticipantsSelectionList.setElementCssClass("text-muted"); - uifactory.addSpacerElement("s4", formLayout, false); - -// update(); - } - - @Override - public void refreshContents() { - update(); + uifactory.addSpacerElement("s4", formLayout, false); } - private void update () { + protected void update() { coachesChoice.setVisible(wantCoaches.isSelected(0)); chooseGroupCoachesLink.setVisible(coachesChoice.isSelected(2) && wantCoaches.isSelected(0)); chooseAreasCoachesLink.setVisible(coachesChoice.isSelected(2) && wantCoaches.isSelected(0)); @@ -295,11 +276,11 @@ public class MembersSelectorFormFragment extends BasicFormFragment { coachesChoice.clearError(); participantsChoice.clearError(); - container.setNeedsLayout(); + setNeedsLayout(); } @Override - public boolean validateFormLogic(UserRequest ureq) { + protected boolean validateFormLogic(UserRequest ureq) { boolean isOK = true; if(sendToCoaches()){ @@ -336,6 +317,12 @@ public class MembersSelectorFormFragment extends BasicFormFragment { return isOK; } + @Override + protected final void formOK(UserRequest ureq) { + storeConfiguration(config); + fireEvent(ureq, Event.DONE_EVENT); + } + private String getGroupNames(List<Long> keys) { StringBuilder sb = new StringBuilder(); List<BusinessGroupShort> groups = businessGroupService.loadShortBusinessGroups(keys); @@ -359,96 +346,90 @@ public class MembersSelectorFormFragment extends BasicFormFragment { } @Override - public void dispose() { + protected void doDispose() { // nothing at the moment } @Override - public boolean processFormEvent(UserRequest ureq, FormItem source, FormEvent event) { - boolean processed = false; - + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if (source == chooseGroupCoachesLink) { - host.getFragmentController().removeAsListenerAndDispose(cmc); - host.getFragmentController().removeAsListenerAndDispose(groupChooseCoaches); + removeAsListenerAndDispose(cmc); + removeAsListenerAndDispose(groupChooseCoaches); - groupChooseCoaches = new GroupSelectionController(ureq, host.getFragmentController().getWindowControl(), true, + groupChooseCoaches = new GroupSelectionController(ureq, getWindowControl(), true, cev.getCourseGroupManager(), getKeys(easyGroupCoachSelectionList)); - host.getFragmentController().listenTo(groupChooseCoaches); + listenTo(groupChooseCoaches); String title = chooseGroupCoachesLink.getLinkTitleText(); - cmc = new CloseableModalController(host.getFragmentController().getWindowControl(), "close", groupChooseCoaches.getInitialComponent(), true, title); - host.getFragmentController().listenTo(cmc); + cmc = new CloseableModalController(getWindowControl(), "close", groupChooseCoaches.getInitialComponent(), true, title); + listenTo(cmc); cmc.activate(); - host.getFragmentController().setFormCanSubmit(false); - processed = true; + setFormCanSubmit(false); } else if(source == chooseGroupParticipantsLink){ - host.getFragmentController().removeAsListenerAndDispose(cmc); - host.getFragmentController().removeAsListenerAndDispose(groupChooseParticipants); + removeAsListenerAndDispose(cmc); + removeAsListenerAndDispose(groupChooseParticipants); - groupChooseParticipants = new GroupSelectionController(ureq, host.getFragmentController().getWindowControl(), true, + groupChooseParticipants = new GroupSelectionController(ureq, getWindowControl(), true, cev.getCourseGroupManager(), getKeys(easyGroupParticipantsSelectionList)); - host.getFragmentController().listenTo(groupChooseParticipants); + listenTo(groupChooseParticipants); String title = chooseGroupParticipantsLink.getLabelText(); - cmc = new CloseableModalController(host.getFragmentController().getWindowControl(), "close", groupChooseParticipants.getInitialComponent(), true, title); - host.getFragmentController().listenTo(cmc); + cmc = new CloseableModalController(getWindowControl(), "close", groupChooseParticipants.getInitialComponent(), true, title); + listenTo(cmc); cmc.activate(); - host.getFragmentController().setFormCanSubmit(false); - processed = true; + setFormCanSubmit(false); } else if (source == chooseAreasCoachesLink) { // already areas -> choose areas - host.getFragmentController().removeAsListenerAndDispose(cmc); - host.getFragmentController().removeAsListenerAndDispose(areaChooseCoaches); + removeAsListenerAndDispose(cmc); + removeAsListenerAndDispose(areaChooseCoaches); - areaChooseCoaches = new AreaSelectionController (ureq, host.getFragmentController().getWindowControl(), true, + areaChooseCoaches = new AreaSelectionController (ureq, getWindowControl(), true, cev.getCourseGroupManager(), getKeys(easyAreaCoachSelectionList)); - host.getFragmentController().listenTo(areaChooseCoaches); + listenTo(areaChooseCoaches); String title = chooseAreasCoachesLink.getLinkTitleText(); - cmc = new CloseableModalController(host.getFragmentController().getWindowControl(), "close", areaChooseCoaches.getInitialComponent(), true, title); - host.getFragmentController().listenTo(cmc); + cmc = new CloseableModalController(getWindowControl(), "close", areaChooseCoaches.getInitialComponent(), true, title); + listenTo(cmc); cmc.activate(); - host.getFragmentController().setFormCanSubmit(false); - processed = true; + setFormCanSubmit(false); } else if (source == chooseAreasParticipantsLink){ // already areas -> choose areas - host.getFragmentController().removeAsListenerAndDispose(cmc); - host.getFragmentController().removeAsListenerAndDispose(areaChooseParticipants); + removeAsListenerAndDispose(cmc); + removeAsListenerAndDispose(areaChooseParticipants); - areaChooseParticipants = new AreaSelectionController (ureq, host.getFragmentController().getWindowControl(), true, + areaChooseParticipants = new AreaSelectionController (ureq, getWindowControl(), true, cev.getCourseGroupManager(), getKeys(easyAreaParticipantsSelectionList)); - host.getFragmentController().listenTo(areaChooseParticipants); + listenTo(areaChooseParticipants); String title = chooseAreasParticipantsLink.getLabelText(); - cmc = new CloseableModalController(host.getFragmentController().getWindowControl(), "close", areaChooseParticipants.getInitialComponent(), true, title); - host.getFragmentController().listenTo(cmc); + cmc = new CloseableModalController(getWindowControl(), "close", areaChooseParticipants.getInitialComponent(), true, title); + listenTo(cmc); cmc.activate(); - host.getFragmentController().setFormCanSubmit(false); - processed = true; - } - - return processed; + setFormCanSubmit(false); + } } + + protected abstract void setFormCanSubmit(boolean enable); protected void cleanUp() { - host.getFragmentController().removeAsListenerAndDispose(cmc); - host.getFragmentController().removeAsListenerAndDispose(areaChooseParticipants); - host.getFragmentController().removeAsListenerAndDispose(areaChooseCoaches); - host.getFragmentController().removeAsListenerAndDispose(groupChooseCoaches); + removeAsListenerAndDispose(cmc); + removeAsListenerAndDispose(areaChooseParticipants); + removeAsListenerAndDispose(areaChooseCoaches); + removeAsListenerAndDispose(groupChooseCoaches); } + @Override - public boolean processEvent(UserRequest ureq, Controller source, Event event) { + protected void event(UserRequest ureq, Controller source, Event event) { + setFormCanSubmit(true); - host.getFragmentController().setFormCanSubmit(true); -// subm.setEnabled(true); if (source == groupChooseCoaches) { if (event == Event.DONE_EVENT) { cmc.deactivate(); easyGroupCoachSelectionList.setValue(getGroupNames(groupChooseCoaches.getSelectedKeys())); easyGroupCoachSelectionList.setUserObject(groupChooseCoaches.getSelectedKeys()); chooseGroupCoachesLink.setI18nKey("groupCoachesChoose"); - container.setNeedsLayout(); + setNeedsLayout(); } else if (Event.CANCELLED_EVENT == event) { cmc.deactivate(); } @@ -458,7 +439,7 @@ public class MembersSelectorFormFragment extends BasicFormFragment { easyAreaCoachSelectionList.setValue(getAreaNames(areaChooseCoaches.getSelectedKeys())); easyAreaCoachSelectionList.setUserObject(areaChooseCoaches.getSelectedKeys()); chooseAreasCoachesLink.setI18nKey("areaCoachesChoose"); - container.setNeedsLayout(); + setNeedsLayout(); } else if (event == Event.CANCELLED_EVENT) { cmc.deactivate(); } @@ -468,7 +449,7 @@ public class MembersSelectorFormFragment extends BasicFormFragment { easyGroupParticipantsSelectionList.setValue(getGroupNames(groupChooseParticipants.getSelectedKeys())); easyGroupParticipantsSelectionList.setUserObject(groupChooseParticipants.getSelectedKeys()); chooseGroupParticipantsLink.setI18nKey("groupParticipantsChoose"); - container.setNeedsLayout(); + setNeedsLayout(); } else if (Event.CANCELLED_EVENT == event) { cmc.deactivate(); } @@ -478,13 +459,11 @@ public class MembersSelectorFormFragment extends BasicFormFragment { easyAreaParticipantsSelectionList.setValue(getAreaNames(areaChooseParticipants.getSelectedKeys())); easyAreaParticipantsSelectionList.setUserObject(areaChooseParticipants.getSelectedKeys()); chooseAreasParticipantsLink.setI18nKey("areaParticipantsChoose"); - container.setNeedsLayout(); + setNeedsLayout(); } else if (event == Event.CANCELLED_EVENT) { cmc.deactivate(); } } - - return false; } private List<Long> getKeys(StaticTextElement element) { @@ -564,7 +543,7 @@ public class MembersSelectorFormFragment extends BasicFormFragment { } protected boolean sendToCoachesAll(){ - return coachesChoice.isSelected(0)&& wantCoaches.isSelected(0); + return coachesChoice.isSelected(0) && wantCoaches.isSelected(0); } protected boolean sendToCoachesGroup(){ @@ -572,11 +551,11 @@ public class MembersSelectorFormFragment extends BasicFormFragment { } protected boolean sendToParticipantsCourse(){ - return participantsChoice.isSelected(1)&& wantParticipants.isSelected(0); + return participantsChoice.isSelected(1) && wantParticipants.isSelected(0); } protected boolean sendToParticipantsAll(){ - return participantsChoice.isSelected(0)&& wantParticipants.isSelected(0); + return participantsChoice.isSelected(0) && wantParticipants.isSelected(0); } protected boolean sendToParticipantsGroup(){ @@ -598,22 +577,37 @@ public class MembersSelectorFormFragment extends BasicFormFragment { return false; } - @Override - public void storeConfiguration(UserRequest ureq, IModuleConfiguration moduleConfiguration) { - MembersSelectorFormFragment configForm = this; - moduleConfiguration.set(CONFIG_KEY_COACHES_GROUP, configForm.getGroupCoaches()); - moduleConfiguration.set(CONFIG_KEY_COACHES_GROUP_ID, configForm.getGroupCoachesIds()); - moduleConfiguration.set(CONFIG_KEY_COACHES_AREA, configForm.getCoachesAreas()); - moduleConfiguration.set(CONFIG_KEY_COACHES_AREA_IDS, configForm.getCoachesAreaIds()); - moduleConfiguration.setBooleanEntry(CONFIG_KEY_COACHES_ALL, configForm.sendToCoachesAll()); - moduleConfiguration.setBooleanEntry(CONFIG_KEY_COACHES_COURSE, configForm.sendToCoachesCourse()); + protected void storeConfiguration(ModuleConfiguration config) { + config.set(getConfigKeyCoachesGroup(), getGroupCoaches()); + config.set(getConfigKeyCoachesGroupIds(), getGroupCoachesIds()); + config.set(getConfigKeyCoachesArea(), getCoachesAreas()); + config.set(getConfigKeyCoachesAreaIds(), getCoachesAreaIds()); + config.setBooleanEntry(getConfigKeyCoachesAll(), sendToCoachesAll()); + config.setBooleanEntry(getConfigKeyCoachesCourse(), sendToCoachesCourse()); - moduleConfiguration.set(CONFIG_KEY_PARTICIPANTS_GROUP, configForm.getGroupParticipants()); - moduleConfiguration.set(CONFIG_KEY_PARTICIPANTS_GROUP_ID, configForm.getGroupParticipantsIds()); - moduleConfiguration.set(CONFIG_KEY_PARTICIPANTS_AREA, configForm.getParticipantsAreas()); - moduleConfiguration.set(CONFIG_KEY_PARTICIPANTS_AREA_ID, configForm.getParticipantsAreaIds()); - moduleConfiguration.setBooleanEntry(CONFIG_KEY_PARTICIPANTS_ALL, configForm.sendToParticipantsAll()); - moduleConfiguration.setBooleanEntry(CONFIG_KEY_PARTICIPANTS_COURSE, configForm.sendToParticipantsCourse()); + config.set(getConfigKeyParticipantsGroup(), getGroupParticipants()); + config.set(getConfigKeyParticipantsGroupIds(), getGroupParticipantsIds()); + config.set(getConfigKeyParticipantsArea(), getParticipantsAreas()); + config.set(getConfigKeyParticipantsAreaIds(), getParticipantsAreaIds()); + config.setBooleanEntry(getConfigKeyParticipantsAll(), sendToParticipantsAll()); + config.setBooleanEntry(getConfigKeyParticipantsCourse(), sendToParticipantsCourse()); } + + protected abstract String getConfigKeyCoachesGroup(); + protected abstract String getConfigKeyCoachesGroupIds(); + + protected abstract String getConfigKeyCoachesArea(); + protected abstract String getConfigKeyCoachesAreaIds(); + + protected abstract String getConfigKeyCoachesCourse(); + protected abstract String getConfigKeyCoachesAll(); + protected abstract String getConfigKeyParticipantsGroup(); + protected abstract String getConfigKeyParticipantsArea(); + + protected abstract String getConfigKeyParticipantsGroupIds(); + protected abstract String getConfigKeyParticipantsAreaIds(); + + protected abstract String getConfigKeyParticipantsCourse(); + protected abstract String getConfigKeyParticipantsAll(); } diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_ar.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_ar.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_ar.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_bg.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_bg.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_bg.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_cs.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_cs.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_cs.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_da.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_da.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_da.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_da.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_de.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_de.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_de.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_el.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_el.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_el.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_en.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_en.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_en.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_es.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_es.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_es.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_fa.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_fa.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_fa.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_fa.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_fr.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_fr.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_fr.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_it.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_it.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_it.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_jp.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_jp.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_jp.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_lt.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_lt.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_lt.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_lt.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_nl_NL.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_nl_NL.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_nl_NL.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_pl.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_pl.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_pl.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_pt_BR.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_pt_BR.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_pt_BR.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_pt_PT.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_pt_PT.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_pt_PT.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_pt_PT.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_ru.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_ru.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_ru.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_sq.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_sq.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_sq.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_zh_CN.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_zh_CN.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_zh_CN.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_zh_TW.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/LocalStrings_zh_TW.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/LocalStrings_zh_TW.properties diff --git a/src/main/java/org/olat/course/editor/formfragments/_i18n/i18nBundleMetadata.properties b/src/main/java/org/olat/course/nodes/members/ui/group/_i18n/i18nBundleMetadata.properties similarity index 100% rename from src/main/java/org/olat/course/editor/formfragments/_i18n/i18nBundleMetadata.properties rename to src/main/java/org/olat/course/nodes/members/ui/group/_i18n/i18nBundleMetadata.properties diff --git a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java index 58037ef4cd065a25102d05359a2c30c090a076a5..f383cb3e4c37c2f17c3eb2c5f545fc0a0c673821 100644 --- a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java +++ b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java @@ -30,10 +30,15 @@ import java.util.List; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.download.DisplayOrDownloadComponent; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.id.context.BusinessControlFactory; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; @@ -55,9 +60,12 @@ import org.springframework.beans.factory.annotation.Autowired; * Initial Date: Jun 16, 2004 * @author gnaegi */ -public class MSCourseNodeRunController extends BasicController { +public class MSCourseNodeRunController extends BasicController implements Activateable2 { private final VelocityContainer myContent; + private DisplayOrDownloadComponent download; + + private String mapperUri; private final boolean showLog; private boolean hasScore, hasPassed, hasComment; private final UserCourseEnvironment userCourseEnv; @@ -132,8 +140,8 @@ public class MSCourseNodeRunController extends BasicController { myContent.contextPut("changelogconfig", courseModule.isDisplayChangeLog()); // Push variables to velocity page - exposeConfigToVC(ureq, config); - exposeUserDataToVC(ureq, userCourseEnv, courseNode); + exposeConfigToVC(ureq); + exposeUserDataToVC(ureq); putInitialPanel(myContent); } @@ -158,6 +166,20 @@ public class MSCourseNodeRunController extends BasicController { return hasComment; } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + String type = entries.get(0).getOLATResourceable().getResourceableTypeName(); + if(type.startsWith("path")) { + if(download != null) { + String path = BusinessControlFactory.getInstance().getPath(entries.get(0)); + String url = mapperUri + "/" + path; + download.triggerFileDownload(url); + } + } + } + /** * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) */ @@ -170,21 +192,22 @@ public class MSCourseNodeRunController extends BasicController { } } - private void exposeConfigToVC(UserRequest ureq, ModuleConfiguration config) { + private void exposeConfigToVC(UserRequest ureq) { + ModuleConfiguration config = courseNode.getModuleConfiguration(); myContent.contextPut(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD, config.get(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD)); myContent.contextPut(MSCourseNode.CONFIG_KEY_HAS_PASSED_FIELD, config.get(MSCourseNode.CONFIG_KEY_HAS_PASSED_FIELD)); myContent.contextPut(MSCourseNode.CONFIG_KEY_HAS_COMMENT_FIELD, config.get(MSCourseNode.CONFIG_KEY_HAS_COMMENT_FIELD)); String infoTextUser = (String) config.get(MSCourseNode.CONFIG_KEY_INFOTEXT_USER); if(StringHelper.containsNonWhitespace(infoTextUser)) { - myContent.contextPut(MSCourseNode.CONFIG_KEY_INFOTEXT_USER, infoTextUser); - myContent.contextPut("in-disclaimer", isPanelOpen(ureq, "disclaimer", true)); + myContent.contextPut(MSCourseNode.CONFIG_KEY_INFOTEXT_USER, infoTextUser); + myContent.contextPut("in-disclaimer", isPanelOpen(ureq, "disclaimer", true)); } myContent.contextPut(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE, AssessmentHelper.getRoundedScore((Float)config.get(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE))); myContent.contextPut(MSCourseNode.CONFIG_KEY_SCORE_MIN, AssessmentHelper.getRoundedScore((Float)config.get(MSCourseNode.CONFIG_KEY_SCORE_MIN))); myContent.contextPut(MSCourseNode.CONFIG_KEY_SCORE_MAX, AssessmentHelper.getRoundedScore((Float)config.get(MSCourseNode.CONFIG_KEY_SCORE_MAX))); } - private void exposeUserDataToVC(UserRequest ureq, UserCourseEnvironment userCourseEnv, PersistentAssessableCourseNode courseNode) { + private void exposeUserDataToVC(UserRequest ureq) { AssessmentEntry assessmentEntry = courseNode.getUserAssessmentEntry(userCourseEnv); if(assessmentEntry == null) { myContent.contextPut("hasPassedValue", Boolean.FALSE); @@ -213,10 +236,14 @@ public class MSCourseNodeRunController extends BasicController { if(courseNode.hasIndividualAsssessmentDocuments()) { List<File> docs = courseNode.getIndividualAssessmentDocuments(userCourseEnv); - String mapperUri = registerCacheableMapper(ureq, null, new DocumentsMapper(docs)); + mapperUri = registerCacheableMapper(ureq, null, new DocumentsMapper(docs)); myContent.contextPut("docsMapperUri", mapperUri); myContent.contextPut("docs", docs); myContent.contextPut("in-assessmentDocuments", isPanelOpen(ureq, "assessmentDocuments", true)); + if(download == null) { + download = new DisplayOrDownloadComponent("", null); + myContent.put("download", download); + } } } } diff --git a/src/main/java/org/olat/course/nodes/ms/_content/run.html b/src/main/java/org/olat/course/nodes/ms/_content/run.html index c0a109a7d8306213d943f2407d20648c6d8f3512..4104256a4ab5f37d03253bc6e9d80f88aed14183 100644 --- a/src/main/java/org/olat/course/nodes/ms/_content/run.html +++ b/src/main/java/org/olat/course/nodes/ms/_content/run.html @@ -156,4 +156,7 @@ #o_togglebox_end() </div> #end +#end +#if($r.available("download")) + $r.render("download") #end \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/pf/ui/PFCoachController.java b/src/main/java/org/olat/course/nodes/pf/ui/PFCoachController.java index 801bced3f9acbf67a210f53899e0fc301694d606..d9701e30875e27c71c487fca7c5a8154bc46d6d4 100644 --- a/src/main/java/org/olat/course/nodes/pf/ui/PFCoachController.java +++ b/src/main/java/org/olat/course/nodes/pf/ui/PFCoachController.java @@ -191,7 +191,7 @@ public class PFCoachController extends FormBasicController implements Controller } else if(source == dropboxTable) { if(event instanceof SelectionEvent) { SelectionEvent se = (SelectionEvent)event; - DropBoxRow currentObject = (DropBoxRow) tableModel.getObject(se.getIndex()); + DropBoxRow currentObject = tableModel.getObject(se.getIndex()); if ("drop.box".equals(se.getCommand())){ doSelectParticipantFolder (ureq, currentObject.getIdentity(), PFView.displayDrop); } else if ("return.box".equals(se.getCommand())){ diff --git a/src/main/java/org/olat/course/nodes/pf/ui/_content/coach.html b/src/main/java/org/olat/course/nodes/pf/ui/_content/coach.html index cf33c5509892fbf3111ab3aa81adc65767207e99..a4e9d0458dae956c6cf75954c5c736078f7ffbec 100644 --- a/src/main/java/org/olat/course/nodes/pf/ui/_content/coach.html +++ b/src/main/java/org/olat/course/nodes/pf/ui/_content/coach.html @@ -1,8 +1,8 @@ -<div class="clearfix"> #if($r.available("single")) $r.render("backLink") - <div class="o_block_bottom">$r.render("single")</div> + <div class="o_sel_pf_participant_folder clearfix o_block_bottom">$r.render("single")</div> #else +<div class="o_sel_pf_participants_list"> #if ($r.available("contextualSubscription")) <div class="clearfix o_block_bottom"> $r.render("contextualSubscription") @@ -12,6 +12,7 @@ #if($hasParticipants) $r.render("buttons") #end -#end </div> +#end + diff --git a/src/main/java/org/olat/course/nodes/pf/ui/_content/participant.html b/src/main/java/org/olat/course/nodes/pf/ui/_content/participant.html index 7a8e73f89fd2c04e5c784ccfe1a836ec2103dbdf..0edb97588c2325a91d11f5faef9995b1bb036fe9 100644 --- a/src/main/java/org/olat/course/nodes/pf/ui/_content/participant.html +++ b/src/main/java/org/olat/course/nodes/pf/ui/_content/participant.html @@ -1,12 +1,4 @@ -<!-- <div class="panel panel-default o_personal"> --> -<!-- <div class="panel-heading">$name $r.translate("drop.box")</div> --> -<!-- <div>$r.translate("drop.info")</div> --> -<!-- <div>$r.render("upload")</div> --> -<!-- </div> --> -<!-- <div class="panel panel-default o_personal"> --> -<!-- <div class="panel-heading">$r.translate("return.box")</div> --> -<!-- <div>$r.translate("return.info")</div> --> -<!-- </div> --> +<div class="o_sel_pf_participant_folder"> #if ($limit) <div class="o_note">$r.translate("limit.count.info", $limit)</div> #end @@ -15,5 +7,6 @@ $r.render("contextualSubscription") #end $r.render("folder") +</div> diff --git a/src/main/java/org/olat/course/nodes/portfolio/PortfolioResultDetailsController.java b/src/main/java/org/olat/course/nodes/portfolio/PortfolioResultDetailsController.java index bf30ca451eaf94fec6fe1b4bddbeb2ea68fc9cb9..0a9ca075bb454bc13d4a1d72c6a0c9024052a69a 100644 --- a/src/main/java/org/olat/course/nodes/portfolio/PortfolioResultDetailsController.java +++ b/src/main/java/org/olat/course/nodes/portfolio/PortfolioResultDetailsController.java @@ -275,7 +275,7 @@ public class PortfolioResultDetailsController extends FormBasicController { binder = portfolioService.getBinderByKey(binder.getKey()); portfolioService.updateBinderUserInformations(binder, getIdentity()); List<AccessRights> rights = portfolioService.getAccessRights(binder, getIdentity()); - BinderSecurityCallback secCallback = BinderSecurityCallbackFactory.getCallbackForCoach(binder, rights); + BinderSecurityCallback secCallback = BinderSecurityCallbackFactory.getCallbackForCourseCoach(binder, rights); BinderConfiguration config = BinderConfiguration.createConfig(binder); BinderController binderCtrl = new BinderController(ureq, getWindowControl(), (TooledStackedPanel)stackPanel, secCallback, binder, config); String displayName = StringHelper.escapeHtml(binder.getTitle()); diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerReturnboxController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerReturnboxController.java index cf820bffd07b3ce9b0fce41d0e0866e573362ff2..b2878c6a5b510d36b52633942e237f8884e41379 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerReturnboxController.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerReturnboxController.java @@ -38,11 +38,11 @@ import org.olat.course.run.userview.UserCourseEnvironment; /** * - * @author Christian Guretzki + * @author Christian Guretzki */ public class ProjectBrokerReturnboxController extends ReturnboxController { - + private Project project; /** @@ -54,13 +54,13 @@ public class ProjectBrokerReturnboxController extends ReturnboxController { * @param userCourseEnv * @param previewMode */ - public ProjectBrokerReturnboxController(UserRequest ureq, WindowControl wControl, + public ProjectBrokerReturnboxController(UserRequest ureq, WindowControl wControl, CourseNode node, UserCourseEnvironment userCourseEnv, boolean previewMode, Project project) { super(ureq, wControl, node, userCourseEnv, previewMode, false); this.project = project; initReturnbox(ureq, wControl, node, userCourseEnv, previewMode); } - + /** * Return returnbox base-path. e.g. course/<COURSE_ID>/returnbox/<NODE_id>/<USER_NAME> * @see org.olat.course.nodes.ta.ReturnboxController#getReturnboxPathFor(org.olat.course.run.environment.CourseEnvironment, org.olat.course.nodes.CourseNode, org.olat.core.id.Identity) @@ -71,9 +71,9 @@ public class ProjectBrokerReturnboxController extends ReturnboxController { } /** - * Return returnbox base-path. e.g. course/<COURSE_ID>/returnbox/<NODE_id> - * To have the path for certain user you must call method 'getReturnboxPathFor' - * + * Return returnbox base-path. e.g. course/<COURSE_ID>/returnbox/<NODE_id> + * To have the path for certain user you must call method 'getReturnboxPathFor' + * * @param project * @param courseEnv * @param cNode @@ -82,5 +82,5 @@ public class ProjectBrokerReturnboxController extends ReturnboxController { public static String getReturnboxBasePathForProject(Project project, CourseEnvironment courseEnv, CourseNode node) { return getReturnboxPathRelToFolderRoot(courseEnv, node) + File.separator + project.getKey(); } - + } diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java index 69b7cbeab3dea4997e7768222b214bec280b44d6..73f25bfe7256a990e90c8a1163cb534eeeaf0d04 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java @@ -76,18 +76,18 @@ import org.olat.group.BusinessGroup; /** * * @author guretzki - * + * */ public class ProjectListController extends BasicController implements GenericEventListener { - + private static final String OPEN_IDENTITY_CMD = "openID"; // List commands private static final String TABLE_ACTION_SHOW_DETAIL = "cmd.show.detail"; private static final String TABLE_ACTION_ACCOUNT_MANAGER = "cmd.account.manager"; private static final String TABLE_ACTION_SELECT = "cmd.select"; private static final String TABLE_ACTION_CANCEL_SELECT = "cmd.cancel.select"; - + private VelocityContainer contentVC; private StackedPanel mainPanel; @@ -100,7 +100,7 @@ public class ProjectListController extends BasicController implements GenericEve private Long courseId; private CourseNode courseNode; private UserCourseEnvironment userCourseEnv; - + private ProjectBrokerModuleConfiguration moduleConfig; private Long projectBrokerId; private int numberOfCustomFieldInTable = 0; @@ -109,7 +109,7 @@ public class ProjectListController extends BasicController implements GenericEve private boolean isParticipantInAnyProject; private CloseableCalloutWindowController calloutCtrl; private Project currentProject; - + private DialogBoxController noDeselectWarning; private final ProjectBrokerMailer projectBrokerMailer; @@ -123,7 +123,7 @@ public class ProjectListController extends BasicController implements GenericEve * @param ne * @param previewMode */ - protected ProjectListController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, CourseNode courseNode, boolean previewMode) { + protected ProjectListController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, CourseNode courseNode, boolean previewMode) { super(ureq, wControl); this.userCourseEnv = userCourseEnv; this.courseNode = courseNode; @@ -132,7 +132,7 @@ public class ProjectListController extends BasicController implements GenericEve projectBrokerManager = CoreSpringFactory.getImpl(ProjectBrokerManager.class); courseId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); moduleConfig = new ProjectBrokerModuleConfiguration(courseNode.getModuleConfiguration()); - + contentVC = createVelocityContainer("project_list"); // set header info with project-broker run mode [accept.automatically.limited , accept.manually.limited etc.] String infoProjectBrokerRunMode = ""; @@ -149,7 +149,7 @@ public class ProjectListController extends BasicController implements GenericEve infoProjectBrokerRunMode = translate("info.projectbroker.runmode.accept.automatically.unlimited" ); } else { infoProjectBrokerRunMode = translate("info.projectbroker.runmode.accept.automatically.limited", Integer.toString(moduleConfig.getNbrParticipantsPerTopic()) ); - } + } } contentVC.contextPut("infoProjectBrokerRunMode", infoProjectBrokerRunMode); mainPanel = new SimpleStackedPanel("projectlist_panel"); @@ -166,7 +166,7 @@ public class ProjectListController extends BasicController implements GenericEve // push title and learning objectives, only visible on intro page contentVC.contextPut("menuTitle", courseNode.getShortTitle()); contentVC.contextPut("displayTitle", courseNode.getLongTitle()); - + projectBrokerId = projectBrokerManager.getProjectBrokerId(cpm, courseNode); if (projectBrokerId == null) { // no project-broker exist => create a new one, happens only once @@ -175,9 +175,9 @@ public class ProjectListController extends BasicController implements GenericEve projectBrokerManager.saveProjectBrokerId(projectBrokerId, cpm, courseNode); getLogger().info("no project-broker exist => create a new one projectBrokerId=" + projectBrokerId); } - + tableController = createTableController(ureq, wControl); - + OLATResourceable projectBroker = projectBrokerManager.getProjectBroker(projectBrokerId); CoordinatorManager.getInstance().getCoordinator().getEventBus().registerFor(this, ureq.getIdentity(), projectBroker); updateProjectListModelOf(tableController, ureq.getIdentity()); @@ -194,10 +194,10 @@ public class ProjectListController extends BasicController implements GenericEve Long resId = ores.getResourceableId(); if (resId.longValue() != 0) { if (isLogDebugEnabled()) logDebug("projectId=" , ores.getResourceableId().toString()); - + Project proj = projectBrokerManager.getProject(ores.getResourceableId()); if (proj != null) { - activateProjectController(proj, ureq); + activateProjectController(proj, ureq); } else { // message not found, do nothing. Load normal start screen logDebug("Invalid projectId=" , ores.getResourceableId().toString()); @@ -210,8 +210,8 @@ public class ProjectListController extends BasicController implements GenericEve putInitialPanel(mainPanel); } - - + + /** * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) */ @@ -260,13 +260,13 @@ public class ProjectListController extends BasicController implements GenericEve updateProjectListModelOf(tableController, urequest.getIdentity()); } else if (pbEditEvent.isCreateEvent() || pbEditEvent.isDeletedEvent()){ mainPanel.popContent(); - updateProjectListModelOf(tableController, urequest.getIdentity()); + updateProjectListModelOf(tableController, urequest.getIdentity()); } } else if (source == noDeselectWarning) { if(DialogBoxUIFactory.isOkEvent(event)){ handleEnrollAction(urequest, currentProject); } - } + } } @@ -291,7 +291,7 @@ public class ProjectListController extends BasicController implements GenericEve List<String> warningButtons = new ArrayList<String>(); warningButtons.add(translate("info.projectbroker.no.deselect.select")); warningButtons.add(translate("info.projectbroker.no.deselect.cancel")); - String message = translate("info.projectbroker.deselect.confirmation",selectedProject.getTitle())+"<br/><div class=\"o_important\">"+translate("info.projectbroker.no.deselect")+"</div>"; + String message = translate("info.projectbroker.deselect.confirmation",selectedProject.getTitle())+"<br/><div class=\"o_important\">"+translate("info.projectbroker.no.deselect")+"</div>"; noDeselectWarning = activateGenericDialog(urequest, translate("info.projectbroker.no.deselect.title"), message, warningButtons, noDeselectWarning); return; } @@ -337,7 +337,7 @@ public class ProjectListController extends BasicController implements GenericEve } private void updateProjectListModelOf(TableController tableCtrl, Identity identity) { - List<Project> projects = new ArrayList<Project>(projectBrokerManager.getProjectListBy(projectBrokerId)); + List<Project> projects = new ArrayList<Project>(projectBrokerManager.getProjectListBy(projectBrokerId)); nbrSelectedProjects = projectBrokerManager.getNbrSelectedProjects(identity, projects); isParticipantInAnyProject = projectBrokerManager.isParticipantInAnyProject( identity, projects); projectListTableModel = new ProjectListTableModel(projects, identity, getTranslator(), moduleConfig, numberOfCustomFieldInTable, numberOfEventInTable, nbrSelectedProjects, isParticipantInAnyProject); @@ -353,22 +353,22 @@ public class ProjectListController extends BasicController implements GenericEve ArrayList<Link> identLinks = new ArrayList<Link>(allIdents.size()); for (Identity identity : allIdents) { String last = identity.getUser().getProperty(UserConstants.LASTNAME, getLocale()); - String first = identity.getUser().getProperty(UserConstants.FIRSTNAME, getLocale()); - String linkName = last + " " + first; - + String first = identity.getUser().getProperty(UserConstants.FIRSTNAME, getLocale()); + String linkName = last + " " + first; + Link idLink = LinkFactory.createCustomLink(linkName, OPEN_IDENTITY_CMD, linkName, Link.NONTRANSLATED, identityVC, this); idLink.setUserObject(identity); identLinks.add(idLink); } - identityVC.contextPut("identLinks", identLinks); - + identityVC.contextPut("identLinks", identLinks); + int row = tableEvent.getRowId(); String targetDomID = ProjectManagerColumnRenderer.PROJECTMANAGER_COLUMN_ROW_IDENT + row; String title = translate("projectlist.callout.title", projectAt.getTitle()); removeAsListenerAndDispose(calloutCtrl); calloutCtrl = new CloseableCalloutWindowController(urequest, getWindowControl(), identityVC, targetDomID, title, true, null); calloutCtrl.activate(); - listenTo(calloutCtrl); + listenTo(calloutCtrl); } else if (projectAt.getProjectLeaders().size() == 1) { // no callout, if its only one user Identity leader = projectAt.getProjectLeaders().get(0); @@ -380,7 +380,7 @@ public class ProjectListController extends BasicController implements GenericEve String businessPath = "[HomePage:" + ident.getKey() + "]"; NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); } - + private void activateProjectController(Project project, UserRequest urequest) { removeAsListenerAndDispose(projectController); @@ -390,28 +390,28 @@ public class ProjectListController extends BasicController implements GenericEve } /** - * + * * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) */ protected void doDispose() { // } - + private TableController createTableController(final UserRequest ureq, WindowControl wControl) { numberOfCustomFieldInTable = 0; - numberOfEventInTable = 0; + numberOfEventInTable = 0; TableGuiConfiguration tableConfig = new TableGuiConfiguration(); tableConfig.setTableEmptyMessage(translate("projectlist.no.projects")); tableConfig.setPreferencesOffered(true, "projectbrokerList"); tableConfig.setShowAllLinkEnabled(false);// Do not allow show all because many entries takes too long to render - + removeAsListenerAndDispose(tableController); tableController = new TableController(tableConfig, ureq, wControl, this.getTranslator(), true); listenTo(tableController); - + int dataColumn = 0; tableController.addColumnDescriptor(new DefaultColumnDescriptor("projectlist.tableheader.title", dataColumn++, TABLE_ACTION_SHOW_DETAIL, getLocale())); - + CustomRenderColumnDescriptor projectManagerDescriptor = new CustomRenderColumnDescriptor("projectlist.tableheader.account.manager", dataColumn++, TABLE_ACTION_ACCOUNT_MANAGER, ureq.getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new ProjectManagerColumnRenderer()){ /** @@ -430,7 +430,7 @@ public class ProjectListController extends BasicController implements GenericEve Object val = getModelData(row); String rowSt = Integer.toString(row); // to get info about row in Renderer! getCustomCellRenderer().render(sb, renderer, val, getLocale(), getAlignment(), rowSt); - } + } }; tableController.addColumnDescriptor(projectManagerDescriptor); // Custom-Fields @@ -441,27 +441,44 @@ public class ProjectListController extends BasicController implements GenericEve numberOfCustomFieldInTable++; DefaultColumnDescriptor columnDescriptor = new DefaultColumnDescriptor(customField.getName(), dataColumn++,null, getLocale()); columnDescriptor.setTranslateHeaderKey(false); - tableController.addColumnDescriptor(columnDescriptor); + tableController.addColumnDescriptor(columnDescriptor); } } // Project Events for (Project.EventType eventType : Project.EventType.values()) { if (moduleConfig.isProjectEventEnabled(eventType) && moduleConfig.isProjectEventTableViewEnabled(eventType)) { numberOfEventInTable ++; - tableController.addColumnDescriptor(new CustomRenderColumnDescriptor("projectlist.tableheader.event." + eventType.getI18nKey(), dataColumn++, + tableController.addColumnDescriptor(new CustomRenderColumnDescriptor("projectlist.tableheader.event." + eventType.getI18nKey(), dataColumn++, null, getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new ProjectEventColumnRenderer())); } } - - tableController.addColumnDescriptor(new CustomRenderColumnDescriptor("projectlist.tableheader.state", dataColumn++, + + tableController.addColumnDescriptor(new CustomRenderColumnDescriptor("projectlist.tableheader.state", dataColumn++, null, ureq.getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new ProjectStateColumnRenderer())); - tableController.addColumnDescriptor(new DefaultColumnDescriptor("projectlist.tableheader.numbers", dataColumn++, null, getLocale())); - + tableController.addColumnDescriptor(new DefaultColumnDescriptor("projectlist.tableheader.numbers", dataColumn++, null, getLocale()) { + @Override + public int compareTo(int rowa, int rowb) { + Object a = table.getTableDataModel().getValueAt(rowa, dataColumn); + Object b = table.getTableDataModel().getValueAt(rowb, dataColumn); + if (a == null || b == null) { + boolean bb = (b == null); + return (a == null) ? (bb ? 0: -1) : (bb ? 1: 0); + } + try { + Long la = new Long((String)a); + Long lb = new Long((String)b); + return la.compareTo(lb); + } catch (NumberFormatException e) { + return super.compareTo(rowa, rowb); + } + } + }); + String selectCmd = userCourseEnv.isCourseReadOnly() ? null : TABLE_ACTION_SELECT; - tableController.addColumnDescriptor(new BooleanColumnDescriptor("projectlist.tableheader.select", dataColumn++, selectCmd, + tableController.addColumnDescriptor(new BooleanColumnDescriptor("projectlist.tableheader.select", dataColumn++, selectCmd, translate("table.action.select"), "-" )); String cancelCmd = userCourseEnv.isCourseReadOnly() ? null : TABLE_ACTION_CANCEL_SELECT; - tableController.addColumnDescriptor(new BooleanColumnDescriptor("projectlist.tableheader.cancel.select", dataColumn++, cancelCmd, + tableController.addColumnDescriptor(new BooleanColumnDescriptor("projectlist.tableheader.cancel.select", dataColumn++, cancelCmd, translate("projectlist.tableheader.cancel.select"), "-" )); return tableController; @@ -469,9 +486,9 @@ public class ProjectListController extends BasicController implements GenericEve /** - * Is called when a project is deleted via group-management + * Is called when a project is deleted via group-management * (ProjectBrokerManager.deleteGroupDataFor(BusinessGroup group) , DeletableGroupData-interface) - * + * * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event) */ @Override diff --git a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManager.java b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManager.java index e55acf81f0a3b83a27cb3359ce144ea08749b75a..e1ec43b7311fdb95edc5f30087bf51b934848743 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManager.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectBrokerManager.java @@ -47,27 +47,27 @@ public interface ProjectBrokerManager { public List<Project> getProjectListBy(Long projectBrokerId); public List<Project> getProjectsWith(BusinessGroup group); - - + + /** * Returns a project-broker object for certain project-broker-ID. * @param projectBrokerId * @return */ public ProjectBroker getProjectBroker(Long projectBrokerId); - + /** - * Creates a new project-broker and save it. + * Creates a new project-broker and save it. * @return */ public ProjectBroker createAndSaveProjectBroker(); - + /** * Update and save an existing project. * @param project */ public void updateProject(Project project); - + /** * Create and save a new project. * @param projectTitle @@ -122,11 +122,11 @@ public interface ProjectBrokerManager { * @param project * @param moduleConfig * @param nbrSelectedProjects - * @param isParticipantInAnyProject + * @param isParticipantInAnyProject * @return */ public boolean canBeProjectSelectedBy(Identity identity, Project project, ProjectBrokerModuleConfiguration moduleConfig, int nbrSelectedProjects, boolean isParticipantInAnyProject); - + /** * Return true when the project can be de-selected by an identity. * @param identity @@ -171,17 +171,17 @@ public interface ProjectBrokerManager { * @param cNode */ public void saveAttachedFile(Project project, String fileName, VFSLeaf uploadedItem, CourseEnvironment courseEnv, CourseNode cNode); - + /** - * Return true when the custom-field value is one of possible-values (drop-down-mode) or when it could be any value (input field). + * Return true when the custom-field value is one of possible-values (drop-down-mode) or when it could be any value (input field). * @param value * @param string * @return */ public boolean isCustomFieldValueValid(String value, String string); - + /** - * Get attachment-file relative path. + * Get attachment-file relative path. * E.g. course/<COURSE_ID>/projectbroker_attach/<COURSE_NODE>/<PROJECT_ID> * @param project * @param courseEnv @@ -228,7 +228,7 @@ public interface ProjectBrokerManager { * @return */ public boolean existProjectName(Long projectBrokerId, String newProjectTitle); - + /** * Get attachment-folder relative path (without project-id). THis path can be used to delete all * attachment-file for certain project-broker. @@ -240,7 +240,7 @@ public interface ProjectBrokerManager { public String getAttachmentBasePathRelToFolderRoot(CourseEnvironment courseEnvironment, CourseNode courseNode); /** - * Get list of selected projects for certain identity. + * Get list of selected projects for certain identity. * @param identity * @param projectBrokerId * @return @@ -255,7 +255,7 @@ public interface ProjectBrokerManager { public Project getProject(Long projectId); /** - * Get list of coached projects for certain identity. + * Get list of coached projects for certain identity. * @param identity * @param projectBrokerId * @return @@ -268,5 +268,5 @@ public interface ProjectBrokerManager { * @return */ public boolean existsProject(Long projectKey); - + } diff --git a/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java b/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java index 868359e658a5a0c0749eb2c9f8f3f3760900f848..ba1c5bb94d4cd5d1276d3a7372b254f8e2948bad 100644 --- a/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java +++ b/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java @@ -63,6 +63,7 @@ import org.olat.fileresource.FileResourceManager; import org.olat.instantMessaging.CloseInstantMessagingEvent; import org.olat.instantMessaging.InstantMessagingService; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.modules.scorm.ScormAPICallback; import org.olat.modules.scorm.ScormAPIandDisplayController; import org.olat.modules.scorm.ScormCPManifestTreeModel; @@ -315,7 +316,7 @@ public class ScormRunController extends BasicController implements ScormAPICallb //increment user attempts only once! if(!config.getBooleanSafe(ScormEditController.CONFIG_ADVANCESCORE, true) || !config.getBooleanSafe(ScormEditController.CONFIG_ATTEMPTSDEPENDONSCORE, false)) { - scormNode.incrementUserAttempts(userCourseEnv); + scormNode.incrementUserAttempts(userCourseEnv, Role.user); attemptsIncremented = true; } diff --git a/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java index 1d8cdb67b42e200833c60833a18e975f714bcc02..9f3777f29c7ef77ab14b33e11bccc88dd248d018 100644 --- a/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java +++ b/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java @@ -97,7 +97,7 @@ public class STCourseNodeRunController extends BasicController { myContent = createVelocityContainer("run"); myContent.setDomReplacementWrapperRequired(false); // we provide our own DOM replacement ID - if (se != null){ + if (se != null && (stCourseNode.hasScoreConfigured() || stCourseNode.hasPassedConfigured())) { HighScoreRunController highScoreCtr = new HighScoreRunController(ureq, wControl, userCourseEnv, stCourseNode); if (highScoreCtr.isViewHighscore()) { Component highScoreComponent = highScoreCtr.getInitialComponent(); @@ -175,10 +175,12 @@ public class STCourseNodeRunController extends BasicController { myContent.contextPut("hasScore", new Boolean(stCourseNode.hasScoreConfigured())); myContent.contextPut("hasPassed", new Boolean(stCourseNode.hasPassedConfigured())); - CourseConfig cc = userCourseEnv.getCourseEnvironment().getCourseConfig(); - if((cc.isEfficencyStatementEnabled() || cc.isCertificateEnabled()) - && userCourseEnv.hasEfficiencyStatementOrCertificate(false)) { - certificationLink = LinkFactory.createButton("certification", myContent, this); + if(stCourseNode.hasScoreConfigured() || stCourseNode.hasPassedConfigured()) { + CourseConfig cc = userCourseEnv.getCourseEnvironment().getCourseConfig(); + if((cc.isEfficencyStatementEnabled() || cc.isCertificateEnabled()) + && userCourseEnv.hasEfficiencyStatementOrCertificate(false)) { + certificationLink = LinkFactory.createButton("certification", myContent, this); + } } } diff --git a/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java b/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java index 9c880aac7ded874f16f5c9bc801c9ce4395e974d..5bd7ee684b5dd20f25e9bc8c2b12b0da5fe46947 100644 --- a/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java +++ b/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java @@ -64,6 +64,7 @@ import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.properties.Property; /** @@ -240,19 +241,19 @@ public class ConvertToGTACourseNode { UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course); Float score = assessmentData.getScore() == null ? null : assessmentData.getScore().floatValue(); ScoreEvaluation scoreEval = new ScoreEvaluation(score, assessmentData.getPassed()); - assessmentMgr.saveScoreEvaluation(gtaNode, null, assessedIdentity, scoreEval, userCourseEnv, false); + assessmentMgr.saveScoreEvaluation(gtaNode, null, assessedIdentity, scoreEval, userCourseEnv, false, Role.auto); //set graded Task task = gtaManager.getTask(assessedIdentity, taskList); if(task == null) { gtaManager.createTask(null, taskList, TaskProcess.graded, null, assessedIdentity, gtaNode); } else { - gtaManager.updateTask(task, TaskProcess.graded, gtaNode); + gtaManager.updateTask(task, TaskProcess.graded, gtaNode, Role.auto); } } if(assessmentData.getAttempts() != null) { - assessmentMgr.saveNodeAttempts(gtaNode, null, assessedIdentity, assessmentData.getAttempts().intValue()); + assessmentMgr.saveNodeAttempts(gtaNode, null, assessedIdentity, assessmentData.getAttempts().intValue(), Role.auto); } if(StringHelper.containsNonWhitespace(assessmentData.getCoachComment())) { @@ -366,7 +367,7 @@ public class ConvertToGTACourseNode { if(task == null) { gtaManager.createTask(null, taskList, process, null, assessedIdentity, gtaNode); } else { - gtaManager.updateTask(task, process, gtaNode); + gtaManager.updateTask(task, process, gtaNode, Role.auto); } } diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxController.java b/src/main/java/org/olat/course/nodes/ta/DropboxController.java index 22e7892d212ea58d922ac12278d925149bff339f..0e4e4b9794c4fa51664ff01672d2719527047f39 100644 --- a/src/main/java/org/olat/course/nodes/ta/DropboxController.java +++ b/src/main/java/org/olat/course/nodes/ta/DropboxController.java @@ -81,6 +81,7 @@ import org.olat.course.nodes.TACourseNode; import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; /** * Initial Date: 02.09.2004 @@ -361,14 +362,7 @@ public class DropboxController extends BasicController { // update attempts counter for this user: one file - one attempts AssessableCourseNode acn = (AssessableCourseNode) node; - /*AssessmentEvaluation eval = acn.getUserScoreEvaluation(userCourseEnv); - if(eval.getAssessmentStatus() == null || eval.getAssessmentStatus() == AssessmentEntryStatus.notStarted) { - eval = new AssessmentEvaluation(eval, AssessmentEntryStatus.inProgress); - acn.updateUserScoreEvaluation(eval, userCourseEnv, getIdentity(), true); - } else { - acn.incrementUserAttempts(userCourseEnv); - }*/ - acn.incrementUserAttempts(userCourseEnv); + acn.incrementUserAttempts(userCourseEnv, Role.user); // log entry for this file UserNodeAuditManager am = userCourseEnv.getCourseEnvironment().getAuditManager(); diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java index a23dc5fa6b1995990bff15fd852faf6b71f21f84..fdd08ceae773a451f8937dd5e95d282e5eecfa44 100644 --- a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java +++ b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java @@ -80,6 +80,7 @@ import org.olat.course.properties.CoursePropertyManager; import org.olat.course.run.scoring.AssessmentEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.properties.Property; import org.olat.user.UserManager; @@ -300,7 +301,7 @@ public class DropboxScoringViewController extends BasicController { AssessmentEvaluation eval = acn.getUserScoreEvaluation(userCourseEnv); if(eval.getAssessmentStatus() == null || eval.getAssessmentStatus() == AssessmentEntryStatus.notStarted) { eval = new AssessmentEvaluation(eval, AssessmentEntryStatus.inProgress); - acn.updateUserScoreEvaluation(eval, userCourseEnv, coach, false); + acn.updateUserScoreEvaluation(eval, userCourseEnv, coach, false, Role.coach); } } @@ -339,7 +340,7 @@ public class DropboxScoringViewController extends BasicController { } if(eval.getAssessmentStatus() == null || eval.getAssessmentStatus() == AssessmentEntryStatus.notStarted) { eval = new AssessmentEvaluation(eval, AssessmentEntryStatus.inProgress); - acn.updateUserScoreEvaluation(eval, userCourseEnv, getIdentity(), false); + acn.updateUserScoreEvaluation(eval, userCourseEnv, getIdentity(), false, Role.coach); fireEvent(ureq, Event.CHANGED_EVENT); } } diff --git a/src/main/java/org/olat/course/nodes/ta/TaskController.java b/src/main/java/org/olat/course/nodes/ta/TaskController.java index 994143f34ce0d395749cb7046749844207f5771c..24c4b58a902c381e21d395b3a6c42088e0b08e2e 100644 --- a/src/main/java/org/olat/course/nodes/ta/TaskController.java +++ b/src/main/java/org/olat/course/nodes/ta/TaskController.java @@ -66,6 +66,7 @@ import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.scoring.AssessmentEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.properties.Property; @@ -352,7 +353,7 @@ public class TaskController extends BasicController { AssessmentEvaluation eval = node.getUserScoreEvaluation(userCourseEnv); if(eval.getAssessmentStatus() == null || eval.getAssessmentStatus() == AssessmentEntryStatus.notStarted) { eval = new AssessmentEvaluation(eval, AssessmentEntryStatus.inProgress); - node.updateUserScoreEvaluation(eval, userCourseEnv, getIdentity(), false); + node.updateUserScoreEvaluation(eval, userCourseEnv, getIdentity(), false, Role.user); } } diff --git a/src/main/java/org/olat/course/reminder/ui/CourseReminderEditController.java b/src/main/java/org/olat/course/reminder/ui/CourseReminderEditController.java index e213a724c161d6c44210b2b0c0b71cb495d805f4..ce7d48fc0174e173a0e3897df3dc7310d8fb1e71 100644 --- a/src/main/java/org/olat/course/reminder/ui/CourseReminderEditController.java +++ b/src/main/java/org/olat/course/reminder/ui/CourseReminderEditController.java @@ -66,6 +66,7 @@ public class CourseReminderEditController extends FormBasicController { private final String[] typeKeys; private final String[] typeValues; + private TextElement subjectEl; private RichTextElement emailEl; private TextElement descriptionEl; private FormLayoutContainer rulesCont; @@ -113,6 +114,7 @@ public class CourseReminderEditController extends FormBasicController { String desc = reminder.getDescription(); descriptionEl = uifactory.addTextElement("reminder.description", "reminder.description", 128, desc, generalCont); + descriptionEl.setMandatory(true); descriptionEl.setElementCssClass("o_sel_course_reminder_desc"); String sendTime = getSendTimeDescription(); @@ -147,12 +149,19 @@ public class CourseReminderEditController extends FormBasicController { FormLayoutContainer contentCont = FormLayoutContainer.createVerticalFormLayout("contents", getTranslator()); contentCont.setRootForm(mainForm); formLayout.add(contentCont); + + //email subject + String subject = reminder.getEmailSubject(); + subjectEl = uifactory.addTextElement("reminder.subject", "reminder.subject", 128, subject, contentCont); + subjectEl.setMandatory(true); + subjectEl.setElementCssClass("o_sel_course_reminder_subject"); String emailContent = reminder == null ? null : reminder.getEmailBody(); if(!StringHelper.containsNonWhitespace(emailContent)) { emailContent = translate("reminder.def.body"); } emailEl = uifactory.addRichTextElementForStringDataMinimalistic("email.content", "email.content", emailContent, 10, 60, contentCont, getWindowControl()); + emailEl.setMandatory(true); String buttonPage = velocity_root + "/edit_rules_buttons.html"; FormLayoutContainer buttonLayout = FormLayoutContainer.createCustomFormLayout("buttons", getTranslator(), buttonPage); @@ -230,6 +239,12 @@ public class CourseReminderEditController extends FormBasicController { descriptionEl.setErrorKey("form.mandatory.hover", null); allOk &= false; } + + subjectEl.clearError(); + if(!StringHelper.containsNonWhitespace(subjectEl.getValue())) { + subjectEl.setErrorKey("form.mandatory.hover", null); + allOk &= false; + } emailEl.clearError(); if(!StringHelper.containsNonWhitespace(emailEl.getValue())) { @@ -328,7 +343,10 @@ public class CourseReminderEditController extends FormBasicController { String configuration = reminderManager.toXML(rules); reminder.setConfiguration(configuration); - + + String emailSubject = subjectEl.getValue(); + reminder.setEmailSubject(emailSubject); + String emailBody = emailEl.getValue(); reminder.setEmailBody(emailBody); diff --git a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties index 710f47e1e259dfd3dea1c2241702d3b1b09c7215..59893882d094e9c69e935af28f6afc1dfc85f679 100644 --- a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties @@ -23,7 +23,8 @@ new.reminder=Neue Erinnerung passed=Bestanden points=Punkte reminder.def.body=<p>Liebe(r) $firstname $lastname</p><p>Sie haben sich in den Kurs "$coursename" eingetragen. Jetzt w\u00E4re ein guter Zeitpunkt diesen zu besuchen\!</p><p>$courseurl</p><p>Viele Gr\u00FCsse</p> -reminder.description=Beschreibung +reminder.description=Beschreibung (nur für Autor) +reminder.subject=E-Mail-Betreff reminder.id=ID reminder.resend=Erinnerung wurde erfolgreich geschickt. reminders=Erinnerungen diff --git a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties index 288c4494183d4f11689fe0d89ab6b847656e7307..1f11ae1a987c7baa8bd14218551cc5bdf74880f6 100644 --- a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties @@ -23,7 +23,8 @@ new.reminder=New reminder passed=Passed points=Points reminder.def.body=<p>Dear $firstname $lastname</p><p>You are registered in the course "$coursename". Now would be a good time to view it!</p><p>$courseurl</p><p>Best regards</p> -reminder.description=Description +reminder.description=Description (only for author) +reminder.subject=E-mail subject reminder.id=ID reminder.resend=Reminder was successfully sent. reminders=Reminders diff --git a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_fr.properties index ab158e5fa75892710bc329c5f0aca0d911cbae6e..e47e474de531cddd4c5999fc82238486030535b0 100644 --- a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Sun Nov 08 12:47:31 CET 2015 +#Tue Aug 15 17:28:32 CEST 2017 add.reminder=Cr\u00E9er un rappel add.rule=+ course.role.all=Membre @@ -26,6 +26,7 @@ reminder.def.body=<p>Ch\u00E8re(er) $firstname $lastname</p><p>Vous \u00EAtes in reminder.description=Description reminder.id=ID reminder.resend=Les rappels ont \u00E9t\u00E9 envoy\u00E9 avec succ\u00E8s. +reminder.subject=Object du courriel reminders=Rappels reminders.intro=Avec la fonction de rappel, vous pouvez facilement envoyer des rappels par courriel aux participants de votre cours. Les e-mails seront envoy\u00E9s d\u00E8s que les r\u00E8gles que vous aurez d\u00E9finies sont v\u00E9rifi\u00E9es, par exemple un jour avant un certain test pour l'utilisateur qui n'a pas encore passer le test. S\u00E9lectionnez "$\:add.reminder" pour cr\u00E9er un nouveau rappel. resend=Renvoyer diff --git a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_pt_BR.properties index a16cc318d9d51e27268e097e34383a23b30ade19..e289fc1e62f3696ca9c404166e7af4f4e3e8537b 100644 --- a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Thu Apr 28 23:21:36 CEST 2016 +#Tue Sep 05 23:26:01 CEST 2017 add.reminder=Adicionar lembrete add.rule=+ course.role.all=Membros @@ -26,6 +26,7 @@ reminder.def.body=<p>Caro $firstname $lastname</p><p>Voc\u00EA est\u00E1 registr reminder.description=Descri\u00E7\u00E3o reminder.id=ID reminder.resend=Lembrete foi enviado com sucesso. +reminder.subject=Assunto do Email reminders=Lembretes reminders.intro=Com a fun\u00E7\u00E3o lembrete voc\u00EA pode facilmente enviar lembretes de e-mail para os participantes do curso. Os e-mails s\u00E3o enviados assim que as regras configuradas por voc\u00EA acontecerem, por exemplo, um dia antes de um determinado teste quando o usu\u00E1rio tiver passado no teste ainda. Selecione "$\:add.reminder" para come\u00E7ar criando um novo lembrete. resend=Reenviar diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java index 3632702891d2af53ed8963236cd499c448ad4e18..718d8ff4e2560cdb2d5284319afe64c18b707efb 100644 --- a/src/main/java/org/olat/course/run/CourseRuntimeController.java +++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java @@ -138,6 +138,7 @@ import org.olat.repository.model.RepositoryEntrySecurity; import org.olat.repository.ui.RepositoryEntryLifeCycleChangeController; import org.olat.repository.ui.RepositoryEntryRuntimeController; import org.olat.resource.OLATResource; +import org.olat.search.SearchModule; import org.olat.search.SearchServiceUIFactory; import org.olat.search.SearchServiceUIFactory.DisplayOption; import org.olat.search.service.QuickSearchEvent; @@ -219,6 +220,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im private InstantMessagingModule imModule; @Autowired private CourseDBManager courseDBManager; + @Autowired + private SearchModule searchModule; public CourseRuntimeController(UserRequest ureq, WindowControl wControl, RepositoryEntry re, RepositoryEntrySecurity reSecurity, RuntimeControllerCreator runtimeControllerCreator, @@ -787,9 +790,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im toolbarPanel.addTool(glossary); } - if(!assessmentLock && lectureModule.isEnabled() - //check the configuration enable the lectures and the user is a teacher - && lectureService.hasLecturesAsTeacher(getRepositoryEntry(), getIdentity())) { + if(!assessmentLock && isLecturesLinkEnabled()) { lecturesLink = LinkFactory.createToolLink("command.lectures", translate("command.lectures"), this, "o_icon_lecture"); toolbarPanel.addTool(lecturesLink); } @@ -804,13 +805,25 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im } // add course search to toolbox - boolean isSearchEnabled = !assessmentLock && !isGuestOnly; + boolean isSearchEnabled = !assessmentLock && searchModule.isSearchAllowed(roles); if (isSearchEnabled) { searchLink = LinkFactory.createToolLink("coursesearch", translate("command.coursesearch"), this, "o_icon_search"); searchLink.setVisible(cc.isCourseSearchEnabled()); toolbarPanel.addTool(searchLink); } - + } + + //check the configuration enable the lectures and the user is a teacher + private boolean isLecturesLinkEnabled() { + if(lectureModule.isEnabled()) { + if(reSecurity.isEntryAdmin()) { + return lectureService.isRepositoryEntryLectureEnabled(getRepositoryEntry()); + } else { + //check the configuration enable the lectures and the user is a teacher + return lectureService.hasLecturesAsTeacher(getRepositoryEntry(), getIdentity()); + } + } + return false; } @Override @@ -1090,9 +1103,22 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im } else if("Reminders".equalsIgnoreCase(type) || "RemindersLogs".equalsIgnoreCase(type)) { doReminders(ureq); } else if("Lectures".equalsIgnoreCase(type)) { - doLectures(ureq); + Activateable2 lectures = doLectures(ureq); + if(lectures != null) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + lectures.activate(ureq, subEntries, entries.get(0).getTransientState()); + } } else if("LectureBlock".equalsIgnoreCase(type)) { - doLectures(ureq).activate(ureq, entries, state); + Activateable2 lectures = doLectures(ureq); + if(lectures != null) { + lectures.activate(ureq, entries, state); + } + } else if("LecturesAdmin".equalsIgnoreCase(type)) { + Activateable2 lecturesAdmin = doLecturesAdmin(ureq); + if(lecturesAdmin != null) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + lecturesAdmin.activate(ureq, subEntries, entries.get(0).getTransientState()); + } } else if("MembersMgmt".equalsIgnoreCase(type)) { Activateable2 members = doMembers(ureq); if(members != null) { @@ -1376,21 +1402,25 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im } } - private void doLecturesAdmin(UserRequest ureq) { + private LectureRepositoryAdminController doLecturesAdmin(UserRequest ureq) { if(delayedClose == Delayed.lecturesAdmin || requestForClose(ureq)) { if (reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR)) { removeCustomCSS(); - OLATResourceable ores = OresHelper.createOLATResourceableType("lecturesAdmin"); + OLATResourceable ores = OresHelper.createOLATResourceableType("LecturesAdmin"); WindowControl swControl = addToHistory(ureq, ores, null); - LectureRepositoryAdminController ctrl = new LectureRepositoryAdminController(ureq, swControl, getRepositoryEntry()); + LectureRepositoryAdminController ctrl = new LectureRepositoryAdminController(ureq, swControl, toolbarPanel, getRepositoryEntry()); listenTo(ctrl); lecturesAdminCtrl = pushController(ureq, translate("command.options.lectures.admin"), ctrl); setActiveTool(lecturesAdminLink); currentToolCtr = lecturesAdminCtrl; + return lecturesAdminCtrl; + } else { + return null; } } else { delayedClose = Delayed.lecturesAdmin; + return null; } } diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_fr.properties index 2076a46fcfdfb0b571a4afc7226a297b882d467e..1558dba54f2c93022ddc6a613661926103a8bbba 100644 --- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Wed Mar 08 11:30:12 CET 2017 +#Sun Aug 27 16:08:10 CEST 2017 command.access=Configuration d'acc\u00E8s command.assessment.mode=Mode d'\u00E9valuation command.bookmark=Ajouter aux favoris @@ -20,6 +20,7 @@ command.glossary.on=activ\u00E9 command.glossary.on.alt=Afficher les termes du glossaire dans le contenu didactique command.glossary.open=Ouvrir le glossaire dans une fen\u00EAtre s\u00E9par\u00E9e command.layout=Disposition +command.lectures=Cours blocs command.next=Aller \u00E0 la page suivante command.openarchiver=Archivage des donn\u00E9es command.openassessment=Outil d'\u00E9valuation @@ -33,6 +34,7 @@ command.opensurveystatistic=Statistique des sondages command.openteststatistic=Statistique des tests command.options=Options command.options.certificates=Attestation de performances +command.options.lectures.admin=Cours blocs et absences command.options.reminders=Rappel command.personalnote=Notes command.previous=Aller \u00E0 la page pr\u00E9c\u00E9dente diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_pt_BR.properties index a9c5091c2348e8ab35732390e1a446c80467d73d..02c39dedf23cd031b643df41c44c0875360c823e 100644 --- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Thu Mar 16 22:33:36 CET 2017 +#Tue Sep 05 23:26:15 CEST 2017 command.access=Configura\u00E7\u00E3o de acesso command.assessment.mode=Modo Teste command.bookmark=Marcar como favorito @@ -20,6 +20,7 @@ command.glossary.on=On command.glossary.on.alt=Termos do gloss\u00E1rio em destaque no conte\u00FAdo de aprendizado command.glossary.open=Abrir gloss\u00E1rio em uma nova janela command.layout=Layout +command.lectures=Aulas command.next=Ir para pr\u00F3xima p\u00E1gina command.openarchiver=Ferramenta para arquivar command.openassessment=Ferramenta de avalia\u00E7\u00E3o @@ -33,6 +34,7 @@ command.opensurveystatistic=Estat\u00EDsticas de Pesquisa command.openteststatistic=Estat\u00EDsticas de Test command.options=Op\u00E7\u00F5es command.options.certificates=Comprovante de conclus\u00E3o +command.options.lectures.admin=Aulas e Aus\u00EAncias (faltas) command.options.reminders=Lembretes command.personalnote=Notas pessoais command.previous=Ir para p\u00E1gina anterior diff --git a/src/main/java/org/olat/course/run/preview/PreviewAssessmentManager.java b/src/main/java/org/olat/course/run/preview/PreviewAssessmentManager.java index b165328516dc155de304b12df1c393d4f2891125..3397f8f13a36c2e77b3739decc7b412d7994b789 100644 --- a/src/main/java/org/olat/course/run/preview/PreviewAssessmentManager.java +++ b/src/main/java/org/olat/course/run/preview/PreviewAssessmentManager.java @@ -44,6 +44,7 @@ import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; /** @@ -103,7 +104,7 @@ final class PreviewAssessmentManager extends BasicManager implements AssessmentM * @see org.olat.course.assessment.AssessmentManager#saveNodeAttempts(org.olat.course.nodes.CourseNode, org.olat.core.id.Identity, org.olat.core.id.Identity, java.lang.Integer) */ @Override - public void saveNodeAttempts(CourseNode courseNode, Identity identity, Identity assessedIdentity, Integer attempts) { + public void saveNodeAttempts(CourseNode courseNode, Identity identity, Identity assessedIdentity, Integer attempts, Role by) { nodeAttempts.put(courseNode.getIdent(), attempts); } @@ -150,7 +151,7 @@ final class PreviewAssessmentManager extends BasicManager implements AssessmentM * @see org.olat.course.assessment.AssessmentManager#incrementNodeAttempts(org.olat.course.nodes.CourseNode, org.olat.core.id.Identity) */ @Override - public void incrementNodeAttempts(CourseNode courseNode, Identity identity, UserCourseEnvironment userCourseEnvironment) { + public void incrementNodeAttempts(CourseNode courseNode, Identity identity, UserCourseEnvironment userCourseEnvironment, Role by) { Integer attempts = nodeAttempts.get(courseNode.getIdent()); if (attempts == null) attempts = new Integer(0); int iAttempts = attempts.intValue(); @@ -164,7 +165,12 @@ final class PreviewAssessmentManager extends BasicManager implements AssessmentM */ @Override public void incrementNodeAttemptsInBackground(CourseNode courseNode, Identity identity, UserCourseEnvironment userCourseEnvironment) { - incrementNodeAttempts(courseNode, identity, userCourseEnvironment); + incrementNodeAttempts(courseNode, identity, userCourseEnvironment, Role.auto); + } + + @Override + public void updateLastModifications(CourseNode courseNode, Identity assessedIdentity, UserCourseEnvironment userCourseEnvironment, Role by) { + // } /** @@ -263,13 +269,13 @@ final class PreviewAssessmentManager extends BasicManager implements AssessmentM */ @Override public void saveScoreEvaluation(AssessableCourseNode courseNode, Identity identity, Identity assessedIdentity, ScoreEvaluation scoreEvaluation, - UserCourseEnvironment userCourseEnvironment, boolean incrementUserAttempts) { + UserCourseEnvironment userCourseEnvironment, boolean incrementUserAttempts, Role by) { saveNodeScore(courseNode, scoreEvaluation.getScore()); saveNodePassed(courseNode, scoreEvaluation.getPassed()); saveAssessmentID(courseNode, scoreEvaluation.getAssessmentID()); if(incrementUserAttempts) { - incrementNodeAttempts(courseNode, identity, userCourseEnvironment); + incrementNodeAttempts(courseNode, identity, userCourseEnvironment, by); } } diff --git a/src/main/java/org/olat/course/run/preview/PreviewIdentity.java b/src/main/java/org/olat/course/run/preview/PreviewIdentity.java index 8ec50a0f737f1eec21ca0b9b9db9f7fb92a666fd..f1053729bc1493ea75372796e06cf05c03d1e3b3 100644 --- a/src/main/java/org/olat/course/run/preview/PreviewIdentity.java +++ b/src/main/java/org/olat/course/run/preview/PreviewIdentity.java @@ -85,6 +85,11 @@ public final class PreviewIdentity implements Identity, User { return data.get(UserConstants.EMAIL); } + @Override + public String getInstitutionalEmail() { + return data.get(UserConstants.INSTITUTIONALEMAIL); + } + @Override public String getFirstName() { return data.get(UserConstants.FIRSTNAME); diff --git a/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java b/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java index 984c19141be6559b6af67770c9a896834217f70c..ca43e06edac7b3f66bf0e7760fb0ee57b1bd8f03 100644 --- a/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java +++ b/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java @@ -19,6 +19,8 @@ */ package org.olat.course.run.scoring; +import java.util.Date; + import org.olat.course.nodes.AssessableCourseNode; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.model.AssessmentEntryStatus; @@ -37,6 +39,11 @@ public class AssessmentEvaluation extends ScoreEvaluation { private final String comment; private final String coachComment; private final int numOfAssessmentDocs; + + private final Date lastModified; + private final Date lastUserModified; + private final Date lastCoachModified; + public AssessmentEvaluation(Float score, Boolean passed) { this(score, passed, null, null); @@ -47,16 +54,24 @@ public class AssessmentEvaluation extends ScoreEvaluation { } public AssessmentEvaluation(Float score, Boolean passed, Boolean fullyAssessed, Long assessmentID) { - this(score, passed, null, null, null, fullyAssessed, assessmentID, null, null, -1); + this(score, passed, null, null, null, fullyAssessed, assessmentID, null, null, -1, null, null, null); + } + + public AssessmentEvaluation(Date lastModified, Date lastUserModified, Date lastCoachModified) { + this(null, null, null, null, null, null, null, null, null, -1, lastModified, lastUserModified, lastCoachModified); } public AssessmentEvaluation(Float score, Boolean passed, Integer attempts, AssessmentEntryStatus assessmentStatus, Boolean userVisibility, - Boolean fullyAssessed, Long assessmentID, String comment, String coachComment, int numOfAssessmentDocs) { + Boolean fullyAssessed, Long assessmentID, String comment, String coachComment, int numOfAssessmentDocs, + Date lastModified, Date lastUserModified, Date lastCoachModified) { super(score, passed, assessmentStatus, userVisibility, fullyAssessed, assessmentID); this.attempts = attempts; this.comment = comment; this.coachComment = coachComment; this.numOfAssessmentDocs = numOfAssessmentDocs; + this.lastModified = lastModified; + this.lastUserModified = lastUserModified; + this.lastCoachModified = lastCoachModified; } /** @@ -67,7 +82,8 @@ public class AssessmentEvaluation extends ScoreEvaluation { */ public AssessmentEvaluation(AssessmentEvaluation eval, AssessmentEntryStatus assessmentStatus) { this(eval.getScore(), eval.getPassed(), eval.getAttempts(), assessmentStatus, eval.getUserVisible(), - eval.getFullyAssessed(), eval.getAssessmentID(), eval.getComment(), eval.getCoachComment(), -1); + eval.getFullyAssessed(), eval.getAssessmentID(), eval.getComment(), eval.getCoachComment(), -1, + eval.getLastModified(), eval.getLastUserModified(), eval.getLastCoachModified()); } public Integer getAttempts() { @@ -86,6 +102,18 @@ public class AssessmentEvaluation extends ScoreEvaluation { return numOfAssessmentDocs; } + public Date getLastModified() { + return lastModified; + } + + public Date getLastUserModified() { + return lastUserModified; + } + + public Date getLastCoachModified() { + return lastCoachModified; + } + public static final AssessmentEvaluation toAssessmentEvalutation(AssessmentEntry entry, AssessableCourseNode node) { if(entry == null) { return AssessmentEvaluation.EMPTY_EVAL; @@ -111,6 +139,7 @@ public class AssessmentEvaluation extends ScoreEvaluation { comment = entry.getComment(); } return new AssessmentEvaluation(score, passed, attempts, entry.getAssessmentStatus(), entry.getUserVisibility(), - entry.getFullyAssessed(), entry.getAssessmentId(), comment, entry.getCoachComment(), entry.getNumberOfAssessmentDocuments()); + entry.getFullyAssessed(), entry.getAssessmentId(), comment, entry.getCoachComment(), entry.getNumberOfAssessmentDocuments(), + entry.getLastModified(), entry.getLastUserModified(), entry.getLastCoachModified()); } } \ No newline at end of file diff --git a/src/main/java/org/olat/course/run/scoring/ScoreAccounting.java b/src/main/java/org/olat/course/run/scoring/ScoreAccounting.java index 1d2697f1a3d892b3bbabf5819d8b9823f9f8d388..970379d59091b60ba6020a58d32bb9724fb322a9 100644 --- a/src/main/java/org/olat/course/run/scoring/ScoreAccounting.java +++ b/src/main/java/org/olat/course/run/scoring/ScoreAccounting.java @@ -177,6 +177,18 @@ public class ScoreAccounting { return se; } + private void updateLastModified(CourseNode cNode, LastModifications lastModifications) { + AssessmentEvaluation eval = cachedScoreEvals.get(cNode); + if(eval != null) { + lastModifications.addLastUserModified(eval.getLastUserModified()); + lastModifications.addLastCoachModified(eval.getLastCoachModified()); + } + + for(int i=cNode.getChildCount(); i-->0; ) { + updateLastModified((CourseNode)cNode.getChildAt(i), lastModifications); + } + } + /** * Recalculate the score of structure nodes. * @@ -196,6 +208,8 @@ public class ScoreAccounting { Boolean userVisibility = entry == null ? null : entry.getUserVisibility(); Long assessmendId = entry == null ? null : entry.getAssessmentId(); int numOfAssessmentDocs = entry == null ? -1 : entry.getNumberOfAssessmentDocuments(); + Date lastModified = entry == null ? null : entry.getLastModified(); + AssessmentEntryStatus assessmentStatus = AssessmentEntryStatus.inProgress; ConditionInterpreter ci = userCourseEnvironment.getConditionInterpreter(); if (cNode.hasScoreConfigured() && scoreExpressionStr != null) { @@ -221,7 +235,11 @@ public class ScoreAccounting { } } } - se = new AssessmentEvaluation(score, passed, null, assessmentStatus, userVisibility, null, assessmendId, null, null, numOfAssessmentDocs); + + LastModifications lastModifications = new LastModifications(); + updateLastModified(cNode, lastModifications); + se = new AssessmentEvaluation(score, passed, null, assessmentStatus, userVisibility, null, assessmendId, null, null, numOfAssessmentDocs, + lastModified, lastModifications.getLastUserModified(), lastModifications.getLastCoachModified()); if(entry == null) { Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); @@ -235,11 +253,49 @@ public class ScoreAccounting { entry.setScore(null); } entry.setPassed(passed); + if(lastModifications.getLastCoachModified() != null + && (entry.getLastCoachModified() == null || (entry.getLastCoachModified() != null && entry.getLastCoachModified().before(lastModifications.getLastCoachModified())))) { + entry.setLastCoachModified(lastModifications.getLastCoachModified()); + } + if(lastModifications.getLastUserModified() != null + && (entry.getLastUserModified() == null || (entry.getLastUserModified() != null && entry.getLastUserModified().before(lastModifications.getLastUserModified())))) { + entry.setLastUserModified(lastModifications.getLastUserModified()); + } entry = userCourseEnvironment.getCourseEnvironment().getAssessmentManager().updateAssessmentEntry(entry); identToEntries.put(cNode.getIdent(), entry); changes = true; } } else { + //only update the last modifications dates + LastModifications lastModifications = new LastModifications(); + updateLastModified(cNode, lastModifications); + if(entry == null) { + if(lastModifications.getLastCoachModified() != null || lastModifications.getLastUserModified() != null) { + se = new AssessmentEvaluation(new Date(), lastModifications.getLastUserModified(), lastModifications.getLastCoachModified()); + Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity(); + userCourseEnvironment.getCourseEnvironment().getAssessmentManager() + .createAssessmentEntry(cNode, assessedIdentity, se); + changes = true; + } + } else { + boolean updated = false; + if(lastModifications.getLastCoachModified() != null + && (entry.getLastCoachModified() == null || (entry.getLastCoachModified() != null && entry.getLastCoachModified().before(lastModifications.getLastCoachModified())))) { + entry.setLastCoachModified(lastModifications.getLastCoachModified()); + updated = true; + } + if(lastModifications.getLastUserModified() != null + && (entry.getLastUserModified() == null || (entry.getLastUserModified() != null && entry.getLastUserModified().before(lastModifications.getLastUserModified())))) { + entry.setLastUserModified(lastModifications.getLastUserModified()); + updated = true; + } + if(updated) { + entry = userCourseEnvironment.getCourseEnvironment().getAssessmentManager().updateAssessmentEntry(entry); + identToEntries.put(cNode.getIdent(), entry); + changes = true; + } + } + se = AssessmentEvaluation.EMPTY_EVAL; } return se; @@ -278,6 +334,18 @@ public class ScoreAccounting { same &= false; } + if((entry.getLastUserModified() == null && se.getLastUserModified() != null) + || (se.getLastUserModified() != null && entry.getLastUserModified() != null + && se.getLastUserModified().after(entry.getLastUserModified()))) { + same &= false; + } + + if((entry.getLastCoachModified() == null && se.getLastCoachModified() != null) + || (se.getLastCoachModified() != null && entry.getLastCoachModified() != null + && se.getLastCoachModified().after(entry.getLastCoachModified()))) { + same &= false; + } + return same; } } @@ -389,5 +457,31 @@ public class ScoreAccounting { public boolean isError() { return error; } + + private static class LastModifications { + + private Date lastUserModified; + private Date lastCoachModified; + + public Date getLastUserModified() { + return lastUserModified; + } + + public void addLastUserModified(Date date) { + if(date != null && (lastUserModified == null || lastUserModified.before(date))) { + lastUserModified = date; + } + } + + public Date getLastCoachModified() { + return lastCoachModified; + } + + public void addLastCoachModified(Date date) { + if(date != null && (lastCoachModified == null || lastCoachModified.before(date))) { + lastCoachModified = date; + } + } + } } diff --git a/src/main/java/org/olat/course/site/ui/CourseSiteAdminController.java b/src/main/java/org/olat/course/site/ui/CourseSiteAdminController.java index 02198886963552fa3fc48605a1848efebcce3a7e..66e426c58ad7be1c66d69f4a928e4be986cf7271 100644 --- a/src/main/java/org/olat/course/site/ui/CourseSiteAdminController.java +++ b/src/main/java/org/olat/course/site/ui/CourseSiteAdminController.java @@ -57,6 +57,7 @@ import org.olat.course.site.model.LanguageConfiguration; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.controllers.ReferencableEntriesSearchController; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -80,6 +81,9 @@ public class CourseSiteAdminController extends FormBasicController { private CourseSiteConfiguration siteConfiguration; private final RepositoryManager repositoryManager; + @Autowired + private I18nModule i18nModule; + public CourseSiteAdminController(UserRequest ureq, WindowControl wControl, CourseSiteConfiguration siteConfiguration) { super(ureq, wControl); @@ -128,7 +132,7 @@ public class CourseSiteAdminController extends FormBasicController { } } - for(String langKey:I18nModule.getEnabledLanguageKeys()) { + for(String langKey:i18nModule.getEnabledLanguageKeys()) { if(langToConfigMap.containsKey(langKey)) { LanguageConfiguration langConfig = langToConfigMap.get(langKey); RepositoryEntry re = repositoryManager.lookupRepositoryEntryBySoftkey(langConfig.getRepoSoftKey(), false); diff --git a/src/main/java/org/olat/course/statistic/MySQLTempStatTableCreator.java b/src/main/java/org/olat/course/statistic/MySQLTempStatTableCreator.java index 28c96b5ebad9439c6c81b4bc19faa63124b249c7..c64f4a3c4029eed2d471fd4a72ffaeb6121548e2 100644 --- a/src/main/java/org/olat/course/statistic/MySQLTempStatTableCreator.java +++ b/src/main/java/org/olat/course/statistic/MySQLTempStatTableCreator.java @@ -98,7 +98,7 @@ public class MySQLTempStatTableCreator implements IStatisticUpdater { long fromSeconds = from.getTime() / 1000l; long untilSeconds = until.getTime() / 1000l; - jdbcTemplate_.update( + long numLoggingActions = jdbcTemplate_.update( "insert into o_stat_temptable (creationdate,businesspath,userproperty2,userproperty4,userproperty10,userproperty3) " + "select " + "creationdate,businesspath,userproperty2,userproperty4,userproperty10,userproperty3 " + @@ -107,8 +107,7 @@ public class MySQLTempStatTableCreator implements IStatisticUpdater { " where " + "actionverb='launch' and actionobject='node' and creationdate>from_unixtime('"+ fromSeconds +"') and creationdate<=from_unixtime('"+ untilSeconds +"');"); - long numLoggingActions = jdbcTemplate_.queryForLong("select count(*) from o_stat_temptable;"); - log_.info("updateStatistic: insert done. number of logging actions: "+numLoggingActions); + log_.info("updateStatistic: insert done. number of logging actions: " + numLoggingActions); } catch(RuntimeException e) { log_.warn("updateStatistic: ran into a RuntimeException: "+e, e); } catch(Error er) { diff --git a/src/main/java/org/olat/course/statistic/StatisticManager.java b/src/main/java/org/olat/course/statistic/StatisticManager.java deleted file mode 100644 index 78619222177190d4969032b43487b3b14c33adb8..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/course/statistic/StatisticManager.java +++ /dev/null @@ -1,39 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.course.statistic; - -/** - * Description:<br> - * TODO: patrickb Class Description for StatisticManager - * - * <P> - * Initial Date: 23.12.2009 <br> - * @author patrickb - */ -public interface StatisticManager { - - String getInitSqlFile(); - void setInitSqlFile(String initSqlFile); -} diff --git a/src/main/java/org/olat/course/statistic/_spring/statisticContext.xml b/src/main/java/org/olat/course/statistic/_spring/statisticContext.xml index ee96ebfb29a61ec0da905f2ace3e794f7562343e..95c386231bb2e052da1e1c7d60f74dee726e111f 100644 --- a/src/main/java/org/olat/course/statistic/_spring/statisticContext.xml +++ b/src/main/java/org/olat/course/statistic/_spring/statisticContext.xml @@ -5,38 +5,6 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - <!-- - - Configuration for the Export Manager - - - There are currently three different implementations for exporting log files: - - a) SimpleLogExporter - ................. - a generic hibernate version which does a plain select and writes the resulting - LoggingObject list into a csv file. - - This version runs on all standard OLAT deployments where the o_loggingtable - resides in the normal DB - - The downside of this version is that it is slow with big tables and result sets - - b) SQLLogExporter - .............. - an optimized sql-export version which leaves the job to export the selected - o_loggingtable rows into a csv file to the database. - - This version requires database specific SQL to be configured in this file. - - This version should be performant since it leaves the job to the database - to export and doesn't read the result into the JVM. - - The downside of this version is that it requires 'FILE' permissions for - the database user executing the 'SELECT INTO OUTFILE' statement. This FILE - permission is a security risk and hence a possible concern. - --> - <!-- ......................................................... Configuration of ExportManager - required for any version @@ -61,20 +29,12 @@ <property name="concurrentExportsPerNode" value="2"/> </bean> - <!-- - ............................................................. - Configuration of DataSource - required for versions b) and c) - ............................................................. - --> - - <!-- ........................................................................ - Sample remaining configuration for SimpleLogExporter or version a) above + Sample remaining configuration for SimpleLogExporter ........................................................................ --> - <bean id="courseLogExporter" class="org.olat.course.statistic.export.SimpleLogExporter"> <property name="dbInstance" ref="database"/> <property name="logLineConverter" ref="logLineConverter"/> diff --git a/src/main/java/org/olat/course/statistic/_spring/statisticsJobContext.xml b/src/main/java/org/olat/course/statistic/_spring/statisticsJobContext.xml index e079b063686f763fa98b3b3efd8afac2e9620127..29d74357e5110310183ee2bd1ada44a63c9816f4 100644 --- a/src/main/java/org/olat/course/statistic/_spring/statisticsJobContext.xml +++ b/src/main/java/org/olat/course/statistic/_spring/statisticsJobContext.xml @@ -6,7 +6,7 @@ <!-- --> - <bean id="updateStatisticsTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="updateStatisticsTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="org.olat.statistics.job.${cluster.singleton.services}" /> <!-- adjust cron style syntax for your notification needs "0 10 0 * *" e.g. 10 minutes after midnight @@ -27,12 +27,12 @@ <property name="startDelay" value="300000" /> </bean> - <bean id="org.olat.statistics.job.enabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="org.olat.statistics.job.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.course.statistic.UpdateStatisticsJob"/> </bean> <!-- dummy bean --> - <bean id="org.olat.statistics.job.disabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="org.olat.statistics.job.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <!-- NOTE: reusing the notifications.DummyJob here --> <property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" /> </bean> diff --git a/src/main/java/org/olat/course/statistic/export/MySQLStoredProcedureLogExporter.java b/src/main/java/org/olat/course/statistic/export/MySQLStoredProcedureLogExporter.java deleted file mode 100644 index f7209cebe88550db3945121061bf15a1b3914c53..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/course/statistic/export/MySQLStoredProcedureLogExporter.java +++ /dev/null @@ -1,155 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.course.statistic.export; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; -import org.olat.core.util.FileUtils; -import org.olat.core.util.StringHelper; -import org.springframework.jdbc.core.CallableStatementCreator; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.SqlParameter; - -/** - * ICourseLogExporter used for the case where a separate DB - * should be used to retrieve the o_loggingtable. - * <p> - * This would be a non-standard situation specifically for a mysql/stored procedure setup - * <P> - * Initial Date: 06.01.2010 <br> - * @author Stefan - */ -public class MySQLStoredProcedureLogExporter implements ICourseLogExporter { - - /** the logging object used in this class **/ - private static final OLog log_ = Tracing.createLoggerFor(SQLLogExporter.class); - - private JdbcTemplate jdbcTemplate_; - - public MySQLStoredProcedureLogExporter() { - // this empty constructor is ok - instantiated via spring - } - - /** set via spring **/ - public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { - jdbcTemplate_ = jdbcTemplate; - } - - /** - * @TODO: charSet is currently ignored!!!!! - * @see org.olat.course.statistic.export.ICourseLogExporter#exportCourseLog(java.io.File, java.lang.String, java.lang.Long, java.util.Date, java.util.Date, boolean) - */ - public void exportCourseLog(final File outFile, String charSet, final Long resourceableId, final Date begin, final Date end, final boolean resourceAdminAction, final boolean anonymize) { - final long startTime = System.currentTimeMillis(); - log_.info("exportCourseLog: BEGIN outFile="+outFile+", charSet="+charSet+", resourceableId="+resourceableId+", begin="+begin+", end="+end+", resourceAdminAction="+resourceAdminAction+", anonymize="+anonymize); - try { - if (!outFile.exists()) { - if (!outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs()) { - throw new IllegalArgumentException("Cannot create parent of OutFile "+outFile.getAbsolutePath()); - } - if (!outFile.createNewFile()) { - throw new IllegalArgumentException("Cannot create outFile "+outFile.getAbsolutePath()); - } - } - } catch (IOException e) { - e.printStackTrace(); - throw new IllegalArgumentException("Cannot create outFile "+outFile.getAbsolutePath()); - } - if (!outFile.delete()) { - throw new IllegalStateException("Could not delete temporary outfile "+outFile.getAbsolutePath()); - } - - // try to make sure the database can write into this directory - if (!outFile.getParentFile().setWritable(true, false)) { - log_.warn("exportCourseLog: COULD NOT SET DIR TO WRITEABLE: "+outFile.getParent()); - } - - try{ - List<SqlParameter> emptyOutParams = new LinkedList<SqlParameter>(); - - // we ignore the result of the stored procedure - jdbcTemplate_.call(new CallableStatementCreator() { - - @Override - public CallableStatement createCallableStatement(Connection con) throws SQLException { - CallableStatement cs = con.prepareCall("call olatng.o_logging_export(?,?,?,?,?,?)"); - cs.setString(1, outFile.getAbsolutePath()); - cs.setBoolean(2, resourceAdminAction); - cs.setString(3, Long.toString(resourceableId)); - cs.setBoolean(4, anonymize); - cs.setTimestamp(5, begin==null ? null : new Timestamp(begin.getTime())); - cs.setTimestamp(6, end==null ? null : new Timestamp(end.getTime())); - MySQLStoredProcedureLogExporter.log_.info("exportCourseLog: executing stored procedure right about now"); - return cs; - } - - }, emptyOutParams); - - log_.info("exportCourseLog: adding header..."); - BufferedInputStream bis = new BufferedInputStream(new FileInputStream(outFile)); - File tmpOutFile = new File(outFile.getParent(), "tmp_"+outFile.getName()); - BufferedOutputStream bos = FileUtils.getBos(tmpOutFile); - bos.write(("creationDate, username, actionVerb, actionObject, greatGrandParent, grandParent, parent, target"+System.getProperty("line.separator")).getBytes(StringHelper.check4xMacRoman(charSet))); - - FileUtils.cpio(bis, bos, "exportCourseLogCSV"); - - bos.flush(); - bos.close(); - bis.close(); - - outFile.delete(); - tmpOutFile.renameTo(outFile); - - } catch(RuntimeException e) { - log_.error("exportCourseLog: runtime exception ",e); - } catch(Error er) { - log_.error("exportCourseLog: error ",er); - } catch (FileNotFoundException e) { - log_.error("exportCourseLog: FileNotFoundException: ",e); - } catch (IOException e) { - log_.error("exportCourseLog: IOException: ", e); - } finally { - final long diff = System.currentTimeMillis() - startTime; - log_.info("exportCourseLog: END DURATION="+diff); - } - } - -} diff --git a/src/main/java/org/olat/course/statistic/export/SQLLogExporter.java b/src/main/java/org/olat/course/statistic/export/SQLLogExporter.java deleted file mode 100644 index 5a25abdb0a238a81e0b6951b36647102294de336..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/course/statistic/export/SQLLogExporter.java +++ /dev/null @@ -1,149 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.course.statistic.export; - -import java.io.File; -import java.io.IOException; -import java.util.Calendar; -import java.util.Date; - -import org.hibernate.Query; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; - -/** - * ICourseLogExporter used for the case where a separate DB - * should be used to retrieve the o_loggingtable. - * <p> - * This would be a non-standard situation - * <P> - * Initial Date: 06.01.2010 <br> - * @author Stefan - */ -public class SQLLogExporter implements ICourseLogExporter { - - /** the logging object used in this class **/ - private static final OLog log_ = Tracing.createLoggerFor(SQLLogExporter.class); - - private SessionFactory sessionFactory_; - - private String anonymizedUserSql_; - private String nonAnonymizedUserSql_; - - public SQLLogExporter() { - // this empty constructor is ok - instantiated via spring - } - - /** set via spring **/ - public void setAnonymizedUserSql(String anonymizedUserSql) { - anonymizedUserSql_ = anonymizedUserSql; - } - - /** set via spring **/ - public void setNonAnonymizedUserSql(String nonAnonymizedUserSql) { - nonAnonymizedUserSql_ = nonAnonymizedUserSql; - } - - /** set via spring **/ - public void setSessionFactory(SessionFactory sessionFactory) { - sessionFactory_ = sessionFactory; - } - - /** - * @TODO: charSet is currently ignored!!!!! - * @see org.olat.course.statistic.export.ICourseLogExporter#exportCourseLog(java.io.File, java.lang.String, java.lang.Long, java.util.Date, java.util.Date, boolean) - */ - public void exportCourseLog(File outFile, String charSet, Long resourceableId, Date begin, Date end, boolean resourceAdminAction, boolean anonymize) { - log_.info("exportCourseLog: BEGIN outFile="+outFile+", charSet="+charSet+", resourceableId="+resourceableId+", begin="+begin+", end="+end+", resourceAdminAction="+resourceAdminAction+", anonymize="+anonymize); - try { - if (!outFile.exists()) { - if (!outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs()) { - throw new IllegalArgumentException("Cannot create parent of OutFile "+outFile.getAbsolutePath()); - } - if (!outFile.createNewFile()) { - throw new IllegalArgumentException("Cannot create outFile "+outFile.getAbsolutePath()); - } - } - } catch (IOException e) { - e.printStackTrace(); - throw new IllegalArgumentException("Cannot create outFile "+outFile.getAbsolutePath()); - } - if (!outFile.delete()) { - throw new IllegalStateException("Could not delete temporary outfile "+outFile.getAbsolutePath()); - } - - // try to make sure the database can write into this directory - if (!outFile.getParentFile().setWritable(true, false)) { - log_.warn("exportCourseLog: COULD NOT SET DIR TO WRITEABLE: "+outFile.getParent()); - } - - String query = String.valueOf(anonymize ? anonymizedUserSql_ : nonAnonymizedUserSql_); - if (begin != null) { - query = query.concat(" AND (v.creationDate >= :createdAfter)"); - } - if (end != null) { - query = query.concat(" AND (v.creationDate <= :createdBefore)"); - } - - Session session = sessionFactory_.openSession(); - final long startTime = System.currentTimeMillis(); - try{ - session.beginTransaction(); - Query dbQuery = session.createSQLQuery(query); - - dbQuery.setBoolean("resAdminAction", resourceAdminAction); - dbQuery.setString("resId", Long.toString(resourceableId)); - if (begin != null) { - dbQuery.setDate("createdAfter", begin); - } - if (end != null) { - Calendar cal = Calendar.getInstance(); - cal.setTime(end); - cal.add(Calendar.DAY_OF_MONTH, 1); - end = cal.getTime(); - dbQuery.setDate("createdBefore", end); - } - - dbQuery.setString("outFile", outFile.getAbsolutePath()); - - dbQuery.scroll(); - } catch(RuntimeException e) { - e.printStackTrace(System.out); - } catch(Error er) { - er.printStackTrace(System.out); - } finally { - if (session!=null) { - session.close(); - } - final long diff = System.currentTimeMillis() - startTime; - log_.info("exportCourseLog: END DURATION="+diff+", outFile="+outFile+", charSet="+charSet+", resourceableId="+resourceableId+", begin="+begin+", end="+end+", resourceAdminAction="+resourceAdminAction+", anonymize="+anonymize); - } - } - -} diff --git a/src/main/java/org/olat/course/statistic/export/UZHStoredProcedureLogExporter.java b/src/main/java/org/olat/course/statistic/export/UZHStoredProcedureLogExporter.java deleted file mode 100644 index 91817f653855bd904c9d6cc44a9d68ac696853e4..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/course/statistic/export/UZHStoredProcedureLogExporter.java +++ /dev/null @@ -1,171 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.course.statistic.export; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; -import org.olat.core.util.FileUtils; -import org.olat.core.util.StringHelper; -import org.springframework.jdbc.core.CallableStatementCreator; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.SqlParameter; - -/** - * ICourseLogExporter used for the case where a separate DB - * should be used to retrieve the o_loggingtable. - * <p> - * This would be a non-standard situation specifically for a mysql/stored procedure setup - * <P> - * Initial Date: 06.01.2010 <br> - * @author Stefan - */ -public class UZHStoredProcedureLogExporter implements ICourseLogExporter { - - /** the logging object used in this class **/ - private static final OLog log_ = Tracing.createLoggerFor(UZHStoredProcedureLogExporter.class); - - private JdbcTemplate jdbcTemplate_; - - private String header_ = "header not configured"; - - public UZHStoredProcedureLogExporter() { - // this empty constructor is ok - instantiated via spring - } - - /** set via spring **/ - public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { - jdbcTemplate_ = jdbcTemplate; - } - - /** set via spring **/ - public void setHeader(String header) { - header_ = header; - } - - /** - * @TODO: charSet is currently ignored!!!!! - * @see org.olat.course.statistic.export.ICourseLogExporter#exportCourseLog(java.io.File, java.lang.String, java.lang.Long, java.util.Date, java.util.Date, boolean) - */ - public void exportCourseLog(final File outFile, String charSet, final Long resourceableId, final Date begin, final Date end, final boolean resourceAdminAction, final boolean anonymize) { - final long startTime = System.currentTimeMillis(); - log_.info("exportCourseLog: BEGIN outFile="+outFile+", charSet="+charSet+", resourceableId="+resourceableId+", begin="+begin+", end="+end+", resourceAdminAction="+resourceAdminAction+", anonymize="+anonymize); - try { - if (!outFile.exists()) { - if (!outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs()) { - throw new IllegalArgumentException("Cannot create parent of OutFile "+outFile.getAbsolutePath()); - } - if (!outFile.createNewFile()) { - throw new IllegalArgumentException("Cannot create outFile "+outFile.getAbsolutePath()); - } - } - } catch (IOException e) { - e.printStackTrace(); - throw new IllegalArgumentException("Cannot create outFile "+outFile.getAbsolutePath()); - } - if (!outFile.delete()) { - throw new IllegalStateException("Could not delete temporary outfile "+outFile.getAbsolutePath()); - } - - // try to make sure the database can write into this directory - if (!outFile.getParentFile().setWritable(true, false)) { - log_.warn("exportCourseLog: COULD NOT SET DIR TO WRITEABLE: "+outFile.getParent()); - } - - BufferedInputStream fis = null; - BufferedOutputStream fos = null; - try{ - List<SqlParameter> emptyOutParams = new LinkedList<SqlParameter>(); - - // we ignore the result of the stored procedure - jdbcTemplate_.call(new CallableStatementCreator() { - - @Override - public CallableStatement createCallableStatement(Connection con) throws SQLException { - CallableStatement cs = con.prepareCall("call o_logging_export(?,?,?,?,?,?)"); - cs.setString(1, outFile.getAbsolutePath()); - cs.setBoolean(2, resourceAdminAction); - cs.setString(3, Long.toString(resourceableId)); - cs.setBoolean(4, anonymize); - cs.setTimestamp(5, begin==null ? null : new Timestamp(begin.getTime())); - cs.setTimestamp(6, end==null ? null : new Timestamp(end.getTime())); - UZHStoredProcedureLogExporter.log_.info("exportCourseLog: executing stored procedure right about now"); - return cs; - } - - }, emptyOutParams); - - log_.info("exportCourseLog: adding header... mysql outfile="+outFile.getAbsolutePath()); - fis = new BufferedInputStream(new FileInputStream(outFile)); - File tmpOutFile = new File(outFile.getParent(), "tmp_"+outFile.getName()); - log_.info("exportCourseLog: tmpoutfile="+tmpOutFile.getAbsolutePath()); - - fos = FileUtils.getBos(tmpOutFile); - - fos.write((header_+System.getProperty("line.separator")).getBytes(StringHelper.check4xMacRoman(charSet))); - - FileUtils.cpio(fis, fos, "exportCourseLogUZH"); - - fos.flush(); - fos.close(); - fis.close(); - - outFile.delete(); - tmpOutFile.renameTo(outFile); - - log_.info("exportCourseLog: resulting outfile="+outFile.getAbsolutePath()); - } catch(RuntimeException e) { - String details = "outFile="+outFile.getAbsolutePath()+", resAdminAction="+resourceAdminAction+", resourceableId="+resourceableId+", anonymize="+anonymize+", begin="+(begin==null ? null : begin.getTime())+", end="+(end==null ? null : end.getTime()); - log_.error("exportCourseLog: runtime exception. Details: "+details,e); - } catch(Error er) { - String details = "outFile="+outFile.getAbsolutePath()+", resAdminAction="+resourceAdminAction+", resourceableId="+resourceableId+", anonymize="+anonymize+", begin="+(begin==null ? null : begin.getTime())+", end="+(end==null ? null : end.getTime()); - log_.error("exportCourseLog: error. Details: "+details,er); - } catch (FileNotFoundException e) { - String details = "outFile="+outFile.getAbsolutePath()+", resAdminAction="+resourceAdminAction+", resourceableId="+resourceableId+", anonymize="+anonymize+", begin="+(begin==null ? null : begin.getTime())+", end="+(end==null ? null : end.getTime()); - log_.error("exportCourseLog: FileNotFoundException. Details: "+details,e); - } catch (IOException e) { - String details = "outFile="+outFile.getAbsolutePath()+", resAdminAction="+resourceAdminAction+", resourceableId="+resourceableId+", anonymize="+anonymize+", begin="+(begin==null ? null : begin.getTime())+", end="+(end==null ? null : end.getTime()); - log_.error("exportCourseLog: IOException. Details: "+details, e); - } finally { - final long diff = System.currentTimeMillis() - startTime; - log_.info("exportCourseLog: END DURATION="+diff); - } - } - -} diff --git a/src/main/java/org/olat/dispatcher/LocaleNegotiator.java b/src/main/java/org/olat/dispatcher/LocaleNegotiator.java index b3d83dd2f70264f39c35d36d1e3e5fda2d677991..b6d7893dfab14be444426a4b1e013155b1eeae2f 100644 --- a/src/main/java/org/olat/dispatcher/LocaleNegotiator.java +++ b/src/main/java/org/olat/dispatcher/LocaleNegotiator.java @@ -24,6 +24,7 @@ import java.util.Enumeration; import java.util.Locale; import java.util.Map; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.util.i18n.I18nModule; @@ -98,8 +99,9 @@ public class LocaleNegotiator { * match language and country and the final ty it with language only */ public static Locale getNegotiatedLocale(Locale loc) { - Map<String,Locale> allLocales = I18nModule.getAllLocales(); - Collection<String> enabledLanguageKeys = I18nModule.getEnabledLanguageKeys(); + I18nModule i18nModule = CoreSpringFactory.getImpl(I18nModule.class); + Map<String,Locale> allLocales = i18nModule.getAllLocales(); + Collection<String> enabledLanguageKeys = i18nModule.getEnabledLanguageKeys(); String lang = loc.getLanguage(); //search a direct match first de_CH_bs... diff --git a/src/main/java/org/olat/fileresource/types/WikiResource.java b/src/main/java/org/olat/fileresource/types/WikiResource.java index 0ff7c3f98894707d8e500a001fd433e72e76d8fc..1b84073425d0296ba196763fad8113b86dcfcec5 100644 --- a/src/main/java/org/olat/fileresource/types/WikiResource.java +++ b/src/main/java/org/olat/fileresource/types/WikiResource.java @@ -51,8 +51,10 @@ public class WikiResource extends FileResource { public static final String TYPE_NAME = "FileResource.WIKI"; public static final String INDEX_FILENAME = WikiManager.generatePageId(WikiPage.WIKI_INDEX_PAGE) + "." + WikiManager.WIKI_FILE_SUFFIX; - public static final String INDEX_PROPNAME = WikiManager.generatePageId(WikiPage.WIKI_INDEX_PAGE) + "." + WikiManager.WIKI_PROPERTIES_SUFFIX; - + public static final String INDEX_PROPNAME = WikiManager.generatePageId(WikiPage.WIKI_INDEX_PAGE) + "." + WikiManager.WIKI_PROPERTIES_SUFFIX; + public static final String INDEX_ALT_FILENAME = INDEX_FILENAME.replace("=", "_"); + public static final String INDEX_ALT_PROPNAME = INDEX_PROPNAME.replace("=", "_"); + public WikiResource() { super(TYPE_NAME); } @@ -78,9 +80,9 @@ public class WikiResource extends FileResource { throws IOException { String filename = file.getFileName().toString(); - if(INDEX_FILENAME.equals(filename)) { + if(INDEX_FILENAME.equals(filename) || INDEX_ALT_FILENAME.equals(filename)) { indexFile = true; - } else if(INDEX_PROPNAME.equals(filename)) { + } else if(INDEX_PROPNAME.equals(filename) || INDEX_ALT_PROPNAME.equals(filename)) { indexProperties = true; } return (indexProperties && indexFile) ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE; diff --git a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java index d61de9b20c3728c794a5cbd2dcad6310f2df4a21..2826474c3c99eb9ea75de382ec62dae5a69383b6 100644 --- a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java +++ b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java @@ -219,6 +219,19 @@ public class BusinessGroupDAO { return groups; } + public BusinessGroup loadByResourceId(Long resourceId) { + StringBuilder sb = new StringBuilder(); + sb.append("select bgi from businessgroup bgi ") + .append(" inner join fetch bgi.resource resource") + .append(" where resource.resName='BusinessGroup' and resource.resId=:resId"); + + List<BusinessGroup> groups = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), BusinessGroup.class) + .setParameter("resId", resourceId) + .getResultList(); + return groups == null || groups.isEmpty() ? null : groups.get(0); + } + public BusinessGroup loadForUpdate(Long id) { StringBuilder sb = new StringBuilder(); sb.append("select bgi from businessgroup bgi ") @@ -873,7 +886,7 @@ public class BusinessGroupDAO { } loadOfferAccess(resourceKeyToGroup); - loadRelations(keyToGroup, null, null); + loadRelations(keyToGroup, params, identity); return groups; } @@ -917,7 +930,7 @@ public class BusinessGroupDAO { } } - loadRelations(keyToGroup, null, null); + loadRelations(keyToGroup, params, identity); loadOfferAccess(resourceKeyToGroup); loadMemberships(identity, keyToGroup); return groups; @@ -1116,15 +1129,15 @@ public class BusinessGroupDAO { if(params.getResources() != null && params.getResources().booleanValue()) { sb.append(" exists (select resourceRel.key from repoentrytogroup as resourceRel where bgi.baseGroup.key=resourceRel.group.key )"); } else { - sb.append(" bgi.baseGroup.key not in (select resourceRel.group.key from repoentrytogroup as resourceRel)"); + sb.append(" not exists (select resourceRel.key from repoentrytogroup as resourceRel where resourceRel.group.key=bGroup.key)"); } } // orphans if(params.isHeadless()) { where = PersistenceHelper.appendAnd(sb, where); - sb.append(" bgi.baseGroup.key not in (select headMembership.group.key from bgroupmember as headMembership") - .append(" where headMembership.role in ('").append(GroupRoles.coach.name()).append("','").append(GroupRoles.participant.name()).append("')") + sb.append(" not exists (select headMembership.key from bgroupmember as headMembership") + .append(" where bGroup.key=headMembership.group.key and headMembership.role in ('").append(GroupRoles.coach.name()).append("','").append(GroupRoles.participant.name()).append("')") .append(" )"); } } @@ -1151,6 +1164,8 @@ public class BusinessGroupDAO { private void loadRelations(Map<Long, ? extends BusinessGroupRow> keyToGroup, BusinessGroupQueryParams params, IdentityRef identity) { if(keyToGroup.isEmpty()) return; + if(params.getResources() != null && !params.getResources().booleanValue()) return;//no resources, no relations + if(params.isHeadless()) return; //headless don't have relations final int RELATIONS_IN_LIMIT = 64; final boolean restrictToMembership = params != null && identity != null @@ -1167,18 +1182,33 @@ public class BusinessGroupDAO { .append(" inner join bGroup.members as membership on membership.identity.key=:identityKey"); } else if(keyToGroup.size() < RELATIONS_IN_LIMIT) { sr.append(" where bgi.key in (:businessGroupKeys)"); + } else if(params.getPublicGroups() != null && params.getPublicGroups().booleanValue()) { + sr.append(" inner join acoffer as offer on (bgi.resource.key = offer.resource.key)"); + } else if(params.getRepositoryEntry() != null) { + sr.append(" inner join repoentrytobusinessgroup as refBgiToGroup") + .append(" on (refBgiToGroup.entry.key=:repositoryEntryKey and bgi.baseGroup.key=refBgiToGroup.businessGroup.key)"); + } else { + sr.append(" inner join bgi.resource as bgResource ") + .append(" inner join bgi.baseGroup as bGroup "); + filterBusinessGroupToSearch(sr, params, false); } TypedQuery<Object[]> resourcesQuery = dbInstance.getCurrentEntityManager() .createQuery(sr.toString(), Object[].class); if(restrictToMembership) { resourcesQuery.setParameter("identityKey", identity.getKey()); - } else if(keyToGroup.size() < RELATIONS_IN_LIMIT) { + } else if(keyToGroup.size() < RELATIONS_IN_LIMIT) { List<Long> businessGroupKeys = new ArrayList<>(keyToGroup.size()); for(Long businessGroupKey:keyToGroup.keySet()) { businessGroupKeys.add(businessGroupKey); } resourcesQuery.setParameter("businessGroupKeys", businessGroupKeys); + } else if(params.getPublicGroups() != null && params.getPublicGroups().booleanValue()) { + //no parameters to add + } else if(params.getRepositoryEntry() != null) { + resourcesQuery.setParameter("repositoryEntryKey", params.getRepositoryEntry().getKey()); + } else { + filterBusinessGroupToSearchParameters(resourcesQuery, params, identity, false); } List<Object[]> resources = resourcesQuery.getResultList(); diff --git a/src/main/java/org/olat/group/manager/BusinessGroupMembershipProcessor.java b/src/main/java/org/olat/group/manager/BusinessGroupMembershipProcessor.java index 5fe41b1e5b0b650f1eac7da0b55b1cab61289ee2..ad8d3141bd4b63f16cf9f24647b91b10a9ba3b81 100644 --- a/src/main/java/org/olat/group/manager/BusinessGroupMembershipProcessor.java +++ b/src/main/java/org/olat/group/manager/BusinessGroupMembershipProcessor.java @@ -25,7 +25,7 @@ import java.util.List; import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.model.IdentityRefImpl; -import org.olat.commons.info.manager.InfoMessageFrontendManager; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.gui.control.Event; import org.olat.core.util.coordinate.CoordinatorManager; diff --git a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java index 23bbd6bfc4cda6ac856cec8f8fc99e25a822cead..dbd5d5219fe71b5917ac9e4909fd5f025950e8bf 100644 --- a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java +++ b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java @@ -44,7 +44,7 @@ import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.SecurityGroup; import org.olat.collaboration.CollaborationTools; import org.olat.collaboration.CollaborationToolsFactory; -import org.olat.commons.info.manager.InfoMessageFrontendManager; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.services.notifications.NotificationsManager; diff --git a/src/main/java/org/olat/group/ui/BusinessGroupFormController.java b/src/main/java/org/olat/group/ui/BusinessGroupFormController.java index d0824191af2fd0a78fffc343f075f2750a3cef80..9e11836ebeab4c29984791e6e18b8a3a698f53b6 100644 --- a/src/main/java/org/olat/group/ui/BusinessGroupFormController.java +++ b/src/main/java/org/olat/group/ui/BusinessGroupFormController.java @@ -178,12 +178,13 @@ public class BusinessGroupFormController extends FormBasicController { BusinessControlFactory bcf = BusinessControlFactory.getInstance(); List<ContextEntry> entries = bcf.createCEListFromString("[BusinessGroup:" + businessGroup.getKey() + "]"); String url = bcf.getAsURIString(entries, true); + url = "<span class='o_copy_code o_nowrap'><input type='text' value='" + url + "' onclick='this.select()'/></span>"; StaticTextElement urlEl = uifactory.addStaticTextElement("create.form.businesspath", url, formLayout); urlEl.setElementCssClass("o_sel_group_url"); // link to group visiting card bcf = BusinessControlFactory.getInstance(); entries = bcf.createCEListFromString("[GroupCard:" + businessGroup.getKey() + "]"); - url = bcf.getAsURIString(entries, true); + url = "<span class='o_copy_code o_nowrap'><input type='text' value='" + bcf.getAsURIString(entries, true) + "' onclick='this.select()'/></span>"; StaticTextElement cardEl = uifactory.addStaticTextElement("create.form.groupcard", url, formLayout); cardEl.setElementCssClass("o_sel_group_card_url"); } diff --git a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_pl.properties index e7cdace443cc621cfe086b8fe9841c81d4c5cb31..34ad1884da83b245d794d60f56145184b6678335 100644 --- a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_pl.properties @@ -1,4 +1,4 @@ -#Thu Sep 03 11:24:43 CEST 2015 +#Thu Aug 03 10:29:08 CEST 2017 LearningGroup=Grupa edukacyjna action.choose=Wybierz admin.menu.title=Grupa @@ -33,7 +33,10 @@ create.form.error.illegalName=U\u017Cycie przecink\u00F3w i cudzys\u0142ow\u00F3 create.form.error.illegalNames=$\:create.form.error.illegalName . Nast\u0119puj\u0105ce nazwy grup s\u0105 nieprawid\u0142owe\: {0} create.form.error.nameTooLong=Nazwy grup mog\u0105 sk\u0142ada\u0107 si\u0119 z maksymalnie 100 znak\u00F3w create.form.error.numberOrNull=Tylko liczby lub puste pole dla 'braku ogranicze\u0144' +create.form.externalid=Zewn\u0119trzne ID create.form.groupcard=Wizyt\u00F3wka +create.form.managedflags=Modu\u0142y zarz\u0105dzane zewn\u0119trznie +create.form.managedflags.intro=Grupa zosta\u0142a utworzona przy u\u017Cyciu zewn\u0119trznego narz\u0119dzia. Z tego powodu niekt\u00F3re ustawienia i modu\u0142y nie mog\u0105 by\u0107 modyfikowane i u\u017Cywane w OpenOLAT. Poni\u017Csze elementy zosta\u0142y zablokowane w OpenOLAT\: create.form.message.example.group=(Przyk\u0142ad\: Czerwony, Zielony, Niebieski) create.form.title=Utw\u00F3rz now\u0105 grup\u0119 edukacyjn\u0105 create.form.title.bgname=Nazwa grupy @@ -42,6 +45,10 @@ create.form.title.description=Opis create.form.title.max=Maksymalna liczba <br>uczestnik\u00F3w create.form.title.min=Minimalna liczba <br>uczestnik\u00F3w create.form.title.minmax.example=Pozostaw puste w przypadku braku ogranicze\u0144 +dedup.done=Oczyszczanie kursu i grup edukacyjnych zako\u0144czy\u0142o si\u0119 pomy\u015Blnie +dedup.members=Oczy\u015B\u0107 cz\u0142onk\u00F3w kursu +dedup.members.desc=Wybierz przycisk "$\:dedup.members" w celu oczyszczenia wszystkich list cz\u0142onk\u00F3w kursu we wszystkich kursach w systemie. Jest to funkcja konserwacji umo\u017Cliwiaj\u0105ca oczyszczanie duplikat\u00F3w kurs\u00F3w i cz\u0142onkostwa grup w ramach kurs\u00F3w. +dedup.running=Proces oczyszczania trwa default.context=Utworzona automatycznie wewn\u0105trz kursu enrolment.email.administrators=Administratorzy systemu enrolment.email.authors=Autorzy kursu @@ -51,7 +58,7 @@ enrolment.email.users=U\u017Cytkownicy error.group.name.exists=Ta nazwa grupy jest ju\u017C w u\u017Cyciu - prosz\u0119 wybra\u0107 inn\u0105 fieldset.legend.groupowners=Nauczyciele fieldset.legend.grouppartips=Uczestnicy -form.error.disableNonEmptyWaitingList=Lista oczekuj\u0105cych nie jest pusta. By j\u0105 deaktywowa\u0107 musisz usun\u0105\u0107 wszystkich oczekuj\u0105cych. +form.error.disableNonEmptyWaitingList=Lista oczekuj\u0105cych nie jest pusta. By j\u0105 dezaktywowa\u0107 musisz usun\u0105\u0107 wszystkich oczekuj\u0105cych. group.deleted=Grupa zosta\u0142a usuni\u0119ta group.name=Nazwa grupy group.not.existing=Grupa nie istnieje @@ -63,6 +70,12 @@ groupsPortlet.no_member=Zosta\u0142e\u015B usuni\u0119ty z grupy lub Twoja grupa groupsPortlet.nogroups=Nie jeste\u015B w \u017Cadnej grupie groupsPortlet.showAll=Poka\u017C wszystko groupsPortlet.title=Moje grupy +leaving.group=U\u017Cytkownicy mog\u0105 opu\u015Bci\u0107 grup\u0119 +leaving.group.authors=Zezwalaj na wyj\u015Bcie z grupy dla cz\u0142onk\u00F3w grup tworzonych przez autor\u00F3w +leaving.group.learners=Zezwalaj na wyj\u015Bcie z grupy dla cz\u0142onk\u00F3w grup tworzonych przez nauczycieli +leaving.group.override=Zezwalaj na zmian\u0119 ustawie\u0144 opuszczania grup przez u\u017Cytkownik\u00F3w autora +mandatory.enrolment=Wymu\u015B powiadomienie e-mail przy zapraszaniu przez +mandatory.membership=Wymagana akceptacja cz\u0142onkostwa je\u015Bli zaproszony przez membership.administrators=$\:enrolment.email.administrators membership.authors=$\:enrolment.email.authors membership.groupmanagers=$\:enrolment.email.groupmanagers @@ -75,26 +88,34 @@ menu.index.alt=Administruj grupami edukacyjnymi module.admin.allow.create=Mo\u017Ce tworzy\u0107 grupy module.admin.desc=Sprecyzuj, kto mo\u017Ce tworzy\u0107 grupy module.admin.title=Zarz\u0105dzanie grupami +module.privacy.desc=W celu zachowania zgodno\u015B\u0107 z zasadami dotycz\u0105cymi prywatno\u015Bci danych, dodawanie u\u017Cytkownika do grupy mo\u017Ce by\u0107 skonfigurowane tak, aby spowodowa\u0107 jego natychmiastowe cz\u0142onkostwo w grupie lub tylko wys\u0142anie zaproszenia, kt\u00F3re musi zosta\u0107 jednoznacznie zaakceptowane przez u\u017Cytkownika przed przyst\u0105pieniem do cz\u0142onkostwa w grupie. module.privacy.title=Ochrona danych +module.resource.courses=Menad\u017Cerowie grup mog\u0105 wyszukiwa\u0107 i przypisywa\u0107 wszystkie kursy grupom. +module.resource.courses.grant=Przyznane pe\u0142ne prawa dost\u0119pu do kursu +module.resource.desc=W\u0142a\u015Bciciele kurs\u00F3w i grup mog\u0105 przypisywa\u0107 swoje grupy do swoich kurs\u00F3w. Dzi\u0119ki poni\u017Cszym ustawieniom, prawa do do\u0142\u0105czania i od\u0142\u0105czania grup do kurs\u00F3w mog\u0105 zosta\u0107 przypisane menad\u017Cerom grup i menad\u017Cerom zasob\u00F3w edukacyjnych. +module.resource.groups=Menad\u017Cerowie zasob\u00F3w edukacyjnych mog\u0105 do\u0142\u0105cza\u0107 wszystkie grupy do kurs\u00F3w. +module.resource.groups.grant=Przyznane pe\u0142ne prawa do zarz\u0105dzania grup\u0105 +module.resource.title=Grupa - przydzielanie zasob\u00F3w newgroup.title=Utw\u00F3rz now\u0105 grup\u0119 edukacyjn\u0105 notification.mail.added.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \r\n\r\nZosta\u0142e\u015B zaproszony do grupy przez\: {0} {1} ({2})\: \r\n\r\nNazwa grupy\: $groupname\r\nOpis\: $groupdescription\r\n\r\nW razie pyta\u0144 skontaktuj si\u0119 z {0} {1} ({2}). \r\n\r\nTa grupa edukacyjna jest u\u017Cywana w nast\u0119puj\u0105cych zasobach edukacyjnych\:\r\n\r\n$courselist notification.mail.added.self.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \r\n\r\nW\u0142a\u015Bnie zapisa\u0142e\u015B si\u0119 do grupy\: \r\n\r\nNazwa grupy\: $groupname\r\nOpis\: $groupdescription\r\n\r\nTa grupa edukacyjna b\u0119dzie u\u017Cywana w nast\u0119puj\u0105cych zasobach edukacyjnych\:\r\n\r\n$courselist -notification.mail.added.self.subject=Grupa edukacyjna OLAT\: $groupname +notification.mail.added.self.subject=Grupa edukacyjna $groupname notification.mail.added.subject=Grupa edukacyjna OLAT\: $groupname notification.mail.error=Nie uda\u0142o si\u0119 wys\u0142a\u0107 wiadomo\u015Bci e-mail. Poinformuj tego u\u017Cytkownika osobi\u015Bcie. +notification.mail.no.ressource=Ta grupa nie jest wykorzystywana w \u017Cadnym zasobie edukacyjnym. notification.mail.removed.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \r\n\r\nZosta\u0142e\u015B wypisany z grupy przez\: {0} {1} ({2})\: \r\n\r\nNazwa grupy\: $groupname\r\nOpis\: $groupdescription\r\n\r\nW razie pyta\u0144 skontaktuj si\u0119 z{0} {1} ({2}).\r\n\r\nTa grupa edukacyjna jest u\u017Cywana w nast\u0119puj\u0105cych zasobach edukacyjnych\:\r\n\r\n$courselist notification.mail.removed.self.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \r\n\r\nWypisa\u0142e\u015B si\u0119 z grupy\: \r\n\r\nNazwa grupy\: $groupname\r\nOpis\: $groupdescription\r\n\r\nTa grupa edukacyjna by\u0142a u\u017Cywana w nast\u0119puj\u0105cych zasobach edukacyjnych\:\r\n\r\n$courselist -notification.mail.removed.self.subject=Grupa edukacyjna OLAT\: $groupname - Zosta\u0142e\u015B wypisany. +notification.mail.removed.self.subject=Grupa edukacyjna $groupname - Zosta\u0142e\u015B wypisany. notification.mail.removed.subject=Grupa edukacyjna OLAT\: $groupname - Zosta\u0142e\u015B wypisany. notification.mail.self.error=Nie uda\u0142o si\u0119 wys\u0142a\u0107 wiadomo\u015Bci e-mail notification.mail.waitingList.added.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \n\n Jeste\u015B w kolejce oczekuj\u0105cych do nast\u0119puj\u0105cej grupy edukacyjnej\: \n\n Nazwa grupy\: $groupname\n Opis\: $groupdescription\n\n -notification.mail.waitingList.added.subject=Grupa edukacyjna OLAT\: $groupname - kolejka oczekuj\u0105cych +notification.mail.waitingList.added.subject=Grupa edukacyjna $groupname - kolejka oczekuj\u0105cych notification.mail.waitingList.removed.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \n\n Nie jeste\u015B ju\u017C w kolejce oczekuj\u0105cych do nast\u0119puj\u0105cej grupy edukacyjnej\: \n\n Nazwa grupy\: $groupname\n Opis\: $groupdescription\n\n -notification.mail.waitingList.removed.subject=Grupa edukacyjna OLAT\: $groupname - kolejka oczekuj\u0105cych\: Zosta\u0142e\u015B wypisany +notification.mail.waitingList.removed.subject=Grupa edukacyjna $groupname - kolejka oczekuj\u0105cych\: Zosta\u0142e\u015B wypisany notification.mail.waitingList.transfer.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \n\n Zosta\u0142e\u015B automatycznie przeniesiony z kolejki oczekuj\u0105cych do listy uczestnik\u00F3w nast\u0119puj\u0105cej grupy edukacyjnej\: \n\n Nazwa grupy\: $groupname\n Opis\: $groupdescription\n\n -notification.mail.waitingList.transfer.subject=Grupa edukacyjna OLAT\: $groupname - kolejka oczekuj\u0105cych\: Zmiana Twojego statusu +notification.mail.waitingList.transfer.subject=Grupa edukacyjna $groupname - kolejka oczekuj\u0105cych\: Zmiana Twojego statusu overview.intro=Zarz\u0105dzanie grupami edukacyjnymi kursu. -overview.title=Zarz\u0105dzanie kontekstem edukacyjnym +overview.title=Zarz\u0105dzanie grup\u0105 owners.message=E-mail do wszystkich w\u0142a\u015Bcicieli owners.message.to=Wszyscy nauczyciele sendtochooser.form.chckbx.owners=Wszyscy nauczyciele diff --git a/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java index 7f2296d8f3bfc911b72a1e5cf9f3b319a62bf118..e6f85aa0acb61fac277644d658f2ebea567f0627 100644 --- a/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java +++ b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java @@ -198,7 +198,7 @@ public class BusinessGroupEditController extends BasicController implements Cont @Override public Component create(UserRequest uureq) { if(membersController == null) { - membersController = new BusinessGroupMembersController(ureq, getWindowControl(), toolbarPanel, currBusinessGroup); + membersController = new BusinessGroupMembersController(uureq, getWindowControl(), toolbarPanel, currBusinessGroup); listenTo(membersController); } else { membersController.updateBusinessGroup(currBusinessGroup); diff --git a/src/main/java/org/olat/group/ui/run/InfoGroupRunController.java b/src/main/java/org/olat/group/ui/run/InfoGroupRunController.java index 102d4191933fad41a80fedc9d0d6bb303a076156..97311924edb9feef791f0a887f901bde3181e5f3 100644 --- a/src/main/java/org/olat/group/ui/run/InfoGroupRunController.java +++ b/src/main/java/org/olat/group/ui/run/InfoGroupRunController.java @@ -23,11 +23,12 @@ import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; -import org.olat.commons.info.manager.InfoMessageFrontendManager; +import org.olat.basesecurity.GroupRoles; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; +import org.olat.commons.info.InfoSubscriptionManager; import org.olat.commons.info.manager.MailFormatter; -import org.olat.commons.info.model.InfoMessage; import org.olat.commons.info.notification.InfoSubscription; -import org.olat.commons.info.notification.InfoSubscriptionManager; import org.olat.commons.info.ui.InfoDisplayController; import org.olat.commons.info.ui.InfoSecurityCallback; import org.olat.commons.info.ui.SendInfoMailFormatter; @@ -48,7 +49,6 @@ import org.olat.core.id.OLATResourceable; import org.olat.core.util.UserSession; import org.olat.core.util.resource.OresHelper; import org.olat.group.BusinessGroup; -import org.olat.group.BusinessGroupService; import org.springframework.beans.factory.annotation.Autowired; /** @@ -64,13 +64,9 @@ public class InfoGroupRunController extends BasicController { private ContextualSubscriptionController subscriptionController; private final String businessPath; - private InfoSubscriptionManager subscriptionManager; @Autowired - private BusinessGroupService groupService; - @Autowired - private InfoMessageFrontendManager messageManager; - + private InfoSubscriptionManager subscriptionManager; public InfoGroupRunController(UserRequest ureq, WindowControl wControl, BusinessGroup businessGroup, boolean canAccess, boolean isAdmin) { super(ureq, wControl); @@ -81,7 +77,6 @@ public class InfoGroupRunController extends BasicController { UserSession usess = ureq.getUserSession(); if(!usess.getRoles().isGuestOnly()) { - subscriptionManager = InfoSubscriptionManager.getInstance(); SubscriptionContext subContext = subscriptionManager.getInfoSubscriptionContext(infoResourceable, resSubPath); PublisherData pdata = subscriptionManager.getInfoPublisherData(infoResourceable, businessPath); subscriptionController = new ContextualSubscriptionController(ureq, getWindowControl(), subContext, pdata); @@ -91,10 +86,13 @@ public class InfoGroupRunController extends BasicController { boolean canAddAndEdit = isAdmin || canAccess; InfoSecurityCallback secCallback = new InfoGroupSecurityCallback(getIdentity(), canAddAndEdit, isAdmin); infoDisplayController = new InfoDisplayController(ureq, wControl, secCallback, businessGroup, resSubPath, businessPath); - SendMailOption subscribers = new SendSubscriberMailOption(infoResourceable, resSubPath, messageManager); + SendMailOption subscribers = new SendSubscriberMailOption(infoResourceable, resSubPath, getLocale()); infoDisplayController.addSendMailOptions(subscribers); - SendMailOption groupMembers = new SendGroupMembersMailOption(groupService, businessGroup); - infoDisplayController.addSendMailOptions(groupMembers); + SendMailOption coaches = new SendGroupMembersMailOption(businessGroup, GroupRoles.coach, translate("sendtochooser.form.radio.owners")); + infoDisplayController.addSendMailOptions(coaches); + SendMailOption participants = new SendGroupMembersMailOption(businessGroup, GroupRoles.participant, translate("sendtochooser.form.radio.partip")); + infoDisplayController.addSendMailOptions(participants); + MailFormatter mailFormatter = new SendInfoMailFormatter(businessGroup.getName(), businessPath, getTranslator()); infoDisplayController.setSendMailFormatter(mailFormatter); listenTo(infoDisplayController); diff --git a/src/main/java/org/olat/group/ui/run/SendGroupMembersMailOption.java b/src/main/java/org/olat/group/ui/run/SendGroupMembersMailOption.java index aad0902a4d7695dbaed708348e5fe48dda19632a..6f079623f78c8d22cc65c479d3a0c2e72ea9bfe1 100644 --- a/src/main/java/org/olat/group/ui/run/SendGroupMembersMailOption.java +++ b/src/main/java/org/olat/group/ui/run/SendGroupMembersMailOption.java @@ -20,12 +20,11 @@ package org.olat.group.ui.run; import java.util.List; -import java.util.Locale; +import org.olat.basesecurity.GroupRoles; import org.olat.commons.info.ui.SendMailOption; -import org.olat.core.gui.translator.Translator; +import org.olat.core.CoreSpringFactory; import org.olat.core.id.Identity; -import org.olat.core.util.Util; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; @@ -35,30 +34,28 @@ import org.olat.group.BusinessGroupService; */ public class SendGroupMembersMailOption implements SendMailOption { - private BusinessGroupService groupService; + private final String label; + private final GroupRoles role; private BusinessGroup businessGroup; - - public SendGroupMembersMailOption(BusinessGroupService groupService, BusinessGroup businessGroup) { - this.groupService = groupService; + public SendGroupMembersMailOption(BusinessGroup businessGroup, GroupRoles role, String label) { + this.role = role; + this.label = label; this.businessGroup = businessGroup; } @Override public String getOptionKey() { - return "send-mail-group-members"; + return "send-mail-group-members-" + role.name(); } @Override - public String getOptionTranslatedName(Locale locale) { - Translator translator = Util.createPackageTranslator(SendGroupMembersMailOption.class, locale); - return translator.translate("wizard.step1.send_option.member"); + public String getOptionName() { + return label; } @Override public List<Identity> getSelectedIdentities() { - List<Identity> groupMembers = groupService.getMembers(businessGroup); - return groupMembers; + return CoreSpringFactory.getImpl(BusinessGroupService.class).getMembers(businessGroup, role.name()); } - } diff --git a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties index ea21cd3005659f0069878766c6169c3edf864d98..b971123dc79eaff685cf7e4293503792457efacb 100644 --- a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Wed Jun 21 23:35:17 CEST 2017 +#Tue Sep 05 23:12:33 CEST 2017 businessgroup.contact.bodytext=<p></p>---<p>Ir imediatamente para o grupo "{0}"\: {1}</p> businessgroup.contact.subject=Mensagem para grupo {0} contact.all.coaches=Todos os treinadores (coaches) de grupo diff --git a/src/main/java/org/olat/gui/control/OlatGuestTopNavController.java b/src/main/java/org/olat/gui/control/OlatGuestTopNavController.java index 113cfa5876b13721e2513658e11cdb25095ff09a..10993e59397df9d208a8f08fd921a6a9dba623cf 100644 --- a/src/main/java/org/olat/gui/control/OlatGuestTopNavController.java +++ b/src/main/java/org/olat/gui/control/OlatGuestTopNavController.java @@ -46,6 +46,8 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.creator.ControllerCreator; import org.olat.core.gui.control.generic.popup.PopupBrowserWindow; +import org.olat.search.SearchModule; +import org.olat.search.SearchUserToolExtension; import org.springframework.beans.factory.annotation.Autowired; /** @@ -58,6 +60,8 @@ public class OlatGuestTopNavController extends BasicController implements Lockab private Link loginLink, impressumLink; + @Autowired + private SearchModule searchModule; @Autowired private ImpressumModule impressumModule; @@ -74,6 +78,13 @@ public class OlatGuestTopNavController extends BasicController implements Lockab impressumLink.setAjaxEnabled(false); impressumLink.setTarget("_blank"); + if(searchModule.isGuestEnabled()) { + SearchUserToolExtension search = CoreSpringFactory.getImpl(SearchUserToolExtension.class); + UserTool userTool = search.createUserTool(ureq, getWindowControl(), getLocale()); + Component cmp = userTool.getMenuComponent(ureq, vc); + vc.put("search.tool", cmp); + } + // the help link HelpModule helpModule = CoreSpringFactory.getImpl(HelpModule.class); if (helpModule.isHelpEnabled()) { diff --git a/src/main/java/org/olat/gui/control/OlatTopNavController.java b/src/main/java/org/olat/gui/control/OlatTopNavController.java index 54f6b93d1d3a65df1d65df5410d9fb3d56e2ea8d..492947b279e19d2d65a4afdceb3574595409b448 100644 --- a/src/main/java/org/olat/gui/control/OlatTopNavController.java +++ b/src/main/java/org/olat/gui/control/OlatTopNavController.java @@ -39,6 +39,7 @@ import org.olat.core.gui.control.Disposable; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.id.Roles; import org.olat.core.id.User; import org.olat.core.id.UserConstants; import org.olat.core.util.StringHelper; @@ -66,8 +67,9 @@ public class OlatTopNavController extends BasicController implements LockableCon topNavVC = createVelocityContainer("topnav"); topNavVC.setDomReplacementWrapperRequired(false); // we provide our own DOM replacmenet ID - boolean isGuest = ureq.getUserSession().getRoles().isGuestOnly(); - boolean isInvitee = ureq.getUserSession().getRoles().isInvitee(); + Roles roles = ureq.getUserSession().getRoles(); + boolean isGuest = roles.isGuestOnly(); + boolean isInvitee = roles.isInvitee(); topNavVC.contextPut("isGuest", new Boolean(isGuest)); topNavVC.contextPut("isInvitee", new Boolean(isInvitee)); diff --git a/src/main/java/org/olat/gui/control/_content/guesttopnav.html b/src/main/java/org/olat/gui/control/_content/guesttopnav.html index ec5accd8eb9c7b95a1e69f90395c502c189895a7..e3650e7ac3a76232e77f1738ff2134c5f65c643a 100644 --- a/src/main/java/org/olat/gui/control/_content/guesttopnav.html +++ b/src/main/java/org/olat/gui/control/_content/guesttopnav.html @@ -10,7 +10,12 @@ <i class="o_icon o_icon_print o_icon-lg"> </i> <span>$r.translate("topnav.printview")</span> </a> - </li> + </li> + #if($r.available("search.tool")) + <li id="o_navbar_search_opener" class="o_navbar_tool dropdown"> + $r.render("search.tool") + </li> + #end #if($r.available("topnav.help")) <li id="o_navbar_help"> $r.render("topnav.help") diff --git a/src/main/java/org/olat/home/HomeMainController.java b/src/main/java/org/olat/home/HomeMainController.java index 9101bda2468c73135aa2a52658d7542e1dec8734..23117198f0577cf533a628e5041d4a91eb389990 100644 --- a/src/main/java/org/olat/home/HomeMainController.java +++ b/src/main/java/org/olat/home/HomeMainController.java @@ -103,12 +103,13 @@ public class HomeMainController extends MainLayoutBasicController implements Act if (entries.size() >= 1) { entries = entries.subList(1, entries.size()); } + + String actionText = gAE.getActionText(getLocale()); + stackPanel.rootController(actionText, contentCtr); + if (currentCtr instanceof Activateable2) { ((Activateable2) currentCtr).activate(ureq, entries, entry.getTransientState()); } - - String actionText = gAE.getActionText(getLocale()); - stackPanel.rootController(actionText, contentCtr); } } } diff --git a/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java b/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java index 0b66c48be24469e9a3fab7d85a61ba1905f30f04..e5ac3f46767d2b9d881cb0462500c76bb4a0c866 100644 --- a/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java +++ b/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java @@ -129,7 +129,7 @@ public class CPRuntimeController extends RepositoryEntryRuntimeController { OLATResource resource = entry.getOlatResource(); OlatRootFolderImpl cpRoot = FileResourceManager.getInstance().unzipContainerResource(resource); WindowControl bwControl = getSubWindowControl("Quota"); - Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), cpRoot.getRelPath(), false); + Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), cpRoot.getRelPath()); pushController(ureq, translate("tab.quota.edit"), quotaCtrl); setActiveTool(quotaLink); } diff --git a/src/main/java/org/olat/ims/qti/QTI12ResultDetailsController.java b/src/main/java/org/olat/ims/qti/QTI12ResultDetailsController.java index da10dac2560e8cdf126279f5b1193d4366285a46..dcf627e99aa0b8142e19cd400ade5fb19d3319cb 100644 --- a/src/main/java/org/olat/ims/qti/QTI12ResultDetailsController.java +++ b/src/main/java/org/olat/ims/qti/QTI12ResultDetailsController.java @@ -65,6 +65,7 @@ import org.olat.ims.qti.process.AssessmentInstance; import org.olat.ims.qti.process.FilePersister; import org.olat.ims.qti.process.Persister; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.modules.iq.IQManager; import org.olat.modules.iq.IQRetrievedEvent; import org.olat.repository.RepositoryEntry; @@ -262,7 +263,7 @@ public class QTI12ResultDetailsController extends BasicController { Boolean passed = new Boolean(ac.isPassed()); ScoreEvaluation sceval = new ScoreEvaluation(score, passed, Boolean.FALSE, new Long(ai.getAssessID())); UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course); - testNode.updateUserScoreEvaluation(sceval, userCourseEnv, assessedIdentity, true); + testNode.updateUserScoreEvaluation(sceval, userCourseEnv, assessedIdentity, true, Role.coach); //cleanup ai.cleanUp(); diff --git a/src/main/java/org/olat/ims/qti/QTIModule.java b/src/main/java/org/olat/ims/qti/QTIModule.java index 4949bb2bf9516d0065a8011d4a657e7d7f52675e..a87d50373398808e54b082c815236fd1f6fefc9e 100644 --- a/src/main/java/org/olat/ims/qti/QTIModule.java +++ b/src/main/java/org/olat/ims/qti/QTIModule.java @@ -26,11 +26,13 @@ package org.olat.ims.qti; import org.olat.core.configuration.AbstractSpringModule; +import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.ims.qti.repository.handlers.QTISurveyHandler; import org.olat.ims.qti.repository.handlers.QTITestHandler; import org.olat.repository.handlers.RepositoryHandlerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; /** @@ -38,8 +40,13 @@ import org.springframework.stereotype.Service; * * @author Mike Stock */ -@Service("") +@Service public class QTIModule extends AbstractSpringModule { + + private static final String CREATE_RESOURCES_ENABLED = "qti12.create.resources.enabled"; + + @Value("${qti12.create.resources.enabled:false}") + private boolean createResourcesEnabled; @Autowired public QTIModule(CoordinatorManager coordinatorManager) { @@ -50,11 +57,23 @@ public class QTIModule extends AbstractSpringModule { public void init() { RepositoryHandlerFactory.registerHandler(new QTISurveyHandler(), 10); RepositoryHandlerFactory.registerHandler(new QTITestHandler(), 10); + initFromChangedProperties(); } - @Override protected void initFromChangedProperties() { - // + String mathExtensionObj = getStringPropertyValue(CREATE_RESOURCES_ENABLED, true); + if(StringHelper.containsNonWhitespace(mathExtensionObj)) { + createResourcesEnabled = "true".equals(mathExtensionObj); + } + } + + public boolean isCreateResourcesEnabled() { + return createResourcesEnabled; + } + + public void setCreateResourcesEnabled(boolean enabled) { + createResourcesEnabled = enabled; + setStringProperty(CREATE_RESOURCES_ENABLED, enabled ? "true" : "false", true); } } diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java b/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java index d79a0996bbf263b29e7d5805481bee5e1a9c5e5b..69dccd96f711a4b53bd0c12f4127c953db971a60 100644 --- a/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java +++ b/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java @@ -52,6 +52,7 @@ import org.olat.fileresource.FileResourceManager; import org.olat.ims.qti.QTI12EditorController; import org.olat.ims.qti.QTI12PreviewController; import org.olat.ims.qti.QTIConstants; +import org.olat.ims.qti.QTIModule; import org.olat.ims.qti.editor.QTIEditHelper; import org.olat.ims.qti.editor.QTIEditorMainController; import org.olat.ims.qti.editor.QTIEditorPackageImpl; @@ -61,8 +62,8 @@ import org.olat.ims.qti.editor.beecom.parser.ParserManager; import org.olat.ims.qti.fileresource.TestFileResource; import org.olat.ims.qti.qpool.QTI12ItemFactory.Type; import org.olat.ims.qti.questionimport.ItemAndMetadata; -import org.olat.ims.resources.IMSEntityResolver; import org.olat.ims.qti21.pool.QTI12And21PoolWordExport; +import org.olat.ims.resources.IMSEntityResolver; import org.olat.modules.qpool.ExportFormatOptions; import org.olat.modules.qpool.ExportFormatOptions.Outcome; import org.olat.modules.qpool.QItemFactory; @@ -101,6 +102,8 @@ public class QTIQPoolServiceProvider implements QPoolSPI { @Autowired private DB dbInstance; @Autowired + private QTIModule qtiModule; + @Autowired private QPoolFileStorage qpoolFileStorage; @Autowired private QLicenseDAO qLicenseDao; @@ -143,12 +146,7 @@ public class QTIQPoolServiceProvider implements QPoolSPI { @Override public boolean isCompatible(String filename, File file) { - boolean ok = new ItemFileResourceValidator().validate(filename, file); - return ok; - } - @Override - public boolean isCompatible(String filename, VFSLeaf file) { - boolean ok = new ItemFileResourceValidator().validate(filename, file); + boolean ok = qtiModule.isCreateResourcesEnabled() && new ItemFileResourceValidator().validate(filename, file); return ok; } @@ -159,12 +157,14 @@ public class QTIQPoolServiceProvider implements QPoolSPI { @Override public List<QItemFactory> getItemfactories() { - List<QItemFactory> factories = new ArrayList<QItemFactory>(); - factories.add(new QTI12ItemFactory(Type.sc)); - factories.add(new QTI12ItemFactory(Type.mc)); - factories.add(new QTI12ItemFactory(Type.kprim)); - factories.add(new QTI12ItemFactory(Type.fib)); - factories.add(new QTI12ItemFactory(Type.essay)); + List<QItemFactory> factories = new ArrayList<>(); + if(qtiModule.isCreateResourcesEnabled()) { + factories.add(new QTI12ItemFactory(Type.sc)); + factories.add(new QTI12ItemFactory(Type.mc)); + factories.add(new QTI12ItemFactory(Type.kprim)); + factories.add(new QTI12ItemFactory(Type.fib)); + factories.add(new QTI12ItemFactory(Type.essay)); + } return factories; } diff --git a/src/main/java/org/olat/ims/qti/render/LocalizedXSLTransformer.java b/src/main/java/org/olat/ims/qti/render/LocalizedXSLTransformer.java index 2c7dba6f738b6129642e5e5d50f757db6e56f07f..47ca6dcb0b767d789ff5e558d90741e1bb666aee 100644 --- a/src/main/java/org/olat/ims/qti/render/LocalizedXSLTransformer.java +++ b/src/main/java/org/olat/ims/qti/render/LocalizedXSLTransformer.java @@ -51,13 +51,14 @@ import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.dom.DOMDocument; import org.dom4j.io.DocumentSource; +import org.olat.core.CoreSpringFactory; import org.olat.core.dispatcher.impl.StaticMediaDispatcher; import org.olat.core.gui.translator.Translator; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.Util; -import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.i18n.I18nModule; import org.olat.ims.qti.QTI12ResultDetailsController; import org.olat.ims.resources.IMSEntityResolver; import org.xml.sax.EntityResolver; @@ -116,11 +117,12 @@ public class LocalizedXSLTransformer { */ // cluster_ok only in VM public static LocalizedXSLTransformer getInstance(Locale locale) { - LocalizedXSLTransformer instance = instanceHash.get(I18nManager.getInstance().getLocaleKey(locale)); + I18nModule i18nModule = CoreSpringFactory.getImpl(I18nModule.class); + LocalizedXSLTransformer instance = instanceHash.get(i18nModule.getLocaleKey(locale)); if (instance == null) { Translator trans = Util.createPackageTranslator(QTI12ResultDetailsController.class, locale); LocalizedXSLTransformer newInstance = new LocalizedXSLTransformer(trans); - instance = instanceHash.putIfAbsent(I18nManager.getInstance().getLocaleKey(locale), newInstance); //see javadoc of ConcurrentHashMap + instance = instanceHash.putIfAbsent(i18nModule.getLocaleKey(locale), newInstance); //see javadoc of ConcurrentHashMap if(instance == null) { //newInstance was put into the map instance = newInstance; } diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java index f55dc3d24c2ff680bb457f4e3761a85c34c7b194..69221a6b0e4a06af86edde4ca610406b56d34a31 100644 --- a/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java +++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java @@ -44,6 +44,7 @@ import org.olat.course.assessment.AssessmentMode; import org.olat.course.assessment.manager.UserCourseInformationsManager; import org.olat.fileresource.FileResourceManager; import org.olat.fileresource.types.ResourceEvaluation; +import org.olat.ims.qti.QTIModule; import org.olat.ims.qti.QTIRuntimeController; import org.olat.ims.qti.editor.QTIEditorMainController; import org.olat.ims.qti.fileresource.TestFileResource; @@ -77,7 +78,7 @@ public class QTITestHandler extends QTIHandler { @Override public boolean isCreate() { - return true; + return CoreSpringFactory.getImpl(QTIModule.class).isCreateResourcesEnabled(); } @Override diff --git a/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java index 320f8eb2fcd6a14517abcac524f46ddf22ed5599..900258218640013818ddb9509e95aea7a058668e 100644 --- a/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java +++ b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java @@ -20,6 +20,7 @@ package org.olat.ims.qti.statistics.ui; import java.io.File; +import java.util.Collections; import java.util.List; import org.dom4j.Document; @@ -43,11 +44,13 @@ import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.i18n.I18nModule; import org.olat.course.CourseFactory; import org.olat.course.ICourse; +import org.olat.course.archiver.ScoreAccountingHelper; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.nodes.IQTESTCourseNode; import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.group.BusinessGroupService; import org.olat.ims.qti.QTIResultManager; import org.olat.ims.qti.container.AssessmentContext; import org.olat.ims.qti.process.AssessmentFactory; @@ -55,6 +58,7 @@ import org.olat.ims.qti.process.AssessmentInstance; import org.olat.ims.qti.process.FilePersister; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.modules.iq.IQManager; import org.olat.modules.iq.IQRetrievedEvent; import org.olat.user.UserManager; @@ -70,30 +74,57 @@ public class QTI12PullTestsToolController extends BasicController implements Act private final Link pullButton; private DialogBoxController retrieveConfirmationCtr; - + private final IQTESTCourseNode courseNode; private final CourseEnvironment courseEnv; - private final List<Identity> assessedIdentities; + //private final List<Identity> assessedIdentities; + private final AssessmentToolOptions asOptions; @Autowired private IQManager iqm; @Autowired private UserManager userManager; + @Autowired + private BusinessGroupService businessGroupService; public QTI12PullTestsToolController(UserRequest ureq, WindowControl wControl, CourseEnvironment courseEnv, AssessmentToolOptions asOptions, IQTESTCourseNode courseNode) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(QTIResultManager.class, getLocale(), getTranslator())); - this.courseEnv = courseEnv; this.courseNode = courseNode; - this.assessedIdentities = asOptions.getIdentities(); + this.asOptions = asOptions; + + boolean enabled = false; + for(Identity assessedIdentity:getIdentities()) { + if(courseNode.isQTI12TestRunning(assessedIdentity, courseEnv)) { + enabled = true; + break; + } + } pullButton = LinkFactory.createButton("menu.pull.tests.title", null, this); pullButton.setTranslator(getTranslator()); + pullButton.setEnabled(enabled); putInitialPanel(pullButton); getInitialComponent().setSpanAsDomReplaceable(true); // override to wrap panel as span to not break link layout } + + private List<Identity> getIdentities() { + List<Identity> identities; + if(asOptions.getGroup() == null && asOptions.getIdentities() == null) { + if(courseEnv != null) { + identities = ScoreAccountingHelper.loadUsers(courseEnv); + } else { + identities = Collections.emptyList(); + } + } else if (asOptions.getIdentities() != null) { + identities = asOptions.getIdentities(); + } else { + identities = businessGroupService.getMembers(asOptions.getGroup()); + } + return identities; + } @Override protected void doDispose() { @@ -116,7 +147,9 @@ public class QTI12PullTestsToolController extends BasicController implements Act protected void event(UserRequest ureq, Controller source, Event event) { if(retrieveConfirmationCtr == source) { if(DialogBoxUIFactory.isYesEvent(event)) { - doRetrieveTests(); + @SuppressWarnings("unchecked") + List<Identity> assessedIdentities = (List<Identity>)retrieveConfirmationCtr.getUserObject(); + doRetrieveTests(assessedIdentities); } removeAsListenerAndDispose(retrieveConfirmationCtr); retrieveConfirmationCtr = null; @@ -126,6 +159,7 @@ public class QTI12PullTestsToolController extends BasicController implements Act private void confirmPull(UserRequest ureq) { int count = 0; StringBuilder fullnames = new StringBuilder(256); + List<Identity> assessedIdentities = getIdentities(); for(Identity assessedIdentity:assessedIdentities) { if(courseNode.isQTI12TestRunning(assessedIdentity, courseEnv)) { if(fullnames.length() > 0) fullnames.append(", "); @@ -143,14 +177,16 @@ public class QTI12PullTestsToolController extends BasicController implements Act String title = translate("retrievetest.confirm.title"); String text = translate("retrievetest.confirm.text", new String[]{ fullnames.toString() }); retrieveConfirmationCtr = activateYesNoDialog(ureq, title, text, retrieveConfirmationCtr); + retrieveConfirmationCtr.setUserObject(assessedIdentities); } else { String title = translate("retrievetest.confirm.title"); String text = translate("retrievetest.confirm.text.plural", new String[]{ fullnames.toString() }); retrieveConfirmationCtr = activateYesNoDialog(ureq, title, text, retrieveConfirmationCtr); + retrieveConfirmationCtr.setUserObject(assessedIdentities); } } - private void doRetrieveTests() { + private void doRetrieveTests(List<Identity> assessedIdentities) { ICourse course = CourseFactory.loadCourse(courseEnv.getCourseResourceableId()); for(Identity assessedIdentity:assessedIdentities) { if(courseNode.isQTI12TestRunning(assessedIdentity, courseEnv)) { @@ -181,7 +217,7 @@ public class QTI12PullTestsToolController extends BasicController implements Act Boolean passed = new Boolean(ac.isPassed()); ScoreEvaluation sceval = new ScoreEvaluation(score, passed, Boolean.FALSE, new Long(ai.getAssessID())); UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course); - courseNode.updateUserScoreEvaluation(sceval, userCourseEnv, assessedIdentity, true); + courseNode.updateUserScoreEvaluation(sceval, userCourseEnv, assessedIdentity, true, Role.coach); //cleanup ai.cleanUp(); diff --git a/src/main/java/org/olat/ims/qti/statistics/ui/_content/print.html b/src/main/java/org/olat/ims/qti/statistics/ui/_content/print.html index 6d9bba90ae0d2e0140215ef6cb939f11371c2608..a2daff5905528bda8931c057d759e5b08dd61014 100644 --- a/src/main/java/org/olat/ims/qti/statistics/ui/_content/print.html +++ b/src/main/java/org/olat/ims/qti/statistics/ui/_content/print.html @@ -9,6 +9,7 @@ #end <script type='text/javascript'> /* <![CDATA[ */ - window.print(); + ## Execute deferred. Gives browser the time to finish the page rendering first before executing the print dialog. + jQuery(function() {window.print();}); /* ]]> */ </script> \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/AssessmentTestMarks.java b/src/main/java/org/olat/ims/qti21/AssessmentTestMarks.java index b13b2385b480b4d96553be659f85f616e0b26bfc..08187568204db712d72a83a1b53a7f085a94d24c 100644 --- a/src/main/java/org/olat/ims/qti21/AssessmentTestMarks.java +++ b/src/main/java/org/olat/ims/qti21/AssessmentTestMarks.java @@ -33,4 +33,8 @@ public interface AssessmentTestMarks extends CreateInfo, ModifiedInfo { public String getMarks(); public void setMarks(String marks); + + public String getHiddenRubrics(); + + public void setHiddenRubrics(String rubrics); } diff --git a/src/main/java/org/olat/ims/qti21/QTI21Constants.java b/src/main/java/org/olat/ims/qti21/QTI21Constants.java index e73a308df2438f6af62a7a16446ae33b9f1c7e34..82ff66ab6240b86674faa2b21ee45c88f1ca9722 100644 --- a/src/main/java/org/olat/ims/qti21/QTI21Constants.java +++ b/src/main/java/org/olat/ims/qti21/QTI21Constants.java @@ -68,6 +68,12 @@ public class QTI21Constants { public static final ComplexReferenceIdentifier PASS_CLX_IDENTIFIER = ComplexReferenceIdentifier.parseString(PASS); + public static final String NUM_ATTEMPTS = "numAttempts"; + + public static final Identifier NUM_ATTEMPTS_IDENTIFIER = Identifier.assumedLegal(NUM_ATTEMPTS); + + public static final ComplexReferenceIdentifier NUM_ATTEMPTS_CLX_IDENTIFIER = ComplexReferenceIdentifier.parseString(NUM_ATTEMPTS); + public static final String FEEDBACKBASIC = "FEEDBACKBASIC"; public static final Identifier FEEDBACKBASIC_IDENTIFIER = Identifier.parseString(FEEDBACKBASIC); @@ -82,12 +88,16 @@ public class QTI21Constants { public static final Identifier CORRECT_IDENTIFIER = Identifier.parseString(CORRECT); + public static final ComplexReferenceIdentifier CORRECT_CLX_IDENTIFIER = ComplexReferenceIdentifier.parseString(CORRECT); + public static final IdentifierValue CORRECT_IDENTIFIER_VALUE = new IdentifierValue(CORRECT); public static final String INCORRECT = "incorrect"; public static final Identifier INCORRECT_IDENTIFIER = Identifier.parseString(INCORRECT); + public static final ComplexReferenceIdentifier INCORRECT_CLX_IDENTIFIER = ComplexReferenceIdentifier.parseString(INCORRECT); + public static final IdentifierValue INCORRECT_IDENTIFIER_VALUE = new IdentifierValue(INCORRECT); public static final String WRONG = "wrong"; @@ -100,6 +110,8 @@ public class QTI21Constants { public static final Identifier EMPTY_IDENTIFIER = Identifier.parseString(EMPTY); + public static final ComplexReferenceIdentifier EMPTY_CLX_IDENTIFIER = ComplexReferenceIdentifier.parseString(EMPTY); + public static final IdentifierValue EMPTY_IDENTIFIER_VALUE = new IdentifierValue(EMPTY); public static final String ANSWERED = "answered"; @@ -137,6 +149,8 @@ public class QTI21Constants { public static final String CSS_MATCH_DRAG_AND_DROP = "match_dnd"; + public static final String CSS_MATCH_KPRIM = "match_krpim"; + public static final String CSS_MATCH_SOURCE_TOP = "source-top"; public static final String CSS_MATCH_SOURCE_LEFT = "source-left"; @@ -145,7 +159,7 @@ public class QTI21Constants { public static final String CSS_MATCH_SOURCE_BOTTOM = "source-bottom"; - + public static final String CSS_INTERACTION_RESPONSIVE = "interaction-responsive"; } diff --git a/src/main/java/org/olat/ims/qti21/QTI21Service.java b/src/main/java/org/olat/ims/qti21/QTI21Service.java index 14233dbcceadbdda86f03b43b7167732f00fa3cf..5942f3d10abc596177fb72c41d8b005888070c5f 100644 --- a/src/main/java/org/olat/ims/qti21/QTI21Service.java +++ b/src/main/java/org/olat/ims/qti21/QTI21Service.java @@ -219,6 +219,13 @@ public interface QTI21Service { */ public AssessmentSessionAuditLogger getAssessmentSessionAuditLogger(AssessmentTestSession session, boolean authorMode); + /** + * + * @param session The test session + * @return The file or null if it doesn't exists + */ + public File getAssessmentSessionAuditLogFile(AssessmentTestSession session); + /** * This will return the last session if it's not finished, terminated or exploded. * @@ -237,7 +244,7 @@ public interface QTI21Service { public AssessmentTestSession updateAssessmentTestSession(AssessmentTestSession session); - public boolean isRunningAssessmentTestSession(RepositoryEntry entry, String subIdent, RepositoryEntry testEntry); + public boolean isRunningAssessmentTestSession(RepositoryEntry entry, String subIdent, RepositoryEntry testEntry, List<? extends IdentityRef> identities); public List<AssessmentTestSession> getRunningAssessmentTestSession(RepositoryEntry entry, String subIdent, RepositoryEntry testEntry); diff --git a/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java b/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java index ac8fd02c189bfa966397e0c6400cf2c624341e95..f1fc1c28ece4b2c404a23a0f6b997e25aa0cab0a 100644 --- a/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java +++ b/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java @@ -452,7 +452,7 @@ public class AssessmentTestSessionDAO { return query.getResultList(); } - public boolean hasRunningTestSessions(RepositoryEntryRef entry, String courseSubIdent, RepositoryEntry testEntry) { + public boolean hasRunningTestSessions(RepositoryEntryRef entry, String courseSubIdent, RepositoryEntry testEntry, List<? extends IdentityRef> identities) { StringBuilder sb = new StringBuilder(); sb.append("select session.key from qtiassessmenttestsession session") .append(" left join session.testEntry testEntry") @@ -464,6 +464,9 @@ public class AssessmentTestSessionDAO { } else { sb.append(" and session.subIdent is null"); } + if(identities != null && identities.size() > 0) { + sb.append(" and session.identity in (:identityKeys)"); + } TypedQuery<Long> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Long.class) @@ -474,6 +477,10 @@ public class AssessmentTestSessionDAO { if(StringHelper.containsNonWhitespace(courseSubIdent)) { query.setParameter("subIdent", courseSubIdent); } + if(identities != null && identities.size() > 0) { + query.setParameter("identityKeys", identities); + } + List<Long> found = query.getResultList(); return found == null || found.isEmpty() || found.get(0) == null ? false : found.get(0) >= 0; } diff --git a/src/main/java/org/olat/ims/qti21/manager/OpenOLATExtensionPackage.java b/src/main/java/org/olat/ims/qti21/manager/OpenOLATExtensionPackage.java new file mode 100644 index 0000000000000000000000000000000000000000..769acf894fb9fcdc3966bb5691a75ff64df72495 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/manager/OpenOLATExtensionPackage.java @@ -0,0 +1,191 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.manager; + +import java.util.Collections; +import java.util.Map; + +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.ims.qti21.manager.extensions.MaximaOperator; + +import uk.ac.ed.ph.jacomax.JacomaxRuntimeException; +import uk.ac.ed.ph.jacomax.MaximaConfiguration; +import uk.ac.ed.ph.jqtiplus.ExtensionNamespaceInfo; +import uk.ac.ed.ph.jqtiplus.JqtiExtensionPackage; +import uk.ac.ed.ph.jqtiplus.JqtiLifecycleEventType; +import uk.ac.ed.ph.jqtiplus.exception.QtiLogicException; +import uk.ac.ed.ph.jqtiplus.node.QtiNode; +import uk.ac.ed.ph.jqtiplus.node.expression.ExpressionParent; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.CustomOperator; +import uk.ac.ed.ph.jqtiplus.node.item.interaction.CustomInteraction; +import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltStylesheetCache; +import uk.ac.ed.ph.qtiworks.mathassess.XsltStylesheetCacheAdapter; +import uk.ac.ed.ph.qtiworks.mathassess.glue.maxima.MaximaLaunchHelper; +import uk.ac.ed.ph.qtiworks.mathassess.glue.maxima.QtiMaximaProcess; +import uk.ac.ed.ph.qtiworks.mathassess.pooling.QtiMaximaProcessPoolManager; +import uk.ac.ed.ph.snuggletex.utilities.StylesheetCache; + +/** + * + * Initial date: 3 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class OpenOLATExtensionPackage implements JqtiExtensionPackage<OpenOLATExtensionPackage> { + + private static final OLog log = Tracing.createLoggerFor(OpenOLATExtensionPackage.class); + + private final ThreadLocal<QtiMaximaProcess> sessionThreadLocal; + + private final StylesheetCache snuggleStylesheetCache; + private QtiMaximaProcessPoolManager qtiMaximaProcessPoolManager; + + public OpenOLATExtensionPackage(final XsltStylesheetCache xsltStylesheetCache) { + snuggleStylesheetCache = new XsltStylesheetCacheAdapter(xsltStylesheetCache); + + /* Create ThreadLocal for communicating with maxima */ + this.sessionThreadLocal = new ThreadLocal<QtiMaximaProcess>(); + } + + @Override + public String getDisplayName() { + return "MAXIMA Extension pack"; + } + + @Override + public Map<String, ExtensionNamespaceInfo> getNamespaceInfoMap() { + return Collections.emptyMap(); + } + + @Override + public boolean implementsCustomOperator(String operatorClassName) { + return MaximaOperator.class.getName().equals(operatorClassName); + } + + @Override + public CustomOperator<OpenOLATExtensionPackage> createCustomOperator(ExpressionParent expressionParent, String operatorClassName) { + return new MaximaOperator(expressionParent); + } + + @Override + public boolean implementsCustomInteraction(String interactionClassName) { + return false; + } + + @Override + public CustomInteraction<OpenOLATExtensionPackage> createCustomInteraction(QtiNode parentObject, String interactionClassName) { + return null; + } + + //------------------------------------------------------------------------ + + @Override + public void lifecycleEvent(final Object source, final JqtiLifecycleEventType eventType) { + //log.debug("Received lifecycle event {}" + eventType); + switch (eventType) { + case MANAGER_INITIALISED: + startMaximaPool(); + break; + + case MANAGER_DESTROYED: + closeMaximaPool(); + break; + + case ITEM_TEMPLATE_PROCESSING_STARTING: + case ITEM_RESPONSE_PROCESSING_STARTING: + case TEST_OUTCOME_PROCESSING_STARTING: + /* Rather than creating a Maxima process at this point that may + * not be used, + * we'll wait until it is first needed. */ + break; + + case ITEM_TEMPLATE_PROCESSING_FINISHED: + case ITEM_RESPONSE_PROCESSING_FINISHED: + case TEST_OUTCOME_PROCESSING_FINISHED: + releaseMaximaSessionForThread(); + break; + + default: + break; + } + } + + private void startMaximaPool() { + final MaximaConfiguration maximaConfiguration = MaximaLaunchHelper.tryMaximaConfiguration(); + if (maximaConfiguration==null) { + log.warn("Failed to obtain a MaximaConfiguration. MathAssess extensions will not work and this package should NOT be used."); + return; + } + try { + qtiMaximaProcessPoolManager = new QtiMaximaProcessPoolManager(); + qtiMaximaProcessPoolManager.setMaximaConfiguration(maximaConfiguration); + qtiMaximaProcessPoolManager.setStylesheetCache(snuggleStylesheetCache); + qtiMaximaProcessPoolManager.init(); + + log.info("MathAssessExtensionPackage successfully initiated using {} to handle communication with Maxima for MathAssess extensions", QtiMaximaProcessPoolManager.class.getSimpleName()); + } + catch (final JacomaxRuntimeException e) { + qtiMaximaProcessPoolManager = null; + log.warn("Failed to start the {}. MathAssess extensions will not work and this package should NOT be used" + + QtiMaximaProcessPoolManager.class.getSimpleName()); + } + } + + private void closeMaximaPool() { + if (qtiMaximaProcessPoolManager != null) { + log.info("Closing {}" + qtiMaximaProcessPoolManager); + try { + qtiMaximaProcessPoolManager.shutdown(); + } + catch (final JacomaxRuntimeException e) { + /* We'll log this but allow things to continue, as pool closure would normally happen on application exit */ + log.warn("Failed to close the {}." + QtiMaximaProcessPoolManager.class.getSimpleName()); + } + } + } + + // ------------------------------------------------------------------------ + + public QtiMaximaProcess obtainMaximaSessionForThread() { + QtiMaximaProcess maximaSession = sessionThreadLocal.get(); + if (maximaSession == null) { + if (qtiMaximaProcessPoolManager != null) { + log.debug("Obtaining new maxima process from pool for this request"); + /* Need to get a new process from pool */ + maximaSession = qtiMaximaProcessPoolManager.obtainProcess(); + sessionThreadLocal.set(maximaSession); + } + else { + throw new QtiLogicException("The MathAssess extensions package could not be configured to communicate with Maxima. This package should not have been used in this case"); + } + } + return maximaSession; + } + + private void releaseMaximaSessionForThread() { + final QtiMaximaProcess maximaSession = sessionThreadLocal.get(); + if (maximaSession != null && qtiMaximaProcessPoolManager != null) { + log.debug("Finished with maxima process for this request - returning to pool"); + qtiMaximaProcessPoolManager.returnProcess(maximaSession); + sessionThreadLocal.set(null); + } + } +} diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java index aadf4ec80bfea5c3a0a1d222926571dacd79ef4a..c00beefe3cf93ee76249c01dc40f91153e566c49 100644 --- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java +++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java @@ -208,6 +208,7 @@ public class QTI21ServiceImpl implements QTI21Service, UserDataDeletable, Initia if (qtiModule.isMathAssessExtensionEnabled()) { log.info("Enabling the MathAssess extensions"); extensionPackages.add(new MathAssessExtensionPackage(xsltStylesheetCache)); + extensionPackages.add(new OpenOLATExtensionPackage(xsltStylesheetCache)); } jqtiExtensionManager = new JqtiExtensionManager(extensionPackages); xsltStylesheetManager = new XsltStylesheetManager(new ClassPathResourceLocator(), xsltStylesheetCache); @@ -446,6 +447,12 @@ public class QTI21ServiceImpl implements QTI21Service, UserDataDeletable, Initia return rows > 0; } + @Override + public File getAssessmentSessionAuditLogFile(AssessmentTestSession session) { + File userStorage = testSessionDao.getSessionStorage(session); + return new File(userStorage, "audit.log"); + } + @Override public AssessmentSessionAuditLogger getAssessmentSessionAuditLogger(AssessmentTestSession session, boolean authorMode) { if(authorMode) { @@ -455,8 +462,7 @@ public class QTI21ServiceImpl implements QTI21Service, UserDataDeletable, Initia return new AssessmentSessionAuditOLog(); } try { - File userStorage = testSessionDao.getSessionStorage(session); - File auditLog = new File(userStorage, "audit.log"); + File auditLog = getAssessmentSessionAuditLogFile(session); FileOutputStream outputStream = new FileOutputStream(auditLog, true); return new AssessmentSessionAuditFileLog(outputStream); } catch (IOException e) { @@ -532,8 +538,8 @@ public class QTI21ServiceImpl implements QTI21Service, UserDataDeletable, Initia } @Override - public boolean isRunningAssessmentTestSession(RepositoryEntry entry, String subIdent, RepositoryEntry testEntry) { - return testSessionDao.hasRunningTestSessions(entry, subIdent, testEntry); + public boolean isRunningAssessmentTestSession(RepositoryEntry entry, String subIdent, RepositoryEntry testEntry, List<? extends IdentityRef> identities) { + return testSessionDao.hasRunningTestSessions(entry, subIdent, testEntry, identities); } @Override diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/MatchInteractionArchive.java b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/MatchInteractionArchive.java index 9c45638a224bd2f77c378f7ad48ee044f89b758c..22057316ae1921846875a187039c1e7d219dc7a1 100644 --- a/src/main/java/org/olat/ims/qti21/manager/archive/interactions/MatchInteractionArchive.java +++ b/src/main/java/org/olat/ims/qti21/manager/archive/interactions/MatchInteractionArchive.java @@ -26,8 +26,10 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.openxml.OpenXMLWorkbook; import org.olat.core.util.openxml.OpenXMLWorksheet.Row; import org.olat.ims.qti21.AssessmentResponse; +import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.manager.CorrectResponsesUtil; import org.olat.ims.qti21.manager.archive.SimpleContentRenderer; +import org.olat.ims.qti21.model.QTI21QuestionType; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction; @@ -61,7 +63,8 @@ public class MatchInteractionArchive extends DefaultInteractionArchive { public int writeHeader2(AssessmentItem item, Interaction interaction, int itemNumber, int interactionNumber, Row dataRow, int col, OpenXMLWorkbook workbook) { MatchInteraction matchInteraction = (MatchInteraction)interaction; - boolean kprim = matchInteraction.getResponseIdentifier().toString().startsWith("KPRIM_"); + boolean kprim = matchInteraction.getResponseIdentifier().toString().startsWith("KPRIM_") + || QTI21QuestionType.hasClass(matchInteraction, QTI21Constants.CSS_MATCH_KPRIM); String fix = kprim ? "_KP" : "_K"; int numOfChoices = matchInteraction.getSimpleMatchSets().get(0).getSimpleAssociableChoices().size(); @@ -84,7 +87,8 @@ public class MatchInteractionArchive extends DefaultInteractionArchive { if(!StringHelper.containsNonWhitespace(stringuifiedResponse)) { col += matchInteraction.getSimpleMatchSets().get(0).getSimpleAssociableChoices().size(); } else { - boolean kprim = matchInteraction.getResponseIdentifier().toString().startsWith("KPRIM_"); + boolean kprim = matchInteraction.getResponseIdentifier().toString().startsWith("KPRIM_") + || QTI21QuestionType.hasClass(matchInteraction, QTI21Constants.CSS_MATCH_KPRIM); Set<String> correctAnswers = CorrectResponsesUtil.getCorrectDirectPairResponses(item, matchInteraction, false); List<String> responses = CorrectResponsesUtil.parseResponses(stringuifiedResponse); diff --git a/src/main/java/org/olat/ims/qti21/manager/extensions/MaximaOperator.java b/src/main/java/org/olat/ims/qti21/manager/extensions/MaximaOperator.java new file mode 100644 index 0000000000000000000000000000000000000000..17082a216b2b29c46daee3c3c30b4f9a55109198 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/manager/extensions/MaximaOperator.java @@ -0,0 +1,155 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.manager.extensions; + +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.ims.qti21.manager.OpenOLATExtensionPackage; + +import uk.ac.ed.ph.jacomax.MaximaTimeoutException; +import uk.ac.ed.ph.jqtiplus.attribute.Attribute; +import uk.ac.ed.ph.jqtiplus.attribute.AttributeList; +import uk.ac.ed.ph.jqtiplus.node.expression.ExpressionParent; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.CustomOperator; +import uk.ac.ed.ph.jqtiplus.running.ProcessingContext; +import uk.ac.ed.ph.jqtiplus.validation.ValidationContext; +import uk.ac.ed.ph.jqtiplus.value.BaseType; +import uk.ac.ed.ph.jqtiplus.value.BooleanValue; +import uk.ac.ed.ph.jqtiplus.value.Cardinality; +import uk.ac.ed.ph.jqtiplus.value.FloatValue; +import uk.ac.ed.ph.jqtiplus.value.IntegerValue; +import uk.ac.ed.ph.jqtiplus.value.NullValue; +import uk.ac.ed.ph.jqtiplus.value.Value; +import uk.ac.ed.ph.qtiworks.mathassess.GlueValueBinder; +import uk.ac.ed.ph.qtiworks.mathassess.glue.MathAssessBadCasCodeException; +import uk.ac.ed.ph.qtiworks.mathassess.glue.MathsContentTooComplexException; +import uk.ac.ed.ph.qtiworks.mathassess.glue.maxima.QtiMaximaProcess; +import uk.ac.ed.ph.qtiworks.mathassess.glue.maxima.QtiMaximaTypeConversionException; +import uk.ac.ed.ph.qtiworks.mathassess.glue.types.ValueWrapper; +import uk.ac.ed.ph.qtiworks.mathassess.value.ReturnTypeType; + +/** + * + * Initial date: 5 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class MaximaOperator extends CustomOperator<OpenOLATExtensionPackage> { + + private final static OLog log = Tracing.createLoggerFor(MaximaOperator.class); + + private static final long serialVersionUID = -5085928825187250511L; + + public MaximaOperator(final ExpressionParent parent) { + super(parent); + } + + @Override + protected Value evaluateSelf(OpenOLATExtensionPackage jqtiExtensionPackage, ProcessingContext context, Value[] childValues, int depth) { + AttributeList attributes = getAttributes(); + Attribute<?> attrValue = attributes.get("value"); + String code = (String)attrValue.getValue(); + + log.debug("Performing scriptRule: code={}, simplify={}" + code); + + /* Pass variables to Maxima */ + final QtiMaximaProcess qtiMaximaProcess = jqtiExtensionPackage.obtainMaximaSessionForThread(); + for(int i=0; i<childValues.length; i++) { + Value childValue = childValues[i]; + String val = getValue(childValue); + code = code.replace("$(" + (i+1) + ")", val); + } + + /* Run code */ + log.debug("Executing scriptRule code"); + try { + qtiMaximaProcess.executeScriptRule(code, true); + } catch (final MaximaTimeoutException e) { + context.fireRuntimeError(this, "A timeout occurred executing the ScriptRule logic. Not setting QTI variables and returing FALSE"); + return BooleanValue.FALSE; + } catch (final RuntimeException e) { + context.fireRuntimeError(this, "An unexpected problem occurred while trying to run the scriptRule logic. Not setting QTI variables and returing FALSE"); + return BooleanValue.FALSE; + } + + /* Read variables back */ + log.debug("Reading variables back from Maxima"); + + /* Run Maxima code and extract result */ + log.info("Running code to determine result of MAXIMA operator"); + + final Class<? extends ValueWrapper> resultClass = GlueValueBinder.getCasReturnClass(ReturnTypeType.FLOAT); + ValueWrapper maximaResult; + try { + maximaResult = qtiMaximaProcess.executeCasProcess(code, true, resultClass); + } catch (final MaximaTimeoutException e) { + context.fireRuntimeError(this, "A timeout occurred executing the CasCondition logic. Returning NULL"); + return NullValue.INSTANCE; + } catch (final MathsContentTooComplexException e) { + context.fireRuntimeError(this, "An unexpected problem occurred querying the result of CasProcess, so returning NULL"); + return NullValue.INSTANCE; + } catch (final MathAssessBadCasCodeException e) { + context.fireRuntimeError(this, "Your CasProcess code did not work as expected. The CAS input was '" + + e.getMaximaInput() + + "' and the CAS output was '" + + e.getMaximaOutput() + + "'. The failure reason was: " + e.getReason()); + return NullValue.INSTANCE; + } catch (final QtiMaximaTypeConversionException e) { + context.fireRuntimeError(this, "Your CasProcess code did not produce a result that could be converted into the required QTI type. The CAS input was '" + + e.getMaximaInput() + + "' and the CAS output was '" + + e.getMaximaOutput() + + "'"); + return NullValue.INSTANCE; + } catch (final RuntimeException e) { + log.warn("Unexpected Maxima failure", e); + context.fireRuntimeError(this, "An unexpected problem occurred while executing this CasProcess"); + return BooleanValue.FALSE; + } + /* Bind result */ + Value result = GlueValueBinder.casToJqti(maximaResult); + if (result==null) { + context.fireRuntimeError(this, "Failed to convert result from Maxima back to a QTI variable - returning NULL"); + return NullValue.INSTANCE; + } + return result; + } + + private String getValue(Value value) { + String val = null; + if(value.getBaseType() == BaseType.FLOAT) { + val = Double.toString(((FloatValue)value).doubleValue()); + } else if(value.getBaseType() == BaseType.INTEGER) { + val = Integer.toString(((IntegerValue)value).intValue()); + } + return val; + } + + @Override + public Cardinality[] getProducedCardinalities(ValidationContext context) { + return new Cardinality[] { Cardinality.SINGLE }; + } + + @Override + public BaseType[] getProducedBaseTypes(ValidationContext context) { + return new BaseType[] { BaseType.FLOAT, BaseType.INTEGER }; + } +} diff --git a/src/main/java/org/olat/ims/qti21/manager/openxml/QTI21WordExport.java b/src/main/java/org/olat/ims/qti21/manager/openxml/QTI21WordExport.java index f6fa794d74dd1345cafc12a5fee00c3b75ca0f3b..ba5463fb300267ae8e29cda9aae7caa11b8bde48 100644 --- a/src/main/java/org/olat/ims/qti21/manager/openxml/QTI21WordExport.java +++ b/src/main/java/org/olat/ims/qti21/manager/openxml/QTI21WordExport.java @@ -471,6 +471,11 @@ public class QTI21WordExport implements MediaResource { case "simpleassociablechoice": //do nothing break; + case "div": + case "p": + trimTextBuffer(); + super.startElement(uri, localName, qName, attributes); + break; default: { if(renderElement) { super.startElement(uri, localName, qName, attributes); @@ -668,7 +673,7 @@ public class QTI21WordExport implements MediaResource { private void startMatch(MatchInteraction matchInteraction) { List<String> cssClasses = matchInteraction.getClassAttr(); - if(cssClasses.contains(QTI21Constants.CSS_MATCH_DRAG_AND_DROP)) { + if(cssClasses != null && cssClasses.contains(QTI21Constants.CSS_MATCH_DRAG_AND_DROP)) { if(hasClass(matchInteraction, QTI21Constants.CSS_MATCH_SOURCE_TOP) || hasClass(matchInteraction, QTI21Constants.CSS_MATCH_SOURCE_BOTTOM)) { startMatchDragAndDropHorizontal(matchInteraction); diff --git a/src/main/java/org/olat/ims/qti21/model/InMemoryAssessmentTestMarks.java b/src/main/java/org/olat/ims/qti21/model/InMemoryAssessmentTestMarks.java index 3ceae524e3ceeb701f334b24c608a4102c749820..035fcb59af4d4419ba4560574ebc836a2aa10afe 100644 --- a/src/main/java/org/olat/ims/qti21/model/InMemoryAssessmentTestMarks.java +++ b/src/main/java/org/olat/ims/qti21/model/InMemoryAssessmentTestMarks.java @@ -32,15 +32,12 @@ import org.olat.ims.qti21.AssessmentTestMarks; public class InMemoryAssessmentTestMarks implements AssessmentTestMarks { private String marks; + private String hiddenRubrics; public InMemoryAssessmentTestMarks() { // } - public InMemoryAssessmentTestMarks(String marks) { - this.marks = marks; - } - @Override public Date getCreationDate() { return null; @@ -65,4 +62,14 @@ public class InMemoryAssessmentTestMarks implements AssessmentTestMarks { public void setMarks(String marks) { this.marks = marks; } + + @Override + public String getHiddenRubrics() { + return hiddenRubrics; + } + + @Override + public void setHiddenRubrics(String rubrics) { + this.hiddenRubrics = rubrics; + } } diff --git a/src/main/java/org/olat/ims/qti21/model/QTI21QuestionType.java b/src/main/java/org/olat/ims/qti21/model/QTI21QuestionType.java index cf588220b3d8b21dbd4aeddfe74c91e9f5cb3486..219eb4b23a6a0ee72d60e76778f35fb2838027ab 100644 --- a/src/main/java/org/olat/ims/qti21/model/QTI21QuestionType.java +++ b/src/main/java/org/olat/ims/qti21/model/QTI21QuestionType.java @@ -210,10 +210,12 @@ public enum QTI21QuestionType { ResponseDeclaration responseDeclaration = item.getResponseDeclaration(interaction.getResponseIdentifier()); String responseIdentifier = responseDeclaration.getIdentifier().toString(); Cardinality cardinalty = responseDeclaration.getCardinality(); - if(hasClass(interaction, "match_dnd")) { + if(hasClass(interaction, QTI21Constants.CSS_MATCH_DRAG_AND_DROP)) { return QTI21QuestionType.matchdraganddrop; } else if(cardinalty.isMultiple()) { - if(responseIdentifier.startsWith("KPRIM_")) { + if(hasClass(interaction, QTI21Constants.CSS_MATCH_KPRIM)) { + return QTI21QuestionType.kprim; + } else if(responseIdentifier.startsWith("KPRIM_")) { return QTI21QuestionType.kprim; } else { return QTI21QuestionType.match; @@ -243,7 +245,9 @@ public enum QTI21QuestionType { } } - private static final boolean hasClass(Interaction interaction, String cssClass) { + public static final boolean hasClass(Interaction interaction, String cssClass) { + if(interaction == null || cssClass == null) return false; + List<String> cssClasses = interaction.getClassAttr(); return cssClasses != null && cssClasses.size() > 0 && cssClasses.contains(cssClass); } diff --git a/src/main/java/org/olat/ims/qti21/model/jpa/AssessmentTestMarksImpl.java b/src/main/java/org/olat/ims/qti21/model/jpa/AssessmentTestMarksImpl.java index ce7b67648b4be7e380a469fd988ee45317602f41..e1f0d0f98585d9a76a18f11fd3c344840f78d047 100644 --- a/src/main/java/org/olat/ims/qti21/model/jpa/AssessmentTestMarksImpl.java +++ b/src/main/java/org/olat/ims/qti21/model/jpa/AssessmentTestMarksImpl.java @@ -40,6 +40,8 @@ import org.olat.ims.qti21.AssessmentTestMarks; import org.olat.repository.RepositoryEntry; /** + * + * This object hold the marks and other hide/show settings * * Initial date: 03.03.2016<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com @@ -65,6 +67,8 @@ public class AssessmentTestMarksImpl implements AssessmentTestMarks, Persistable @Column(name="q_marks", nullable=true, insertable=true, updatable=true) private String marks; + @Column(name="q_hidden_rubrics", nullable=true, insertable=true, updatable=true) + private String hiddenRubrics; @ManyToOne(targetEntity=RepositoryEntry.class,fetch=FetchType.LAZY,optional=false) @JoinColumn(name="fk_reference_entry", nullable=false, insertable=true, updatable=false) @@ -99,24 +103,36 @@ public class AssessmentTestMarksImpl implements AssessmentTestMarks, Persistable this.creationDate = creationDate; } + @Override public Date getLastModified() { return lastModified; } + @Override public void setLastModified(Date lastModified) { this.lastModified = lastModified; } - - - + + @Override public String getMarks() { return marks; } + @Override public void setMarks(String marks) { this.marks = marks; } - + + @Override + public String getHiddenRubrics() { + return hiddenRubrics; + } + + @Override + public void setHiddenRubrics(String rubrics) { + this.hiddenRubrics = rubrics; + } + public RepositoryEntry getTestEntry() { return testEntry; } diff --git a/src/main/java/org/olat/ims/qti21/model/statistics/NumericalInputInteractionStatistics.java b/src/main/java/org/olat/ims/qti21/model/statistics/NumericalInputInteractionStatistics.java index 900817488bf4b3827b9fe6927ac6dc5b73316fcc..4f106f174c48b797c1776875a532711a6e59624d 100644 --- a/src/main/java/org/olat/ims/qti21/model/statistics/NumericalInputInteractionStatistics.java +++ b/src/main/java/org/olat/ims/qti21/model/statistics/NumericalInputInteractionStatistics.java @@ -90,6 +90,6 @@ public class NumericalInputInteractionStatistics extends AbstractTextEntryIntera private boolean match(double answer) { double lTolerance = lowerTolerance == null ? 0.0d : lowerTolerance.doubleValue(); double uTolerance = upperTolerance == null ? 0.0d : upperTolerance.doubleValue(); - return toleranceMode.isEqual(answer, correctFloatResponse.doubleValue(), lTolerance, uTolerance, true, true); + return toleranceMode.isEqual(correctFloatResponse.doubleValue(), answer, lTolerance, uTolerance, true, true); } } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AlienItemAnalyzer.java b/src/main/java/org/olat/ims/qti21/model/xml/AlienItemAnalyzer.java new file mode 100644 index 0000000000000000000000000000000000000000..9eeb1b527f360eba03f7b4014020bedd84d8a960 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/model/xml/AlienItemAnalyzer.java @@ -0,0 +1,267 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.model.xml; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.ims.qti21.QTI21Constants; +import org.olat.ims.qti21.model.QTI21QuestionType; + +import uk.ac.ed.ph.jqtiplus.node.content.ItemBody; +import uk.ac.ed.ph.jqtiplus.node.content.basic.Block; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.CustomOperator; +import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; +import uk.ac.ed.ph.jqtiplus.node.item.ModalFeedback; +import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction; +import uk.ac.ed.ph.jqtiplus.node.item.interaction.MatchInteraction; +import uk.ac.ed.ph.jqtiplus.types.Identifier; +import uk.ac.ed.ph.jqtiplus.utils.QueryUtils; + +/** + * + * Initial date: 30 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AlienItemAnalyzer { + + private static final OLog log = Tracing.createLoggerFor(AlienItemAnalyzer.class); + + private final AssessmentItem item; + + public AlienItemAnalyzer(AssessmentItem item) { + this.item = item; + } + + public Report analyze() { + try { + // We doesn't support item created by TaoTesting, the difference in response + // processing are quiet large. + if(item.getToolName() != null && "TAO".equalsIgnoreCase(item.getToolName())) { + return new Report(QTI21QuestionType.unkown, true); + } + + QTI21QuestionType type = QTI21QuestionType.getTypeRelax(item); + Report report = new Report(type); + checkTemplateProcessing(report); + checkFeedback(report); + checkItemBody(report); + checkCustomOperator(report); + checkKprim(report); + return report; + } catch (Exception e) { + log.error("", e); + return new Report(QTI21QuestionType.unkown, true); + } + } + + private void checkFeedback(Report report) { + if(item.getModalFeedbacks() != null + && item.getModalFeedbacks().size() > 0) { + + Set<Identifier> outcomeIdentifiers = new HashSet<>(); + List<ModalFeedback> feedbacks = item.getModalFeedbacks(); + for(ModalFeedback feedback:feedbacks) { + if(feedback.getOutcomeIdentifier() != null) { + outcomeIdentifiers.add(feedback.getOutcomeIdentifier()); + } + } + + if(outcomeIdentifiers.size() == 1) { + if(outcomeIdentifiers.iterator().next().equals(QTI21Constants.FEEDBACKMODAL_IDENTIFIER)) { + checkFeedbackModalResponseProcessing(report); + } else { + report.addWarning(ReportWarningEnum.alienFeedbacks); + } + } else { + // Onyx and OpenOLAT only use one outcome identifier for the feedbacks + // Taotesting use several different identifiers. And we don't + // understand feedbacks without outcome identifiers + report.addWarning(ReportWarningEnum.alienFeedbacks); + } + } + } + + private void checkFeedbackModalResponseProcessing(Report report) { + if(report.getType() != QTI21QuestionType.unkown) { + boolean allOk = true; + List<ModalFeedback> feedbacks = item.getModalFeedbacks(); + for(ModalFeedback feedback:feedbacks) { + ModalFeedbackBuilder feedbackBuilder = new ModalFeedbackBuilder(item, feedback); + if(feedbackBuilder.isCorrectRule() + || feedbackBuilder.isIncorrectRule()) { + //ok + } else if(feedbackBuilder.isCorrectSolutionRule() + || (feedback.getOutcomeIdentifier() != null + && QTI21Constants.CORRECT_SOLUTION_IDENTIFIER.equals(feedback.getOutcomeIdentifier()))) { + //ok + } else if(feedbackBuilder.isEmptyRule() || feedbackBuilder.isAnsweredRule() || feedbackBuilder.isHint()) { + //ok + } else { + List<ModalFeedbackCondition> conditions = feedbackBuilder.getFeedbackConditons(); + if(conditions == null || conditions.isEmpty()) { + allOk &= false; + } + } + } + + if(!allOk) { + report.addWarning(ReportWarningEnum.unsupportedFeedbacks); + } + } + } + + /** + * Check if there are text after the interaction + */ + private void checkItemBody(Report report) { + if(report.getType() == QTI21QuestionType.sc + || report.getType() == QTI21QuestionType.mc + || report.getType() == QTI21QuestionType.kprim + || report.getType() == QTI21QuestionType.match + || report.getType() == QTI21QuestionType.matchdraganddrop + || report.getType() == QTI21QuestionType.hotspot + || report.getType() == QTI21QuestionType.essay + || report.getType() == QTI21QuestionType.upload) { + + ItemBody itemBody = item.getItemBody(); + List<Block> blocks = itemBody.getBlocks(); + Block lastBlock = blocks.get(blocks.size() - 1); + if(!(lastBlock instanceof Interaction)) { + report.addWarning(ReportWarningEnum.textAfterInteraction); + } + } + } + + private void checkTemplateProcessing(Report report) { + if(item.getTemplateDeclarations() != null + && item.getTemplateDeclarations().size()> 0) { + report.addWarning(ReportWarningEnum.templates); + } else if(item.getTemplateProcessing() != null + && item.getTemplateProcessing().getTemplateProcessingRules() != null + && item.getTemplateProcessing().getTemplateProcessingRules().size() > 0) { + report.addWarning(ReportWarningEnum.templates); + } + } + + private void checkCustomOperator(Report report) { + @SuppressWarnings("rawtypes") + List<CustomOperator> customOperators = QueryUtils.search(CustomOperator.class, item); + if(customOperators != null && customOperators.size() > 0) { + report.addWarning(ReportWarningEnum.templates); + } + } + + private void checkKprim(Report report) { + List<Interaction> interactions = item.getItemBody().findInteractions(); + if(interactions != null && interactions.size() == 1) { + Interaction interaction = interactions.get(0); + if(interaction instanceof MatchInteraction) { + report.addAlternative(QTI21QuestionType.match); + report.addAlternative(QTI21QuestionType.matchdraganddrop); + } + } + } + + public enum ReportWarningEnum { + + templates("warning.t" + + "emplates", "o_icon_error"), + alienFeedbacks("warning.alien.feedbacks", "o_icon_error"), + unsupportedFeedbacks("warning.unsupported.feedbacks", "o_icon_error"), + textAfterInteraction("warning.text.after.interaction", "o_icon_error"), + customOperator("warning.custom.operator", "o_icon_error"); + + private final String i18nKey; + private final String cssClass; + + private ReportWarningEnum(String i18nKey, String cssClass) { + this.i18nKey = i18nKey; + this.cssClass = cssClass; + } + + public String i18nKey() { + return i18nKey; + } + + public String cssClass() { + return cssClass; + } + } + + public static class Report { + + private QTI21QuestionType type; + + private boolean blocker; + private final List<ReportWarningEnum> warnings = new ArrayList<>(); + private final List<QTI21QuestionType> alternatives = new ArrayList<>(); + + public Report(QTI21QuestionType type) { + this(type, false); + } + + public Report(QTI21QuestionType type, boolean blocker) { + this.type = type; + this.blocker = blocker; + } + + public boolean isBlocker() { + return blocker; + } + + public void setBlocker(boolean blocker) { + this.blocker = blocker; + } + + public boolean hasWarnings() { + return warnings.size() > 0; + } + + protected void addWarning(ReportWarningEnum warning) { + warnings.add(warning); + } + + public List<ReportWarningEnum> getWarnings() { + return warnings; + } + + public List<QTI21QuestionType> getAlternatives() { + return alternatives; + } + + public void addAlternative(QTI21QuestionType alternative) { + alternatives.add(alternative); + } + + public QTI21QuestionType getType() { + return type; + } + + public void setType(QTI21QuestionType type) { + this.type = type; + } + } +} diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java index 9b19ebdd7da2a89265465c91c4e14cfb7db44823..6f54181f45b6f72182abc34e3ece7a5c4fcd964e 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java @@ -21,6 +21,7 @@ package org.olat.ims.qti21.model.xml; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.StringReader; import java.util.ArrayList; import java.util.List; @@ -33,7 +34,7 @@ import org.olat.core.gui.render.StringOutput; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; -import org.olat.core.util.filter.FilterFactory; +import org.olat.core.util.filter.impl.NekoHTMLFilter; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -41,6 +42,7 @@ import org.w3c.dom.Node; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; import uk.ac.ed.ph.jqtiplus.exception.QtiModelException; @@ -76,7 +78,24 @@ public class AssessmentHtmlBuilder { } public boolean containsSomething(String html) { - return StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(html)); + if(!StringHelper.containsNonWhitespace(html)) return false; + + try { + SAXParser parser = new SAXParser(); + ContentDetectionHandler contentHandler = new ContentDetectionHandler(); + parser.setContentHandler(contentHandler); + parser.parse(new InputSource(new StringReader(html))); + return contentHandler.isContentAvailable(); + } catch (SAXException e) { + log.error("", e); + return false; + } catch (IOException e) { + log.error("", e); + return false; + } catch (Exception e) { + log.error("", e); + return false; + } } public String flowStaticString(List<? extends FlowStatic> statics) { @@ -497,4 +516,44 @@ public class AssessmentHtmlBuilder { // } } + + private static class ContentDetectionHandler extends DefaultHandler { + + private boolean collect = false; + private boolean content = false; + + public boolean isContentAvailable() { + return content; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) { + String elem = localName.toLowerCase(); + if("script".equals(elem)) { + collect = false; + } else if(!NekoHTMLFilter.blockTags.contains(localName)) { + content = true; + } + } + + @Override + public void characters(char[] chars, int offset, int length) { + if(!content && collect && offset >= 0 && length > 0) { + String text = new String(chars, offset, length); + if(text.trim().length() > 0) { + content = true; + } + } + } + + @Override + public void endElement(String uri, String localName, String qName) { + String elem = localName.toLowerCase(); + if("script".equals(elem)) { + collect = true; + } else if(!NekoHTMLFilter.blockTags.contains(localName)) { + content = true; + } + } + } } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemBuilder.java index a4b2b897a8a5d4e682f9239218dd40e3ca3006d5..d41084415aa51674f4883feb047253cdb45f259d 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemBuilder.java @@ -25,8 +25,11 @@ import static org.olat.ims.qti21.QTI21Constants.MINSCORE_IDENTIFIER; import java.util.ArrayList; import java.util.List; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.model.QTI21QuestionType; +import org.olat.ims.qti21.model.xml.ModalFeedbackBuilder.ModalFeedbackType; import uk.ac.ed.ph.jqtiplus.node.content.xhtml.text.P; import uk.ac.ed.ph.jqtiplus.node.expression.general.BaseValue; @@ -46,6 +49,7 @@ import uk.ac.ed.ph.jqtiplus.node.shared.declaration.DefaultValue; import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; import uk.ac.ed.ph.jqtiplus.types.Identifier; import uk.ac.ed.ph.jqtiplus.value.BaseType; +import uk.ac.ed.ph.jqtiplus.value.Cardinality; import uk.ac.ed.ph.jqtiplus.value.FloatValue; import uk.ac.ed.ph.jqtiplus.value.IdentifierValue; import uk.ac.ed.ph.jqtiplus.value.Value; @@ -58,6 +62,8 @@ import uk.ac.ed.ph.jqtiplus.value.Value; * */ public abstract class AssessmentItemBuilder { + + private static final OLog log = Tracing.createLoggerFor(AssessmentItemBuilder.class); protected final AssessmentItem assessmentItem; protected final QtiSerializer qtiSerializer; @@ -125,22 +131,34 @@ public abstract class AssessmentItemBuilder { List<ModalFeedback> feedbacks = assessmentItem.getModalFeedbacks(); for(ModalFeedback feedback:feedbacks) { ModalFeedbackBuilder feedbackBuilder = new ModalFeedbackBuilder(assessmentItem, feedback); - if(feedbackBuilder.isCorrectRule()) { - correctFeedback = feedbackBuilder; - } else if(feedbackBuilder.isIncorrectRule()) { - incorrectFeedback = feedbackBuilder; - } else if(feedbackBuilder.isCorrectSolutionRule() - || (feedback.getOutcomeIdentifier() != null - && QTI21Constants.CORRECT_SOLUTION_IDENTIFIER.equals(feedback.getOutcomeIdentifier()))) { - correctSolutionFeedback = feedbackBuilder; - } else if(feedbackBuilder.isEmptyRule()) { - emptyFeedback = feedbackBuilder; - } else if(feedbackBuilder.isAnsweredRule()) { - answeredFeedback = feedbackBuilder; - } else if(feedbackBuilder.isHint()) { - hint = feedbackBuilder; - } else { - additionalFeedbacks.add(feedbackBuilder); + ModalFeedbackType feedbackType = feedbackBuilder.getType(); + if(feedbackType != null && feedbackType != ModalFeedbackType.unkown) { + switch(feedbackType) { + case correct: + correctFeedback = feedbackBuilder; + break; + case incorrect: + incorrectFeedback = feedbackBuilder; + break; + case correctSolution: + correctSolutionFeedback = feedbackBuilder; + break; + case empty: + emptyFeedback = feedbackBuilder; + break; + case answered: + answeredFeedback = feedbackBuilder; + break; + case hint: + hint = feedbackBuilder; + break; + case additional: + additionalFeedbacks.add(feedbackBuilder); + break; + case unkown: + log.error("Unkown feedback:"); + break; + } } } } @@ -186,7 +204,7 @@ public abstract class AssessmentItemBuilder { } public ModalFeedbackBuilder createHint() { - hint = new ModalFeedbackBuilder(assessmentItem); + hint = new ModalFeedbackBuilder(assessmentItem, ModalFeedbackType.hint); return hint; } @@ -199,7 +217,7 @@ public abstract class AssessmentItemBuilder { } public ModalFeedbackBuilder createCorrectFeedback() { - correctFeedback = new ModalFeedbackBuilder(assessmentItem); + correctFeedback = new ModalFeedbackBuilder(assessmentItem, ModalFeedbackType.correct); return correctFeedback; } @@ -212,7 +230,7 @@ public abstract class AssessmentItemBuilder { } public ModalFeedbackBuilder createEmptyFeedback() { - emptyFeedback = new ModalFeedbackBuilder(assessmentItem); + emptyFeedback = new ModalFeedbackBuilder(assessmentItem, ModalFeedbackType.empty); return emptyFeedback; } @@ -225,7 +243,7 @@ public abstract class AssessmentItemBuilder { } public ModalFeedbackBuilder createAnsweredFeedback() { - answeredFeedback = new ModalFeedbackBuilder(assessmentItem); + answeredFeedback = new ModalFeedbackBuilder(assessmentItem, ModalFeedbackType.answered); return answeredFeedback; } @@ -233,12 +251,59 @@ public abstract class AssessmentItemBuilder { answeredFeedback = null; } + public List<ModalFeedbackBuilder> getAdditionalFeedbackBuilders() { + return additionalFeedbacks; + } + + public void setAdditionalFeedbackBuilders(List<ModalFeedbackBuilder> feedbacks) { + additionalFeedbacks = new ArrayList<>(feedbacks); + } + + + public ModalFeedbackBuilder getFeedbackBuilder(ModalFeedbackType type) { + switch(type) { + case hint: return getHint(); + case correctSolution: return getCorrectSolutionFeedback(); + case correct: return getCorrectFeedback(); + case incorrect: return getIncorrectFeedback(); + case empty: return getEmptyFeedback(); + case answered: return getAnsweredFeedback(); + default: return null; + } + } + + public ModalFeedbackBuilder createFeedbackBuilder(ModalFeedbackType type) { + switch(type) { + case hint: return createHint(); + case correctSolution: return createCorrectSolutionFeedback(); + case correct: return createCorrectFeedback(); + case incorrect: return createIncorrectFeedback(); + case empty: return createEmptyFeedback(); + case answered: return createAnsweredFeedback(); + default: return null; + } + } + + public void removeFeedbackBuilder(ModalFeedbackType type) { + switch(type) { + case hint: removeHint(); break; + case correctSolution: removeCorrectSolutionFeedback(); break; + case correct: removeCorrectFeedback(); break; + case incorrect: removeIncorrectFeedback(); break; + case empty: removeEmptyFeedback(); break; + case answered: removeAnsweredFeedback(); break; + default: { + //do nothing + } + } + } + public ModalFeedbackBuilder getIncorrectFeedback() { return incorrectFeedback; } public ModalFeedbackBuilder createIncorrectFeedback() { - incorrectFeedback = new ModalFeedbackBuilder(assessmentItem); + incorrectFeedback = new ModalFeedbackBuilder(assessmentItem, ModalFeedbackType.incorrect); return incorrectFeedback; } @@ -247,7 +312,7 @@ public abstract class AssessmentItemBuilder { } public ModalFeedbackBuilder createCorrectSolutionFeedback() { - correctSolutionFeedback = new ModalFeedbackBuilder(assessmentItem); + correctSolutionFeedback = new ModalFeedbackBuilder(assessmentItem, ModalFeedbackType.correctSolution); return correctSolutionFeedback; } @@ -405,7 +470,31 @@ public abstract class AssessmentItemBuilder { if(answeredFeedback != null) { appendModalFeedback(answeredFeedback, QTI21Constants.ANSWERED, modalFeedbacks, responseRules); } + + if(additionalFeedbacks.size() > 0) { + for(ModalFeedbackBuilder feedback:additionalFeedbacks) { + appendAdditionalFeedback(feedback, modalFeedbacks, responseRules); + } + } + } + } + + protected void appendAdditionalFeedback(ModalFeedbackBuilder feedback, List<ModalFeedback> modalFeedbacks, List<ResponseRule> responseRules) { + Identifier feedbackIdentifier = feedback.getIdentifier(); + ModalFeedback modalFeedback = AssessmentItemFactory + .createModalFeedback(assessmentItem, feedbackIdentifier, feedback.getTitle(), feedback.getText()); + modalFeedbacks.add(modalFeedback); + + Cardinality cardinality = null; + Identifier responseIdentifier = null; + if(this instanceof ResponseIdentifierForFeedback) { + responseIdentifier = ((ResponseIdentifierForFeedback)this).getResponseIdentifier(); + cardinality = assessmentItem.getResponseDeclaration(responseIdentifier).getCardinality(); } + ResponseCondition feedbackCondition = AssessmentItemFactory + .createModalFeedbackRuleWithConditions(assessmentItem.getResponseProcessing(), feedbackIdentifier, + responseIdentifier, cardinality, feedback.getFeedbackConditons()); + responseRules.add(feedbackCondition); } protected void appendCorrectSolutionAndIncorrectModalFeedback(List<ModalFeedback> modalFeedbacks, List<ResponseRule> responseRules) { diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemChecker.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemChecker.java new file mode 100644 index 0000000000000000000000000000000000000000..1ff7fc99d27f99c1bcce02bb7f674e3f98c2104a --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemChecker.java @@ -0,0 +1,92 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.model.xml; + +import java.util.List; + +import uk.ac.ed.ph.jqtiplus.node.expression.Expression; +import uk.ac.ed.ph.jqtiplus.node.expression.general.Variable; +import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; +import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration; +import uk.ac.ed.ph.jqtiplus.node.item.template.declaration.TemplateDeclaration; +import uk.ac.ed.ph.jqtiplus.node.item.template.processing.SetCorrectResponse; +import uk.ac.ed.ph.jqtiplus.types.ComplexReferenceIdentifier; +import uk.ac.ed.ph.jqtiplus.types.Identifier; +import uk.ac.ed.ph.jqtiplus.utils.QueryUtils; +import uk.ac.ed.ph.jqtiplus.value.BaseType; + +/** + * + * + * + * Initial date: 5 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AssessmentItemChecker { + + /** + * + * The method check and correct the type of some variables. + * + * @param item + * @return + */ + public static boolean checkAndCorrect(AssessmentItem item) { + boolean allOk = true; + allOk &= checkSetCorrectResponse(item); + return allOk; + } + + /** + * responseDeclaration -> float + * + * templateVraiable -> integer + * + * setCorrectResponse + * -> variable -> integer doesn't match float -> issue + * @param item + * @return + */ + private static boolean checkSetCorrectResponse(AssessmentItem item) { + boolean allOk = true; + + List<SetCorrectResponse> setCorrectResponses = QueryUtils.search(SetCorrectResponse.class, item); + for(SetCorrectResponse setCorrectResponse:setCorrectResponses) { + Identifier responseIdentifier = setCorrectResponse.getIdentifier(); + ResponseDeclaration responseDeclaration = item.getResponseDeclaration(responseIdentifier); + BaseType baseType = responseDeclaration.getBaseType(); + Expression expression = setCorrectResponse.getExpression(); + if(expression instanceof Variable) { + Variable variable = (Variable)expression; + ComplexReferenceIdentifier cpxVariableIdentifier = variable.getIdentifier(); + Identifier variableIdentifier = Identifier.assumedLegal(cpxVariableIdentifier.toString()); + TemplateDeclaration templateDeclaration = item.getTemplateDeclaration(variableIdentifier); + if(templateDeclaration != null && !templateDeclaration.hasBaseType(baseType)) { + templateDeclaration.setBaseType(baseType); + allOk &= false; + } + } + } + + return allOk; + } + +} diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java index 8824040add4e31675035d5dca2e030ea44bab3f9..a2d956b7f71a2772da71313875b2639f291cc2e1 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java @@ -46,19 +46,25 @@ import uk.ac.ed.ph.jqtiplus.node.content.ItemBody; import uk.ac.ed.ph.jqtiplus.node.content.basic.TextRun; import uk.ac.ed.ph.jqtiplus.node.content.xhtml.object.Object; import uk.ac.ed.ph.jqtiplus.node.content.xhtml.text.P; +import uk.ac.ed.ph.jqtiplus.node.expression.Expression; import uk.ac.ed.ph.jqtiplus.node.expression.general.BaseValue; import uk.ac.ed.ph.jqtiplus.node.expression.general.Correct; +import uk.ac.ed.ph.jqtiplus.node.expression.general.MapResponse; import uk.ac.ed.ph.jqtiplus.node.expression.general.Variable; import uk.ac.ed.ph.jqtiplus.node.expression.operator.And; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Equal; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Gt; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Gte; import uk.ac.ed.ph.jqtiplus.node.expression.operator.IsNull; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Lt; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Lte; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Match; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Member; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Multiple; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Not; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Shape; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Sum; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.ToleranceMode; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; import uk.ac.ed.ph.jqtiplus.node.item.CorrectResponse; import uk.ac.ed.ph.jqtiplus.node.item.ModalFeedback; @@ -79,6 +85,7 @@ import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.MapEntry; import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.Mapping; import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseCondition; +import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseConditionChild; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseElse; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseElseIf; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseIf; @@ -92,12 +99,15 @@ import uk.ac.ed.ph.jqtiplus.node.test.View; import uk.ac.ed.ph.jqtiplus.node.test.VisibilityMode; import uk.ac.ed.ph.jqtiplus.types.ComplexReferenceIdentifier; import uk.ac.ed.ph.jqtiplus.types.Identifier; +import uk.ac.ed.ph.jqtiplus.utils.QueryUtils; import uk.ac.ed.ph.jqtiplus.value.BaseType; import uk.ac.ed.ph.jqtiplus.value.Cardinality; import uk.ac.ed.ph.jqtiplus.value.DirectedPairValue; import uk.ac.ed.ph.jqtiplus.value.FloatValue; import uk.ac.ed.ph.jqtiplus.value.IdentifierValue; +import uk.ac.ed.ph.jqtiplus.value.IntegerValue; import uk.ac.ed.ph.jqtiplus.value.Orientation; +import uk.ac.ed.ph.jqtiplus.value.SingleValue; import uk.ac.ed.ph.jqtiplus.value.StringValue; /** @@ -184,6 +194,90 @@ public class AssessmentItemFactory { outcomeDeclarations.getOutcomeDeclarations().add(feedbackOutcomeDeclaration); } + /* + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier"> + correct + </baseValue> + </setOutcomeValue> + */ + public static void appendSetOutcomeFeedbackCorrect(ResponseConditionChild responseCondition) { + SetOutcomeValue correctOutcomeValue = new SetOutcomeValue(responseCondition); + correctOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER); + responseCondition.getResponseRules().add(correctOutcomeValue); + + BaseValue correctValue = new BaseValue(correctOutcomeValue); + correctValue.setBaseTypeAttrValue(BaseType.IDENTIFIER); + correctValue.setSingleValue(QTI21Constants.CORRECT_IDENTIFIER_VALUE); + correctOutcomeValue.setExpression(correctValue); + } + + /* + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier">incorrect</baseValue> + </setOutcomeValue> + */ + public static void appendSetOutcomeFeedbackIncorrect(ResponseConditionChild responseCondition) { + SetOutcomeValue incorrectOutcomeValue = new SetOutcomeValue(responseCondition); + incorrectOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER); + responseCondition.getResponseRules().add(incorrectOutcomeValue); + + BaseValue incorrectValue = new BaseValue(incorrectOutcomeValue); + incorrectValue.setBaseTypeAttrValue(BaseType.IDENTIFIER); + incorrectValue.setSingleValue(QTI21Constants.INCORRECT_IDENTIFIER_VALUE); + incorrectOutcomeValue.setExpression(incorrectValue); + } + + /* + <setOutcomeValue identifier="SCORE"> + <sum> + <variable identifier="SCORE"/> + <mapResponse identifier="RESPONSE_1"/> + </sum> + </setOutcomeValue> + */ + public static void appendSetOutcomeScoreMapResponse(ResponseConditionChild responseCondition, Identifier responseIdentifier) { + SetOutcomeValue scoreOutcome = new SetOutcomeValue(responseCondition); + scoreOutcome.setIdentifier(QTI21Constants.SCORE_IDENTIFIER); + responseCondition.getResponseRules().add(scoreOutcome); + + Sum sum = new Sum(scoreOutcome); + scoreOutcome.getExpressions().add(sum); + + Variable scoreVar = new Variable(sum); + scoreVar.setIdentifier(QTI21Constants.SCORE_CLX_IDENTIFIER); + sum.getExpressions().add(scoreVar); + + MapResponse mapResponse = new MapResponse(sum); + mapResponse.setIdentifier(responseIdentifier); + sum.getExpressions().add(mapResponse); + } + + /* + <setOutcomeValue identifier="SCORE"> + <sum> + <variable identifier="SCORE"/> + <variable identifier="MAXSCORE"/> + </sum> + </setOutcomeValue> + */ + public static void appendSetOutcomeScoreMaxScore(ResponseConditionChild responseCondition) { + SetOutcomeValue scoreOutcomeValue = new SetOutcomeValue(responseCondition); + scoreOutcomeValue.setIdentifier(QTI21Constants.SCORE_IDENTIFIER); + responseCondition.getResponseRules().add(scoreOutcomeValue); + + Sum sum = new Sum(scoreOutcomeValue); + scoreOutcomeValue.getExpressions().add(sum); + + Variable scoreVar = new Variable(sum); + scoreVar.setIdentifier(QTI21Constants.SCORE_CLX_IDENTIFIER); + sum.getExpressions().add(scoreVar); + + Variable maxScoreVar = new Variable(sum); + maxScoreVar.setIdentifier(QTI21Constants.MAXSCORE_CLX_IDENTIFIER); + sum.getExpressions().add(maxScoreVar); + } + public static HotspotInteraction appendHotspotInteraction(ItemBody itemBody, Identifier responseDeclarationId, Identifier correctResponseId) { HotspotInteraction hotspotInteraction = new HotspotInteraction(itemBody); hotspotInteraction.setResponseIdentifier(responseDeclarationId); @@ -1045,6 +1139,247 @@ public class AssessmentItemFactory { return modalFeedback; } + /** + * the additional feedback have only responseIf + * + * + * @param item + * @param feedback + * @return + */ + public static boolean matchAdditionalFeedback(AssessmentItem item, ModalFeedback feedback) { + List<ResponseRule> responseRules = item.getResponseProcessing().getResponseRules(); + for(ResponseRule responseRule:responseRules) { + if(responseRule instanceof ResponseCondition) { + ResponseCondition responseCondition = (ResponseCondition)responseRule; + if(responseCondition.getResponseIf() == null || responseCondition.getResponseElse() != null + || (responseCondition.getResponseElseIfs() != null && responseCondition.getResponseElseIfs().size() > 0)) { + continue; + } + + ResponseIf responseIf = responseCondition.getResponseIf(); + List<ResponseRule> ifResponseRules = responseIf.getResponseRules(); + if(ifResponseRules == null || ifResponseRules.size() != 1 || !(ifResponseRules.get(0) instanceof SetOutcomeValue)) { + continue; + } + + SetOutcomeValue setOutcomeValue = (SetOutcomeValue)responseIf.getResponseRules().get(0); + if(!findBaseValueInExpression(setOutcomeValue.getExpression(), feedback.getIdentifier())) { + continue; + } + + List<Expression> expressions = responseIf.getExpressions(); + if(expressions == null || expressions.size() != 1 || !(expressions.get(0) instanceof And)) { + continue; + } + + List<Variable> variables = QueryUtils.search(Variable.class, expressions.get(0)); + if(variables != null && variables.size() == 1) { + Variable bValue = variables.get(0); + ComplexReferenceIdentifier identifier = bValue.getIdentifier(); + if(identifier.equals(QTI21Constants.SCORE_CLX_IDENTIFIER) + || identifier.equals(QTI21Constants.NUM_ATTEMPTS_CLX_IDENTIFIER)) { + return true; + } + if(identifier.equals(QTI21Constants.CORRECT_CLX_IDENTIFIER) + || identifier.equals(QTI21Constants.INCORRECT_CLX_IDENTIFIER) + || identifier.equals(QTI21Constants.EMPTY_CLX_IDENTIFIER)) { + return false; + } + String identifierToString = identifier.toString(); + if(identifierToString.contains("RESPONSE_")) { + return true; + } + } + } + } + + return false; + } + + public static ResponseCondition createModalFeedbackRuleWithConditions(ResponseProcessing responseProcessing, + Identifier feedbackIdentifier, Identifier responseIdentifier, Cardinality cardinality, List<ModalFeedbackCondition> conditions) { + ResponseCondition rule = new ResponseCondition(responseProcessing); + + /* + <responseCondition> + <responseIf> + <and> + <equal toleranceMode="exact"> + <variable identifier="SCORE" /> + <baseValue baseType="float"> + 4 + </baseValue> + </equal> + </and> + <setOutcomeValue identifier="FEEDBACKMODAL"> + <multiple> + <variable identifier="FEEDBACKMODAL" /> + <baseValue baseType="identifier"> + Feedback2074019497 + </baseValue> + </multiple> + </setOutcomeValue> + </responseIf> + </responseCondition> + */ + + ResponseIf responseIf = new ResponseIf(rule); + rule.setResponseIf(responseIf); + + {//rule + And and = new And(responseIf); + responseIf.getExpressions().add(and); + for(ModalFeedbackCondition condition:conditions) { + appendModalFeedbackCondition(condition, responseIdentifier, cardinality, and); + } + } + + {//outcome + SetOutcomeValue feedbackVar = new SetOutcomeValue(responseIf); + feedbackVar.setIdentifier(QTI21Constants.FEEDBACKMODAL_IDENTIFIER); + + Multiple multiple = new Multiple(feedbackVar); + feedbackVar.setExpression(multiple); + + Variable variable = new Variable(multiple); + variable.setIdentifier(ComplexReferenceIdentifier.parseString(QTI21Constants.FEEDBACKMODAL)); + multiple.getExpressions().add(variable); + + BaseValue feedbackVal = new BaseValue(feedbackVar); + feedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER); + feedbackVal.setSingleValue(new IdentifierValue(feedbackIdentifier)); + multiple.getExpressions().add(feedbackVal); + + responseIf.getResponseRules().add(feedbackVar); + } + + return rule; + } + + private static void appendModalFeedbackCondition(ModalFeedbackCondition condition, Identifier responseIdentifier, Cardinality cardinality, And and) { + ModalFeedbackCondition.Variable var = condition.getVariable(); + ModalFeedbackCondition.Operator operator = condition.getOperator(); + String value = condition.getValue(); + + if(var == ModalFeedbackCondition.Variable.response) { + if(cardinality == Cardinality.MULTIPLE) { + if(operator == ModalFeedbackCondition.Operator.equals) { + Member member = new Member(and); + and.getExpressions().add(member); + appendVariableBaseValue(var, value, responseIdentifier, member, true); + } else if(operator == ModalFeedbackCondition.Operator.notEquals) { + Not not = new Not(and); + and.getExpressions().add(not); + + Member member = new Member(not); + not.getExpressions().add(member); + appendVariableBaseValue(var, value, responseIdentifier, member, true); + } + } else { + if(operator == ModalFeedbackCondition.Operator.equals) { + Match match = new Match(and); + and.getExpressions().add(match); + appendVariableBaseValue(var, value, responseIdentifier, match, false); + } else if(operator == ModalFeedbackCondition.Operator.notEquals) { + Not not = new Not(and); + and.getExpressions().add(not); + + Match match = new Match(not); + not.getExpressions().add(match); + appendVariableBaseValue(var, value, responseIdentifier, match, false); + } + } + } else { + switch(operator) { + case bigger: { + Gt gt = new Gt(and); + and.getExpressions().add(gt); + appendVariableBaseValue(var, value, responseIdentifier, gt, false); + break; + } + case biggerEquals: { + Gte gte = new Gte(and); + and.getExpressions().add(gte); + appendVariableBaseValue(var, value, responseIdentifier, gte, false); + break; + } + case equals: { + Equal equal = new Equal(and); + equal.setToleranceMode(ToleranceMode.EXACT); + and.getExpressions().add(equal); + appendVariableBaseValue(var, value, responseIdentifier, equal, false); + break; + } + case notEquals: { + Not not = new Not(and); + and.getExpressions().add(not); + Equal equal = new Equal(not); + equal.setToleranceMode(ToleranceMode.EXACT); + not.getExpressions().add(equal); + appendVariableBaseValue(var, value, responseIdentifier, equal, false); + break; + } + case smaller: { + Lt lt = new Lt(and); + and.getExpressions().add(lt); + appendVariableBaseValue(var, value, responseIdentifier, lt, false); + break; + } + case smallerEquals: { + Lte lte = new Lte(and); + and.getExpressions().add(lte); + appendVariableBaseValue(var, value, responseIdentifier, lte, false); + break; + } + } + } + } + + /* + <variable identifier="SCORE" /> + <baseValue baseType="float">4</baseValue> + */ + /** + * + * @param var + * @param value + * @param responseIdentifier + * @param parentExpression + * @param reverse if true, reverse the order, first baseValue and then variable + */ + private static void appendVariableBaseValue(ModalFeedbackCondition.Variable var, String value, + Identifier responseIdentifier, Expression parentExpression, boolean reverse) { + + Variable variable = new Variable(parentExpression); + BaseValue bValue = new BaseValue(parentExpression); + if(reverse) { + parentExpression.getExpressions().add(bValue); + parentExpression.getExpressions().add(variable); + } else { + parentExpression.getExpressions().add(variable); + parentExpression.getExpressions().add(bValue); + } + + switch(var) { + case score: + bValue.setBaseTypeAttrValue(BaseType.FLOAT); + bValue.setSingleValue(new FloatValue(Double.parseDouble(value))); + variable.setIdentifier(QTI21Constants.SCORE_CLX_IDENTIFIER); + break; + case attempts: + bValue.setBaseTypeAttrValue(BaseType.INTEGER); + bValue.setSingleValue(new IntegerValue(Integer.parseInt(value))); + variable.setIdentifier(QTI21Constants.NUM_ATTEMPTS_CLX_IDENTIFIER); + break; + case response: + bValue.setBaseTypeAttrValue(BaseType.IDENTIFIER); + bValue.setSingleValue(new IdentifierValue(Identifier.parseString(value))); + variable.setIdentifier(ComplexReferenceIdentifier.parseString(responseIdentifier.toString())); + break; + } + } + public static ResponseCondition createModalFeedbackBasicRule(ResponseProcessing responseProcessing, Identifier feedbackIdentifier, String inCorrect, boolean hint) { ResponseCondition rule = new ResponseCondition(responseProcessing); @@ -1405,7 +1740,26 @@ public class AssessmentItemFactory { return list; } - + public static boolean findBaseValueInExpression(Expression expression, Identifier feedbackIdentifier) { + if(expression instanceof BaseValue) { + BaseValue bValue = (BaseValue)expression; + SingleValue sValue = bValue.getSingleValue(); + if(sValue instanceof IdentifierValue) { + IdentifierValue iValue = (IdentifierValue)sValue; + if(feedbackIdentifier.equals(iValue.identifierValue())) { + return true; + } + } + } else { + List<Expression> childExpressions = expression.getExpressions(); + for(Expression childExpression:childExpressions) { + if(findBaseValueInExpression(childExpression, feedbackIdentifier)) { + return true; + } + } + } + return false; + } } 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 7f205a853c107703428109e77c0960dc6ec46f2c..af88a7f3a713f806f4706612dafbe8a537e64d00 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 @@ -251,9 +251,11 @@ public class AssessmentItemMetadata { EducationalType educational = metadata.getEducational(false); if(educational != null) { - // + level = metadata.getEducationContext(); } + taxonomyPath = metadata.getClassificationTaxonomy(); + //qti metadata QTIMetadataType qtiMetadata = metadata.getQtiMetadata(true); if(qtiMetadata != null) { diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentTestBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentTestBuilder.java index f36e4a63ce44624d0e93674d8ed84faff9401639..4eea17295542bdb7e0cb241edb2ce28821ac0798 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentTestBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentTestBuilder.java @@ -318,7 +318,7 @@ public class AssessmentTestBuilder { assessmentTest.getOutcomeProcessing().getOutcomeRules().add(cutValueRule); } } else if(cutValueRule != null) { - assessmentTest.getOutcomeDeclarations().remove(cutValueRule); + assessmentTest.getOutcomeProcessing().getOutcomeRules().remove(cutValueRule); } } 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 2d58b8466267d7979998a708869f533db3851326..01e478957b407ea7132a4a4c8fdd5f9d4ecd4599 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 @@ -26,6 +26,7 @@ import java.util.StringTokenizer; import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; +import org.olat.core.util.StringHelper; import org.olat.imscp.xml.manifest.ManifestMetadataType; import org.olat.imscp.xml.manifest.MetadataType; import org.olat.imsmd.xml.manifest.ClassificationType; @@ -204,6 +205,23 @@ public class ManifestMetadataBuilder { } } + public String getEducationContext() { + EducationalType educational = getEducational(true); + StringBuilder sb = new StringBuilder(); + if(educational != null) { + ContextType type = getFromAny(ContextType.class, educational.getContent()); + if(type != null && type.getSource() != null && type.getSource().getLangstring() != null + && type.getValue() != null && type.getValue().getLangstring() != null) { + String source = type.getSource().getLangstring().getValue(); + String value = type.getValue().getLangstring().getValue(); + if(StringHelper.containsNonWhitespace(source) && StringHelper.containsNonWhitespace(value)) { + sb.append(value); + } + } + } + return sb.length() == 0 ? null: sb.toString(); + } + public void setEducationalContext(String context, String lang) { EducationalType educational = getEducational(true); if(educational != null) { @@ -250,6 +268,28 @@ public class ManifestMetadataBuilder { } } + public String getClassificationTaxonomy() { + StringBuilder sb = new StringBuilder(); + ClassificationType classification = getClassification("discipline", null, false); + if(classification != null) { + TaxonpathType taxonpath = getFromAny(TaxonpathType.class, classification.getContent()); + if(taxonpath != null) { + List<TaxonType> taxons = taxonpath.getTaxon(); + if(taxons != null) { + for(TaxonType taxon:taxons) { + if(taxon.getEntry() != null && taxon.getEntry().getLangstring().size() > 0) { + LangstringType value = taxon.getEntry().getLangstring().get(0); + if(value != null && value.getValue() != null) { + sb.append("/").append(value.getValue()); + } + } + } + } + } + } + return sb.length() == 0 ? null : sb.toString(); + } + /** * Set a taxonomy path of purpose "discipline" * @param taxonomyPath diff --git a/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackBuilder.java index 3be928e15ae5a838a8d0130e6eb4924359d6a4b1..2d9790bcfa55f8cb13b345909cdc6fbfe5c2203d 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackBuilder.java @@ -19,6 +19,9 @@ */ package org.olat.ims.qti21.model.xml; +import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.findBaseValueInExpression; + +import java.util.ArrayList; import java.util.List; import org.olat.ims.qti21.QTI21Constants; @@ -27,15 +30,28 @@ import org.olat.ims.qti21.model.IdentifierGenerator; import uk.ac.ed.ph.jqtiplus.attribute.value.StringAttribute; import uk.ac.ed.ph.jqtiplus.node.expression.Expression; import uk.ac.ed.ph.jqtiplus.node.expression.general.BaseValue; +import uk.ac.ed.ph.jqtiplus.node.expression.general.Variable; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.And; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Equal; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Gt; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Gte; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Lt; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Lte; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Match; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Member; +import uk.ac.ed.ph.jqtiplus.node.expression.operator.Not; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; import uk.ac.ed.ph.jqtiplus.node.item.ModalFeedback; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseCondition; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseIf; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseRule; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.SetOutcomeValue; +import uk.ac.ed.ph.jqtiplus.types.ComplexReferenceIdentifier; import uk.ac.ed.ph.jqtiplus.types.Identifier; +import uk.ac.ed.ph.jqtiplus.value.BaseType; +import uk.ac.ed.ph.jqtiplus.value.FloatValue; import uk.ac.ed.ph.jqtiplus.value.IdentifierValue; -import uk.ac.ed.ph.jqtiplus.value.SingleValue; +import uk.ac.ed.ph.jqtiplus.value.IntegerValue; /** * @@ -48,22 +64,20 @@ public class ModalFeedbackBuilder { private final ModalFeedback modalFeedback; private final AssessmentItem assessmentItem; + private final ModalFeedbackType type; + private String title; private String text; private Identifier identifier; + private List<ModalFeedbackCondition> conditions; - public ModalFeedbackBuilder(AssessmentItem assessmentItem) { + public ModalFeedbackBuilder(AssessmentItem assessmentItem, ModalFeedbackType type) { this.assessmentItem = assessmentItem; this.modalFeedback = null; + this.type = type; identifier = IdentifierGenerator.newNumberAsIdentifier("Feedback"); } - public ModalFeedbackBuilder(AssessmentItem assessmentItem, Identifier identifier) { - this.assessmentItem = assessmentItem; - this.identifier = identifier; - this.modalFeedback = null; - } - public ModalFeedbackBuilder(AssessmentItem assessmentItem, ModalFeedback modalFeedback) { this.assessmentItem = assessmentItem; this.modalFeedback = modalFeedback; @@ -72,13 +86,163 @@ public class ModalFeedbackBuilder { StringAttribute titleAttr = modalFeedback.getAttributes().getStringAttribute(ModalFeedback.ATTR_TITLE_NAME); title = titleAttr == null ? null : titleAttr.getComputedValue(); identifier = modalFeedback.getIdentifier(); + type = extract(); } else { identifier = IdentifierGenerator.newNumberAsIdentifier("Feedback"); + type = null; } } - public Identifier getModalFeedbackIdentifier() { - return modalFeedback.getIdentifier(); + private ModalFeedbackType extract() { + if(isCorrectRule()) { + return ModalFeedbackType.correct; + } + if(isIncorrectRule()) { + return ModalFeedbackType.incorrect; + } + if(isEmptyRule()) { + return ModalFeedbackType.empty; + } + if(isAnsweredRule()) { + return ModalFeedbackType.answered; + } + if(isCorrectSolutionRule()) { + return ModalFeedbackType.correctSolution; + } + if(isHint()) { + return ModalFeedbackType.hint; + } + extractConditions(); + if(conditions != null && conditions.size() > 0) { + return ModalFeedbackType.additional; + } + return ModalFeedbackType.unkown; + } + + public void extractConditions() { + ResponseCondition feedbackRule = findFeedbackResponseCondition(modalFeedback.getIdentifier(), QTI21Constants.FEEDBACKMODAL_IDENTIFIER); + ResponseIf responseIf = feedbackRule.getResponseIf(); + if(responseIf != null && responseIf.getExpressions() != null + && responseIf.getExpressions().size() == 1 + && responseIf.getExpressions().get(0) instanceof And + && responseIf.getResponseRules().size() == 1 + && responseIf.getResponseRules().get(0) instanceof SetOutcomeValue) { + And and = (And)responseIf.getExpression(); + List<Expression> conditionElements = and.getExpressions(); + List<ModalFeedbackCondition> extractedConditions = new ArrayList<>(); + for(Expression conditionElement:conditionElements) { + ModalFeedbackCondition condition = extractCondition(conditionElement); + if(condition != null) { + extractedConditions.add(condition); + } + } + if(extractedConditions != null) { + conditions = extractedConditions; + } + } + } + + private ModalFeedbackCondition extractCondition(Expression conditionElement) { + ModalFeedbackOperatorAndExpressions operatorAndExpressions = extractOperatorCondition(conditionElement); + if(operatorAndExpressions.getOperator() != null) { + List<Expression> expressions = operatorAndExpressions.getExpressions(); + ModalFeedbackCondition.Variable variable = extractVariableCondition(expressions); + String value = extractBaseValueCondition(expressions); + + ModalFeedbackCondition condition = new ModalFeedbackCondition(); + condition.setVariable(variable); + condition.setValue(value); + condition.setOperator(operatorAndExpressions.getOperator()); + return condition; + } + + return null; + } + + private String extractBaseValueCondition(List<Expression> expressions) { + BaseValue bValue = null; + if(expressions.get(0) instanceof BaseValue) { + bValue = (BaseValue)expressions.get(0); + } else if(expressions.get(1) instanceof BaseValue) { + bValue = (BaseValue)expressions.get(1); + } + if(bValue != null) { + if(bValue.getBaseTypeAttrValue() == BaseType.IDENTIFIER) { + IdentifierValue val = (IdentifierValue)bValue.getSingleValue(); + return val.identifierValue().toString(); + } + if(bValue.getBaseTypeAttrValue() == BaseType.INTEGER) { + IntegerValue val = (IntegerValue)bValue.getSingleValue(); + return Integer.toString(val.intValue()); + } + if(bValue.getBaseTypeAttrValue() == BaseType.FLOAT) { + FloatValue val = (FloatValue)bValue.getSingleValue(); + return Double.toString(val.doubleValue()); + } + } + + return null; + } + + private ModalFeedbackCondition.Variable extractVariableCondition(List<Expression> expressions) { + Variable variable = null; + if(expressions.get(0) instanceof Variable) { + variable = (Variable)expressions.get(0); + } else if(expressions.get(1) instanceof Variable) { + variable = (Variable)expressions.get(1); + } + if(variable != null) { + ComplexReferenceIdentifier varIdentifier = variable.getIdentifier(); + if(QTI21Constants.SCORE_CLX_IDENTIFIER.equals(varIdentifier)) { + return ModalFeedbackCondition.Variable.score; + } else if(QTI21Constants.NUM_ATTEMPTS_CLX_IDENTIFIER.equals(varIdentifier)) { + return ModalFeedbackCondition.Variable.attempts; + } else { + return ModalFeedbackCondition.Variable.response; + } + } + + return null; + } + + private ModalFeedbackOperatorAndExpressions extractOperatorCondition(Expression conditionElement) { + ModalFeedbackCondition.Operator operator = null; + List<Expression> expressions = conditionElement.getExpressions(); + if(conditionElement instanceof Gt) { + operator = ModalFeedbackCondition.Operator.bigger; + } else if(conditionElement instanceof Gte) { + operator = ModalFeedbackCondition.Operator.biggerEquals; + } else if(conditionElement instanceof Equal || conditionElement instanceof Match || conditionElement instanceof Member) { + operator = ModalFeedbackCondition.Operator.equals; + } else if(conditionElement instanceof Lt) { + operator = ModalFeedbackCondition.Operator.smaller; + } else if(conditionElement instanceof Lte) { + operator = ModalFeedbackCondition.Operator.smallerEquals; + } else if(conditionElement instanceof Not) { + if(conditionElement.getExpressions().size() == 1 && (conditionElement.getExpressions().get(0) instanceof Match || conditionElement.getExpressions().get(0) instanceof Member)) { + operator = ModalFeedbackCondition.Operator.notEquals; + expressions = conditionElement.getExpressions().get(0).getExpressions(); + } + } + return new ModalFeedbackOperatorAndExpressions(operator, expressions); + } + + private static class ModalFeedbackOperatorAndExpressions { + private final ModalFeedbackCondition.Operator operator; + private final List<Expression> expressions; + + public ModalFeedbackOperatorAndExpressions(ModalFeedbackCondition.Operator operator, List<Expression> expressions) { + this.operator = operator; + this.expressions = expressions; + } + + public ModalFeedbackCondition.Operator getOperator() { + return operator; + } + + public List<Expression> getExpressions() { + return expressions; + } } public boolean isCorrectRule() { @@ -103,7 +267,10 @@ public class ModalFeedbackBuilder { public boolean isCorrectSolutionRule() { ResponseCondition feedbackRule = findFeedbackResponseCondition(modalFeedback.getIdentifier(), QTI21Constants.CORRECT_SOLUTION_IDENTIFIER); - return findBaseValueInExpressionsOfResponseIf(feedbackRule, QTI21Constants.INCORRECT_IDENTIFIER); + boolean allOk = findBaseValueInExpressionsOfResponseIf(feedbackRule, QTI21Constants.INCORRECT_IDENTIFIER); + allOk |= modalFeedback.getOutcomeIdentifier() != null + && QTI21Constants.CORRECT_SOLUTION_IDENTIFIER.equals(modalFeedback.getOutcomeIdentifier()); + return allOk; } public boolean isHint() { @@ -134,6 +301,22 @@ public class ModalFeedbackBuilder { public void setIdentifier(Identifier identifier) { this.identifier = identifier; } + + public ModalFeedbackType getType() { + return type; + } + + public Identifier getModalFeedbackIdentifier() { + return modalFeedback.getIdentifier(); + } + + public List<ModalFeedbackCondition> getFeedbackConditons() { + return conditions; + } + + public void setFeedbackConditions(List<ModalFeedbackCondition> conditions) { + this.conditions = new ArrayList<>(conditions); + } private ResponseCondition findFeedbackResponseCondition(Identifier feedbackIdentifier, Identifier outcomeValueIdentifier) { List<ResponseRule> responseRules = assessmentItem.getResponseProcessing().getResponseRules(); @@ -177,24 +360,16 @@ public class ModalFeedbackBuilder { return false; } - private boolean findBaseValueInExpression(Expression expression, Identifier feedbackIdentifier) { - if(expression instanceof BaseValue) { - BaseValue bValue = (BaseValue)expression; - SingleValue sValue = bValue.getSingleValue(); - if(sValue instanceof IdentifierValue) { - IdentifierValue iValue = (IdentifierValue)sValue; - if(feedbackIdentifier.equals(iValue.identifierValue())) { - return true; - } - } - } else { - List<Expression> childExpressions = expression.getExpressions(); - for(Expression childExpression:childExpressions) { - if(findBaseValueInExpression(childExpression, feedbackIdentifier)) { - return true; - } - } - } - return false; + + + public enum ModalFeedbackType { + hint, + correctSolution, + correct, + incorrect, + empty, + answered, + additional, + unkown } } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackCondition.java b/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackCondition.java new file mode 100644 index 0000000000000000000000000000000000000000..4f945a6705e24b7f16ada2c7fe7847e4df034f30 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/model/xml/ModalFeedbackCondition.java @@ -0,0 +1,82 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.model.xml; + +/** + * + * Initial date: 31 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ModalFeedbackCondition { + + private Variable variable; + private Operator operator; + private String value; + + public ModalFeedbackCondition() { + // + } + + public ModalFeedbackCondition(Variable variable, Operator operator, String value) { + this.variable = variable; + this.operator = operator; + this.value = value; + } + + public Variable getVariable() { + return variable; + } + + public void setVariable(Variable variable) { + this.variable = variable; + } + + public Operator getOperator() { + return operator; + } + + public void setOperator(Operator operator) { + this.operator = operator; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public enum Variable { + score, + attempts, + response + } + + public enum Operator { + bigger, + biggerEquals, + equals, + notEquals, + smaller, + smallerEquals + } +} diff --git a/src/main/java/org/olat/ims/qti21/model/xml/OnyxToQtiWorksHandler.java b/src/main/java/org/olat/ims/qti21/model/xml/OnyxToQtiWorksHandler.java index b84585d81db330830cb8779d057fac4f71af4865..af620c4e3a557b014f556a0dd0248e9daa771c52 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/OnyxToQtiWorksHandler.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/OnyxToQtiWorksHandler.java @@ -127,8 +127,19 @@ public class OnyxToQtiWorksHandler extends DefaultHandler2 { } } } else if("assessmentItem".equals(qName) || "assessmentTest".equals(qName)) { - writeAssessmentElement(attributes); + writeAssessmentElementAttributes(attributes); + } else if("object".equals(qName)) { + writeObjectElementAttributes(attributes); + } else if("img".equals(qName)) { + writeImgElementAttributes(attributes); } else { + if("customOperator".equals(qName)) { + String customOperatorDefinition = attributes.getValue("definition"); + if("MAXIMA".equals(customOperatorDefinition)) { + xtw.writeAttribute("class", "org.olat.ims.qti21.manager.extensions.MaximaOperator"); + } + } + int numOfAttributes = attributes.getLength(); for(int i=0;i<numOfAttributes; i++) { String attrQName = attributes.getQName(i); @@ -153,7 +164,37 @@ public class OnyxToQtiWorksHandler extends DefaultHandler2 { } } - private void writeAssessmentElement(Attributes attributes) + private void writeObjectElementAttributes(Attributes attributes) + throws XMLStreamException { + int numOfAttributes = attributes.getLength(); + for(int i=0;i<numOfAttributes; i++) { + String attrQName = attributes.getQName(i); + String attrValue = attributes.getValue(i); + if("data".equals(attrQName)) { + if(attrValue.contains("%2F")) { + attrValue = attrValue.replace("%2F", "/"); + } + } + xtw.writeAttribute(attrQName, attrValue); + } + } + + private void writeImgElementAttributes(Attributes attributes) + throws XMLStreamException { + int numOfAttributes = attributes.getLength(); + for(int i=0;i<numOfAttributes; i++) { + String attrQName = attributes.getQName(i); + String attrValue = attributes.getValue(i); + if("src".equals(attrQName)) { + if(attrValue.contains("%2F")) { + attrValue = attrValue.replace("%2F", "/"); + } + } + xtw.writeAttribute(attrQName, attrValue); + } + } + + private void writeAssessmentElementAttributes(Attributes attributes) throws XMLStreamException { boolean hasToolName = false; boolean hasEditor = false; @@ -186,12 +227,84 @@ public class OnyxToQtiWorksHandler extends DefaultHandler2 { rubricCharacterBuffer.append(ch, start, length); } else { try { - xtw.writeCharacters(ch, start, length); + // replace MathJax start and end \( \ + String text = new String(ch, start, length); + if(text.contains("\\(") || text.contains("\\)")) { + processLatexParenthesis(text); + } else if(text.contains("$$")) { + processLatexDollar(text); + } else { + xtw.writeCharacters(ch, start, length); + } } catch (XMLStreamException e) { throw new SAXException(e); } } } + + private boolean latexDollarOpen = false; + + private void processLatexDollar(String text) + throws XMLStreamException, SAXException { + for(int i=100; i-->0; ) { + + int index = text.indexOf("$$"); + if(index < 0) { + char[] lastBits = text.toCharArray(); + xtw.writeCharacters(lastBits, 0, lastBits.length); + break; + } else { + String startText = text.substring(0, index); + if(startText.length() > 0) { + char[] startBits = startText.toCharArray(); + xtw.writeCharacters(startBits, 0, startBits.length); + } + + if(latexDollarOpen) { + xtw.writeEndElement(); + latexDollarOpen = false; + } else { + xtw.writeStartElement("span"); + xtw.writeAttribute("class", "math"); + latexDollarOpen = true; + } + text = text.substring(index + 2, text.length()); + } + } + } + + private void processLatexParenthesis(String text) + throws XMLStreamException, SAXException { + for(int i=100; i-->0; ) { + + int indexOpen = text.indexOf("\\("); + int indexClose = text.indexOf("\\)"); + if(indexOpen < 0 && indexClose < 0) { + char[] lastBits = text.toCharArray(); + xtw.writeCharacters(lastBits, 0, lastBits.length); + break; + } else if((indexOpen >= 0 && indexOpen < indexClose) || (indexOpen >= 0 && indexClose < 0)) { + String startText = text.substring(0, indexOpen); + if(startText.length() > 0) { + char[] startBits = startText.toCharArray(); + xtw.writeCharacters(startBits, 0, startBits.length); + } + + xtw.writeStartElement("span"); + xtw.writeAttribute("class", "math"); + text = text.substring(indexOpen + 2, text.length()); + } else if((indexClose >= 0 && indexOpen > indexClose) || (indexClose >= 0 && indexOpen < 0)) { + String startText = text.substring(0, indexClose); + if(startText.length() > 0) { + char[] startBits = startText.toCharArray(); + xtw.writeCharacters(startBits, 0, startBits.length); + } + + xtw.writeEndElement(); + text = text.substring(indexClose + 2, text.length()); + } + } + } @Override public void endElement(String uri, String localName, String qName) diff --git a/src/main/java/org/olat/ims/qti21/model/xml/QTI21ExplorerHandler.java b/src/main/java/org/olat/ims/qti21/model/xml/QTI21ExplorerHandler.java index 889d2a5743f2b6f3546e859951bfaba79ff537a0..d742171f494395907995e2dac01ba95389ea5935 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/QTI21ExplorerHandler.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/QTI21ExplorerHandler.java @@ -19,6 +19,9 @@ */ package org.olat.ims.qti21.model.xml; +import java.util.Scanner; + +import org.olat.core.util.StringHelper; import org.olat.ims.qti21.model.xml.QTI21Infos.InputType; import org.xml.sax.Attributes; import org.xml.sax.SAXException; @@ -33,6 +36,7 @@ import org.xml.sax.ext.DefaultHandler2; public class QTI21ExplorerHandler extends DefaultHandler2 { private static final String VERSION_MARKER = "Version "; + private static final String PRODID_MARKER = "PRODID:"; private StringBuilder collector; private final QTI21Infos infos = new QTI21Infos(); @@ -67,6 +71,8 @@ public class QTI21ExplorerHandler extends DefaultHandler2 { collector = new StringBuilder(); } else if("toolVersion".equals(qName)) { collector = new StringBuilder(); + } else if("entity".equals(qName)) { + collector = new StringBuilder(); } } @@ -93,6 +99,27 @@ public class QTI21ExplorerHandler extends DefaultHandler2 { collector = null; } else if("toolVersion".equals(qName)) { infos.setVersion(collector.toString().trim()); + collector = null; + } else if("entity".equals(qName)) { + String entity = collector.toString(); + if(infos.getEditor() == null && StringHelper.containsNonWhitespace(entity)) { + final Scanner s = new Scanner(entity); + while(s.hasNextLine()) { + final String line = s.nextLine(); + if(line.startsWith(PRODID_MARKER)) { + int index = line.indexOf(':') + 1; + int nextIndex = line.lastIndexOf(' '); + if(index > 0 && nextIndex > 0) { + String editor = line.substring(index, nextIndex); + String version = line.substring(nextIndex + 1); + infos.setEditor(editor); + infos.setVersion(version); + } + } + } + s.close(); + } + collector = null; } } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/ResponseIdentifierForFeedback.java b/src/main/java/org/olat/ims/qti21/model/xml/ResponseIdentifierForFeedback.java new file mode 100644 index 0000000000000000000000000000000000000000..1f8b17f5f8ca2f207edfca89c9894e000b53a394 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/model/xml/ResponseIdentifierForFeedback.java @@ -0,0 +1,58 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.model.xml; + +import java.util.List; + +import uk.ac.ed.ph.jqtiplus.types.Identifier; + +/** + * Interface to provide the response identifier for custom/additional feedbacks + * with conditions and the list of possible answers. + * + * Initial date: 1 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface ResponseIdentifierForFeedback { + + public Identifier getResponseIdentifier(); + + public List<Answer> getAnswers(); + + public class Answer { + private final String label; + private final Identifier identifier; + + public Answer(Identifier identifier, String label) { + this.label = label; + this.identifier = identifier; + } + + public String getLabel() { + return label; + } + + public Identifier getIdentifier() { + return identifier; + } + + } +} diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/ChoiceAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/ChoiceAssessmentItemBuilder.java index 5161cb3c068c69ccedfef8e6bd401a0a0fd49faa..a2564bc9059b0bd727b5a0576d9f5d4894257ec1 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/ChoiceAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/ChoiceAssessmentItemBuilder.java @@ -78,6 +78,15 @@ public abstract class ChoiceAssessmentItemBuilder extends AssessmentItemBuilder scoreMapping.put(identifier, score); } + public abstract int getMaxPossibleCorrectAnswers(); + + public abstract int getMaxChoices(); + + public abstract void setMaxChoices(int choices); + + public abstract int getMinChoices(); + + public abstract void setMinChoices(int choices); public abstract boolean isCorrect(Choice choice); diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java index 4945c6351350e71b5df2fe3030a23aa1557763a7..e93e21795a897bf82ccfa0d32c81f93081ce7057 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java @@ -37,6 +37,7 @@ import java.util.concurrent.atomic.DoubleAdder; import javax.xml.transform.stream.StreamResult; +import org.apache.commons.lang.StringEscapeUtils; import org.olat.core.gui.render.StringOutput; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; @@ -201,7 +202,7 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder { String marker = "responseIdentifier=\"" + interaction.getResponseIdentifier().toString() + "\""; question = question.replace(marker, marker + " openolatType=\"string\""); if(StringHelper.containsNonWhitespace(textEntry.getSolution())) { - question = question.replace(marker, marker + " data-qti-solution=\"" + StringHelper.escapeHtml(textEntry.getSolution()) + "\""); + question = question.replace(marker, marker + " data-qti-solution=\"" + escapeForDataQtiSolution(textEntry.getSolution()) + "\""); } entry = textEntry; @@ -390,6 +391,14 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder { textEntry.setAlternatives(alternatives); } } + + public String escapeForDataQtiSolution(String solution) { + return StringHelper.escapeHtml(solution).replace("/", "\u2215"); + } + + public String unescapeDataQtiSolution(String solution) { + return StringEscapeUtils.unescapeHtml(solution).replace("\u2215", "/"); + } @Override public QTI21QuestionType getQuestionType() { @@ -980,10 +989,10 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder { return false; } - private boolean match(double firstNumber) { + private boolean match(double answer) { double lTolerance = lowerTolerance == null ? 0.0d : lowerTolerance.doubleValue(); double uTolerance = upperTolerance == null ? 0.0d : upperTolerance.doubleValue(); - return toleranceMode.isEqual(firstNumber, solution, + return toleranceMode.isEqual(solution, answer, lTolerance, uTolerance, true, true); } @@ -1023,17 +1032,6 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder { public List<TextEntryAlternative> getAlternatives() { return alternatives; } - - public String alternativesToString() { - StringBuilder sb = new StringBuilder(); - if(alternatives != null) { - for(TextEntryAlternative alternative:alternatives) { - if(sb.length() > 0) sb.append(","); - sb.append(alternative.getAlternative()); - } - } - return sb.toString(); - } public void setAlternatives(List<TextEntryAlternative> alternatives) { this.alternatives = alternatives; diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/HotspotAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/HotspotAssessmentItemBuilder.java index dda243ded4c6e032ee732667a0247eb15317c523..32ccf6a7158c4cf96c74bad8e6f57e80fcd76638 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/HotspotAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/HotspotAssessmentItemBuilder.java @@ -40,6 +40,7 @@ import org.olat.ims.qti21.model.IdentifierGenerator; import org.olat.ims.qti21.model.QTI21QuestionType; import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; import org.olat.ims.qti21.model.xml.AssessmentItemFactory; +import org.olat.ims.qti21.model.xml.ResponseIdentifierForFeedback; import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuilder.ScoreEvaluation; import uk.ac.ed.ph.jqtiplus.node.content.ItemBody; @@ -82,7 +83,7 @@ import uk.ac.ed.ph.jqtiplus.value.SingleValue; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class HotspotAssessmentItemBuilder extends AssessmentItemBuilder { +public class HotspotAssessmentItemBuilder extends AssessmentItemBuilder implements ResponseIdentifierForFeedback { private String question; private Identifier responseIdentifier; @@ -182,6 +183,22 @@ public class HotspotAssessmentItemBuilder extends AssessmentItemBuilder { scoreEvaluation = hasMapping ? ScoreEvaluation.perAnswer : ScoreEvaluation.allCorrectAnswers; } + @Override + public Identifier getResponseIdentifier() { + return responseIdentifier; + } + + @Override + public List<Answer> getAnswers() { + List<HotspotChoice> hotspotChoices = getHotspotChoices(); + List<Answer> answers = new ArrayList<>(hotspotChoices.size()); + int count = 0; + for(HotspotChoice choice:hotspotChoices) { + answers.add(new Answer(choice.getIdentifier(), Integer.toString(++count))); + } + return answers; + } + public String getBackground() { Object graphichObject = hotspotInteraction.getObject(); if(graphichObject != null) { @@ -275,6 +292,27 @@ public class HotspotAssessmentItemBuilder extends AssessmentItemBuilder { this.question = question; } + public boolean isResponsive() { + List<String> cssClasses = hotspotInteraction.getClassAttr(); + return cssClasses != null && cssClasses.size() > 0 + && cssClasses.contains(QTI21Constants.CSS_INTERACTION_RESPONSIVE); + } + + public void setResponsive(boolean responsive) { + List<String> cssClasses = hotspotInteraction.getClassAttr(); + if(cssClasses == null) { + cssClasses = new ArrayList<>(); + } + if(responsive) { + if(!cssClasses.contains(QTI21Constants.CSS_INTERACTION_RESPONSIVE)) { + cssClasses.add(QTI21Constants.CSS_INTERACTION_RESPONSIVE); + } + } else { + cssClasses.remove(QTI21Constants.CSS_INTERACTION_RESPONSIVE); + } + hotspotInteraction.setClassAttr(cssClasses); + } + public HotspotChoice getHotspotChoice(String identifier) { List<HotspotChoice> choices = getHotspotChoices(); for(HotspotChoice choice:choices) { diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/HottextAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/HottextAssessmentItemBuilder.java index e9e1c2541651a6d91fdf62b0e28378dd84602a36..2eae339843a2d8df41abfd8faa84e6f1b3c8778c 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/HottextAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/HottextAssessmentItemBuilder.java @@ -37,10 +37,13 @@ import java.util.stream.Collectors; import javax.xml.transform.stream.StreamResult; import org.olat.core.gui.render.StringOutput; +import org.olat.core.util.filter.FilterFactory; import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.model.IdentifierGenerator; import org.olat.ims.qti21.model.QTI21QuestionType; +import org.olat.ims.qti21.model.xml.AssessmentHtmlBuilder; import org.olat.ims.qti21.model.xml.AssessmentItemFactory; +import org.olat.ims.qti21.model.xml.ResponseIdentifierForFeedback; import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuilder.ScoreEvaluation; import uk.ac.ed.ph.jqtiplus.node.content.ItemBody; @@ -85,7 +88,7 @@ import uk.ac.ed.ph.jqtiplus.value.SingleValue; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class HottextAssessmentItemBuilder extends ChoiceAssessmentItemBuilder { +public class HottextAssessmentItemBuilder extends ChoiceAssessmentItemBuilder implements ResponseIdentifierForFeedback { private String question; private Identifier responseIdentifier; @@ -188,6 +191,23 @@ public class HottextAssessmentItemBuilder extends ChoiceAssessmentItemBuilder { } } } + + @Override + public Identifier getResponseIdentifier() { + return responseIdentifier; + } + + @Override + public List<Answer> getAnswers() { + List<Hottext> hottexts = getChoices(); + List<Answer> answers = new ArrayList<>(hottexts.size()); + for(Hottext hottext:hottexts) { + String answer = new AssessmentHtmlBuilder().inlineStaticString(hottext.getInlineStatics()); + answer = FilterFactory.getHtmlTagAndDescapingFilter().filter(answer); + answers.add(new Answer(hottext.getIdentifier(), answer)); + } + return answers; + } @Override public QTI21QuestionType getQuestionType() { @@ -203,6 +223,31 @@ public class HottextAssessmentItemBuilder extends ChoiceAssessmentItemBuilder { public boolean isCorrect(Choice choice) { return correctAnswers.contains(choice.getIdentifier()); } + + @Override + public int getMaxPossibleCorrectAnswers() { + return getChoices().size(); + } + + @Override + public int getMaxChoices() { + return hottextInteraction.getMaxChoices(); + } + + @Override + public void setMaxChoices(int choices) { + hottextInteraction.setMaxChoices(choices); + } + + @Override + public int getMinChoices() { + return hottextInteraction.getMinChoices(); + } + + @Override + public void setMinChoices(int choices) { + hottextInteraction.setMinChoices(choices); + } @Override public List<Hottext> getChoices() { diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/KPrimAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/KPrimAssessmentItemBuilder.java index 9ecbebe5f261a0f5500f76a65065c954af4c60de..c054d83498345818ddf012ebb3acf038f5ef626a 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/KPrimAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/KPrimAssessmentItemBuilder.java @@ -111,6 +111,10 @@ public class KPrimAssessmentItemBuilder extends AssessmentItemBuilder { //the single choice interaction ItemBody itemBody = appendDefaultItemBody(assessmentItem); MatchInteraction matchInteraction = appendMatchInteractionForKPrim(itemBody, responseDeclarationId, defaultAnswer); + List<String> cssClasses = new ArrayList<>(); + cssClasses.add(QTI21Constants.CSS_MATCH_KPRIM); + matchInteraction.setClassAttr(cssClasses); + SimpleMatchSet matchSet = matchInteraction.getSimpleMatchSets().get(0); Map<Identifier,Identifier> associations = new HashMap<>(); for(SimpleAssociableChoice choice:matchSet.getSimpleAssociableChoices()) { @@ -271,14 +275,16 @@ public class KPrimAssessmentItemBuilder extends AssessmentItemBuilder { //add question getHtmlHelper().appendHtml(assessmentItem.getItemBody(), question); + + if(cssClass == null) { + cssClass = new ArrayList<>(); + } + if(!cssClass.contains(QTI21Constants.CSS_MATCH_KPRIM)) { + cssClass.add(QTI21Constants.CSS_MATCH_KPRIM); + } matchInteraction.setShuffle(isShuffle()); - if(cssClass == null || cssClass.isEmpty()) { - matchInteraction.setClassAttr(null); - } else { - matchInteraction.setClassAttr(cssClass); - } - + matchInteraction.setClassAttr(cssClass); blocks.add(matchInteraction); } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/MatchAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/MatchAssessmentItemBuilder.java index 59a7d45439e84275edc6d638bf8bdfed57dd4485..4f74399f85147fb0120843ce532165c3f242daec 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/MatchAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/MatchAssessmentItemBuilder.java @@ -23,6 +23,10 @@ import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.appendAssociati import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.appendDefaultItemBody; import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.appendDefaultOutcomeDeclarations; import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.appendMatchInteraction; +import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.appendSetOutcomeFeedbackCorrect; +import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.appendSetOutcomeFeedbackIncorrect; +import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.appendSetOutcomeScoreMapResponse; +import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.appendSetOutcomeScoreMaxScore; import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.createMatchResponseDeclaration; import static org.olat.ims.qti21.model.xml.AssessmentItemFactory.createResponseProcessing; @@ -44,14 +48,10 @@ import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuild import uk.ac.ed.ph.jqtiplus.group.NodeGroupList; import uk.ac.ed.ph.jqtiplus.node.content.ItemBody; import uk.ac.ed.ph.jqtiplus.node.content.basic.Block; -import uk.ac.ed.ph.jqtiplus.node.expression.general.BaseValue; import uk.ac.ed.ph.jqtiplus.node.expression.general.Correct; -import uk.ac.ed.ph.jqtiplus.node.expression.general.MapResponse; import uk.ac.ed.ph.jqtiplus.node.expression.general.Variable; import uk.ac.ed.ph.jqtiplus.node.expression.operator.IsNull; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Match; -import uk.ac.ed.ph.jqtiplus.node.expression.operator.Not; -import uk.ac.ed.ph.jqtiplus.node.expression.operator.Sum; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; import uk.ac.ed.ph.jqtiplus.node.item.CorrectResponse; import uk.ac.ed.ph.jqtiplus.node.item.interaction.MatchInteraction; @@ -62,17 +62,14 @@ import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.Mapping; import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseCondition; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseElse; -import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseElseIf; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseIf; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseProcessing; import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseRule; -import uk.ac.ed.ph.jqtiplus.node.item.response.processing.SetOutcomeValue; import uk.ac.ed.ph.jqtiplus.node.outcome.declaration.OutcomeDeclaration; import uk.ac.ed.ph.jqtiplus.node.shared.FieldValue; import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; import uk.ac.ed.ph.jqtiplus.types.ComplexReferenceIdentifier; import uk.ac.ed.ph.jqtiplus.types.Identifier; -import uk.ac.ed.ph.jqtiplus.value.BaseType; import uk.ac.ed.ph.jqtiplus.value.DirectedPairValue; import uk.ac.ed.ph.jqtiplus.value.SingleValue; @@ -447,7 +444,11 @@ public class MatchAssessmentItemBuilder extends AssessmentItemBuilder { ResponseCondition rule = new ResponseCondition(assessmentItem.getResponseProcessing()); responseRules.add(0, rule); if(scoreEvaluation == ScoreEvaluation.perAnswer) { - buildMainScoreRulePerAnswer(rule); + if(associations.isEmpty()) { + buildMainScoreRulePerAnswerNoAnswers(rule); + } else { + buildMainScoreRulePerAnswer(rule); + } } else { buildMainScoreRuleAllCorrectAnswers(rule); } @@ -455,102 +456,140 @@ public class MatchAssessmentItemBuilder extends AssessmentItemBuilder { @Override protected void buildModalFeedbacksAndHints(List<OutcomeDeclaration> outcomeDeclarations, List<ResponseRule> responseRules) { - if(correctFeedback != null || incorrectFeedback != null) { - if(scoreEvaluation == ScoreEvaluation.perAnswer) { - ResponseCondition responseCondition = AssessmentItemFactory.createModalFeedbackResponseConditionByScore(assessmentItem.getResponseProcessing()); - responseRules.add(responseCondition); - } - } - super.buildModalFeedbacksAndHints(outcomeDeclarations, responseRules); } - private void buildMainScoreRulePerAnswer(ResponseCondition rule) { + /** + * Special case where no answers are correct:<br> + * <ul> + * <li>If no answers chosen: maxScore + correct + * <li>If answer chosen: map score of answers + incorrect + * </ul> + * + * @param rule + */ + private void buildMainScoreRulePerAnswerNoAnswers(ResponseCondition rule) { /* - <responseCondition> - <responseIf> - <not> - <isNull> - <variable identifier="RESPONSE_4953445" /> - </isNull> - </not> - <setOutcomeValue identifier="SCORE"> - <sum> - <variable identifier="SCORE" /><mapResponse identifier="RESPONSE_4953445" /> - </sum> - </setOutcomeValue> - <setOutcomeValue identifier="FEEDBACKBASIC"> - <baseValue baseType="identifier"> - incorrect - </baseValue> - </setOutcomeValue> - </responseIf> - </responseCondition> - <responseCondition> - <responseIf> - <and> - <not> - <match> - <variable identifier="FEEDBACKBASIC" /> - <baseValue baseType="identifier"> - empty - </baseValue> - </match> - </not> - <equal toleranceMode="exact"> - <variable identifier="SCORE" /><variable identifier="MAXSCORE" /> - </equal> - </and> - <setOutcomeValue identifier="FEEDBACKBASIC"> - <baseValue baseType="identifier"> - correct - </baseValue> - </setOutcomeValue> - </responseIf> - </responseCondition> + <responseIf> + <isNull> + <variable identifier="RESPONSE_1"/> + </isNull> + <setOutcomeValue identifier="SCORE"> + <sum> + <variable identifier="SCORE"/> + <variable identifier="MAXSCORE"/> + </sum> + </setOutcomeValue> + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier">correct</baseValue> + </setOutcomeValue> + </responseIf> + <responseElse> + <setOutcomeValue identifier="SCORE"> + <sum> + <variable identifier="SCORE"/> + <mapResponse identifier="RESPONSE_1"/> + </sum> + </setOutcomeValue> + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier">incorrect</baseValue> + </setOutcomeValue> + </responseElse> */ - //if no response ResponseIf responseIf = new ResponseIf(rule); rule.setResponseIf(responseIf); - - Not not = new Not(responseIf); - responseIf.getExpressions().add(not); - IsNull isNull = new IsNull(not); - not.getExpressions().add(isNull); + IsNull isNull = new IsNull(responseIf); + responseIf.getExpressions().add(isNull); Variable variable = new Variable(isNull); variable.setIdentifier(ComplexReferenceIdentifier.parseString(responseIdentifier.toString())); isNull.getExpressions().add(variable); - {// outcome score - SetOutcomeValue scoreOutcome = new SetOutcomeValue(responseIf); - scoreOutcome.setIdentifier(QTI21Constants.SCORE_IDENTIFIER); - responseIf.getResponseRules().add(scoreOutcome); - - Sum sum = new Sum(scoreOutcome); - scoreOutcome.getExpressions().add(sum); - - Variable scoreVar = new Variable(sum); - scoreVar.setIdentifier(QTI21Constants.SCORE_CLX_IDENTIFIER); - sum.getExpressions().add(scoreVar); + //outcome sum score + max score + appendSetOutcomeScoreMaxScore(responseIf); - MapResponse mapResponse = new MapResponse(sum); - mapResponse.setIdentifier(responseIdentifier); - sum.getExpressions().add(mapResponse); - } + //outcome correct feedback + appendSetOutcomeFeedbackCorrect(responseIf); - {//outcome feedback - SetOutcomeValue incorrectOutcomeValue = new SetOutcomeValue(responseIf); - incorrectOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER); - responseIf.getResponseRules().add(incorrectOutcomeValue); - - BaseValue incorrectValue = new BaseValue(incorrectOutcomeValue); - incorrectValue.setBaseTypeAttrValue(BaseType.IDENTIFIER); - incorrectValue.setSingleValue(QTI21Constants.INCORRECT_IDENTIFIER_VALUE); - incorrectOutcomeValue.setExpression(incorrectValue); - } + ResponseElse responseElse = new ResponseElse(rule); + rule.setResponseElse(responseElse); + // outcome score + appendSetOutcomeScoreMapResponse(responseElse, responseIdentifier); + //outcome incorrect feedback + appendSetOutcomeFeedbackIncorrect(responseElse); + } + + /** + * Case with some correct answers and scoring per answer: + * <ul> + * <li>All correct: calculate score + correct + * <li>Else: calculate score + incorrect + * </ul> + * + * @param rule + */ + private void buildMainScoreRulePerAnswer(ResponseCondition rule) { + /* + <responseCondition> + <responseIf> + <match> + <variable identifier="RESPONSE_1"/> + <correct identifier="RESPONSE_1"/> + </match> + <setOutcomeValue identifier="SCORE"> + <sum> + <variable identifier="SCORE"/> + <mapResponse identifier="RESPONSE_1"/> + </sum> + </setOutcomeValue> + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier">correct</baseValue> + </setOutcomeValue> + </responseIf> + <responseElse> + <setOutcomeValue identifier="SCORE"> + <sum> + <variable identifier="SCORE"/> + <mapResponse identifier="RESPONSE_1"/> + </sum> + </setOutcomeValue> + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier">incorrect</baseValue> + </setOutcomeValue> + </responseElse> + </responseCondition> + */ + + //if no response + ResponseIf responseIf = new ResponseIf(rule); + rule.setResponseIf(responseIf); + Match match = new Match(responseIf); + responseIf.getExpressions().add(match); + + Variable responseVar = new Variable(match); + ComplexReferenceIdentifier choiceResponseIdentifier + = ComplexReferenceIdentifier.parseString(responseIdentifier.toString()); + responseVar.setIdentifier(choiceResponseIdentifier); + match.getExpressions().add(responseVar); + + Correct correct = new Correct(match); + correct.setIdentifier(choiceResponseIdentifier); + match.getExpressions().add(correct); + + // outcome score + appendSetOutcomeScoreMapResponse(responseIf, responseIdentifier); + //outcome correct feedback + appendSetOutcomeFeedbackCorrect(responseIf); + + ResponseElse responseElse = new ResponseElse(rule); + rule.setResponseElse(responseElse); + + // outcome score + appendSetOutcomeScoreMapResponse(responseElse, responseIdentifier); + // outcome incorrect feedback + appendSetOutcomeFeedbackIncorrect(responseElse); } private void buildMainScoreRuleAllCorrectAnswers(ResponseCondition rule) { @@ -599,82 +638,40 @@ public class MatchAssessmentItemBuilder extends AssessmentItemBuilder { ResponseIf responseIf = new ResponseIf(rule); rule.setResponseIf(responseIf); - {//if no response + // match the correct answers (or null if there are no associations) + if(associations.isEmpty()) { IsNull isNull = new IsNull(responseIf); responseIf.getExpressions().add(isNull); - Variable variable = new Variable(isNull); - variable.setIdentifier(ComplexReferenceIdentifier.parseString(responseIdentifier.toString())); - isNull.getExpressions().add(variable); - - SetOutcomeValue incorrectOutcomeValue = new SetOutcomeValue(responseIf); - incorrectOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER); - responseIf.getResponseRules().add(incorrectOutcomeValue); - - BaseValue incorrectValue = new BaseValue(incorrectOutcomeValue); - incorrectValue.setBaseTypeAttrValue(BaseType.IDENTIFIER); - incorrectValue.setSingleValue(QTI21Constants.EMPTY_IDENTIFIER_VALUE); - incorrectOutcomeValue.setExpression(incorrectValue); - } - - ResponseElseIf responseElseIf = new ResponseElseIf(rule); - rule.getResponseElseIfs().add(responseElseIf); - - {// match the correct answers - Match match = new Match(responseElseIf); - responseElseIf.getExpressions().add(match); + Variable responseVar = new Variable(isNull); + ComplexReferenceIdentifier choiceResponseIdentifier + = ComplexReferenceIdentifier.parseString(responseIdentifier.toString()); + responseVar.setIdentifier(choiceResponseIdentifier); + isNull.getExpressions().add(responseVar); + } else { + Match match = new Match(responseIf); + responseIf.getExpressions().add(match); - Variable scoreVar = new Variable(match); + Variable responseVar = new Variable(match); ComplexReferenceIdentifier choiceResponseIdentifier = ComplexReferenceIdentifier.parseString(responseIdentifier.toString()); - scoreVar.setIdentifier(choiceResponseIdentifier); - match.getExpressions().add(scoreVar); + responseVar.setIdentifier(choiceResponseIdentifier); + match.getExpressions().add(responseVar); Correct correct = new Correct(match); correct.setIdentifier(choiceResponseIdentifier); match.getExpressions().add(correct); } - {//outcome score - SetOutcomeValue scoreOutcomeValue = new SetOutcomeValue(responseElseIf); - scoreOutcomeValue.setIdentifier(QTI21Constants.SCORE_IDENTIFIER); - responseElseIf.getResponseRules().add(scoreOutcomeValue); + //outcome score + max score + appendSetOutcomeScoreMaxScore(responseIf); - Sum sum = new Sum(scoreOutcomeValue); - scoreOutcomeValue.getExpressions().add(sum); - - Variable scoreVar = new Variable(sum); - scoreVar.setIdentifier(QTI21Constants.SCORE_CLX_IDENTIFIER); - sum.getExpressions().add(scoreVar); - - Variable maxScoreVar = new Variable(sum); - maxScoreVar.setIdentifier(QTI21Constants.MAXSCORE_CLX_IDENTIFIER); - sum.getExpressions().add(maxScoreVar); - } - - {//outcome feedback - SetOutcomeValue correctOutcomeValue = new SetOutcomeValue(responseElseIf); - correctOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER); - responseElseIf.getResponseRules().add(correctOutcomeValue); - - BaseValue correctValue = new BaseValue(correctOutcomeValue); - correctValue.setBaseTypeAttrValue(BaseType.IDENTIFIER); - correctValue.setSingleValue(QTI21Constants.CORRECT_IDENTIFIER_VALUE); - correctOutcomeValue.setExpression(correctValue); - } + //outcome correct feedback + appendSetOutcomeFeedbackCorrect(responseIf); ResponseElse responseElse = new ResponseElse(rule); rule.setResponseElse(responseElse); - - {// outcome feedback - SetOutcomeValue incorrectOutcomeValue = new SetOutcomeValue(responseElse); - incorrectOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER); - responseElse.getResponseRules().add(incorrectOutcomeValue); - - BaseValue incorrectValue = new BaseValue(incorrectOutcomeValue); - incorrectValue.setBaseTypeAttrValue(BaseType.IDENTIFIER); - incorrectValue.setSingleValue(QTI21Constants.INCORRECT_IDENTIFIER_VALUE); - incorrectOutcomeValue.setExpression(incorrectValue); - } + // outcome incorrect feedback + appendSetOutcomeFeedbackIncorrect(responseElse); } } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/MultipleChoiceAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/MultipleChoiceAssessmentItemBuilder.java index a0375f34a9a5cad676a446ea57128ff63687bc0f..3a4b0a90aa722b5054a019ae6e9df77f5e73273c 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/MultipleChoiceAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/MultipleChoiceAssessmentItemBuilder.java @@ -104,7 +104,7 @@ public class MultipleChoiceAssessmentItemBuilder extends SimpleChoiceAssessmentI //the single choice interaction ItemBody itemBody = appendDefaultItemBody(assessmentItem); - ChoiceInteraction choiceInteraction = appendChoiceInteraction(itemBody, responseDeclarationId, 1, true); + ChoiceInteraction choiceInteraction = appendChoiceInteraction(itemBody, responseDeclarationId, 0, true); appendSimpleChoice(choiceInteraction, defaultAnswer, correctResponseId); @@ -160,6 +160,11 @@ public class MultipleChoiceAssessmentItemBuilder extends SimpleChoiceAssessmentI correctAnswers.add(identifier); } + @Override + public int getMaxPossibleCorrectAnswers() { + return choices.size(); + } + @Override public void clearSimpleChoices() { if(correctAnswers != null) { @@ -194,6 +199,18 @@ public class MultipleChoiceAssessmentItemBuilder extends SimpleChoiceAssessmentI blocks.add(singleChoiceInteraction); List<SimpleChoice> choiceList = getChoices(); singleChoiceInteraction.getSimpleChoices().addAll(choiceList); + + int finalMaxChoices = 0; + if(maxChoices >= 0 && maxChoices <= choiceList.size()) { + finalMaxChoices = maxChoices; + } + singleChoiceInteraction.setMaxChoices(finalMaxChoices); + + int finalMinChoices = 0; + if(minChoices >= 0 && minChoices <= choiceList.size()) { + finalMinChoices = minChoices; + } + singleChoiceInteraction.setMinChoices(finalMinChoices); } @Override diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/SimpleChoiceAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/SimpleChoiceAssessmentItemBuilder.java index 8edcace6acafed1b411ff4539585fe88ad43a502..aa651ce01068bfc8c6262266d51ad9dcace46ae3 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/SimpleChoiceAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/SimpleChoiceAssessmentItemBuilder.java @@ -26,6 +26,8 @@ import java.util.List; import javax.xml.transform.stream.StreamResult; import org.olat.core.gui.render.StringOutput; +import org.olat.core.util.filter.FilterFactory; +import org.olat.ims.qti21.model.xml.ResponseIdentifierForFeedback; import uk.ac.ed.ph.jqtiplus.node.content.basic.Block; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; @@ -47,8 +49,10 @@ import uk.ac.ed.ph.jqtiplus.value.SingleValue; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public abstract class SimpleChoiceAssessmentItemBuilder extends ChoiceAssessmentItemBuilder { - +public abstract class SimpleChoiceAssessmentItemBuilder extends ChoiceAssessmentItemBuilder implements ResponseIdentifierForFeedback { + + protected int maxChoices; + protected int minChoices; protected boolean shuffle; protected String question; protected List<String> cssClass; @@ -112,7 +116,26 @@ public abstract class SimpleChoiceAssessmentItemBuilder extends ChoiceAssessment choices.addAll(choiceInteraction.getSimpleChoices()); orientation = choiceInteraction.getOrientation(); cssClass = choiceInteraction.getClassAttr(); + maxChoices = choiceInteraction.getMaxChoices(); + minChoices = choiceInteraction.getMinChoices(); + } + } + + @Override + public Identifier getResponseIdentifier() { + return responseIdentifier; + } + + @Override + public List<Answer> getAnswers() { + List<SimpleChoice> simpleChoices = getChoices(); + List<Answer> answers = new ArrayList<>(simpleChoices.size()); + for(SimpleChoice choice:simpleChoices) { + String choiceContent = getHtmlHelper().flowStaticString(choice.getFlowStatics()); + String label = FilterFactory.getHtmlTagAndDescapingFilter().filter(choiceContent); + answers.add(new Answer(choice.getIdentifier(), label)); } + return answers; } @Override @@ -123,7 +146,27 @@ public abstract class SimpleChoiceAssessmentItemBuilder extends ChoiceAssessment public ChoiceInteraction getChoiceInteraction() { return choiceInteraction; } - + + @Override + public int getMaxChoices() { + return maxChoices; + } + + @Override + public void setMaxChoices(int maxChoices) { + this.maxChoices = maxChoices; + } + + @Override + public int getMinChoices() { + return minChoices; + } + + @Override + public void setMinChoices(int minChoices) { + this.minChoices = minChoices; + } + public boolean isShuffle() { return shuffle; } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/SingleChoiceAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/SingleChoiceAssessmentItemBuilder.java index d4758acf08c209e8e8e6eb62040d0f712b0a271e..b7ef3eaeccf2e2f2d0b719b9253ee9638b2ddc23 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/SingleChoiceAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/SingleChoiceAssessmentItemBuilder.java @@ -41,7 +41,6 @@ import uk.ac.ed.ph.jqtiplus.node.expression.general.MapResponse; import uk.ac.ed.ph.jqtiplus.node.expression.general.Variable; import uk.ac.ed.ph.jqtiplus.node.expression.operator.IsNull; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Match; -import uk.ac.ed.ph.jqtiplus.node.expression.operator.Not; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Sum; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; import uk.ac.ed.ph.jqtiplus.node.item.CorrectResponse; @@ -140,6 +139,11 @@ public class SingleChoiceAssessmentItemBuilder extends SimpleChoiceAssessmentIte correctAnswer = identifier; } + @Override + public int getMaxPossibleCorrectAnswers() { + return 1; + } + @Override public void clearSimpleChoices() { correctAnswer = null; @@ -317,11 +321,10 @@ public class SingleChoiceAssessmentItemBuilder extends SimpleChoiceAssessmentIte /* <responseCondition> <responseIf> - <not> - <isNull> - <variable identifier="RESPONSE_1" /> - </isNull> - </not> + <match> + <variable identifier="RESPONSE_1" /> + <correct identifier="RESPONSE_1" /> + </match> <setOutcomeValue identifier="SCORE"> <sum> <variable identifier="SCORE" /> @@ -330,7 +333,7 @@ public class SingleChoiceAssessmentItemBuilder extends SimpleChoiceAssessmentIte </setOutcomeValue> <setOutcomeValue identifier="FEEDBACKBASIC"> <baseValue baseType="identifier"> - incorrect + correct </baseValue> </setOutcomeValue> </responseIf> @@ -339,17 +342,20 @@ public class SingleChoiceAssessmentItemBuilder extends SimpleChoiceAssessmentIte ResponseIf responseIf = new ResponseIf(rule); rule.setResponseIf(responseIf); - Not not = new Not(responseIf); - responseIf.getExpressions().add(not); - - IsNull isNull = new IsNull(not); - not.getExpressions().add(isNull); - - Variable responseVar = new Variable(isNull); - ComplexReferenceIdentifier choiceResponseIdentifier - = ComplexReferenceIdentifier.parseString(choiceInteraction.getResponseIdentifier().toString()); - responseVar.setIdentifier(choiceResponseIdentifier); - isNull.getExpressions().add(responseVar); + {// match the correct answer + Match match = new Match(responseIf); + responseIf.getExpressions().add(match); + + Variable responseVar = new Variable(match); + ComplexReferenceIdentifier choiceResponseIdentifier + = ComplexReferenceIdentifier.parseString(choiceInteraction.getResponseIdentifier().toString()); + responseVar.setIdentifier(choiceResponseIdentifier); + match.getExpressions().add(responseVar); + + Correct correct = new Correct(match); + correct.setIdentifier(choiceResponseIdentifier); + match.getExpressions().add(correct); + } {// outcome score SetOutcomeValue scoreOutcome = new SetOutcomeValue(responseIf); @@ -369,9 +375,40 @@ public class SingleChoiceAssessmentItemBuilder extends SimpleChoiceAssessmentIte } {//outcome feedback - SetOutcomeValue incorrectOutcomeValue = new SetOutcomeValue(responseIf); + SetOutcomeValue correctOutcomeValue = new SetOutcomeValue(responseIf); + correctOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER); + responseIf.getResponseRules().add(correctOutcomeValue); + + BaseValue correctValue = new BaseValue(correctOutcomeValue); + correctValue.setBaseTypeAttrValue(BaseType.IDENTIFIER); + correctValue.setSingleValue(QTI21Constants.CORRECT_IDENTIFIER_VALUE); + correctOutcomeValue.setExpression(correctValue); + } + + ResponseElse responseElse = new ResponseElse(rule); + rule.setResponseElse(responseElse); + + {//outcome score + SetOutcomeValue scoreOutcome = new SetOutcomeValue(responseElse); + scoreOutcome.setIdentifier(QTI21Constants.SCORE_IDENTIFIER); + responseElse.getResponseRules().add(scoreOutcome); + + Sum sum = new Sum(scoreOutcome); + scoreOutcome.getExpressions().add(sum); + + Variable scoreVar = new Variable(sum); + scoreVar.setIdentifier(QTI21Constants.SCORE_CLX_IDENTIFIER); + sum.getExpressions().add(scoreVar); + + MapResponse mapResponse = new MapResponse(sum); + mapResponse.setIdentifier(choiceInteraction.getResponseIdentifier()); + sum.getExpressions().add(mapResponse); + } + + {// outcome feedback + SetOutcomeValue incorrectOutcomeValue = new SetOutcomeValue(responseElse); incorrectOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER); - responseIf.getResponseRules().add(incorrectOutcomeValue); + responseElse.getResponseRules().add(incorrectOutcomeValue); BaseValue incorrectValue = new BaseValue(incorrectOutcomeValue); incorrectValue.setBaseTypeAttrValue(BaseType.IDENTIFIER); diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI12To21Converter.java b/src/main/java/org/olat/ims/qti21/pool/QTI12To21Converter.java index 06203519fe247c7097bd1bf8058ff4b1ae0bae4f..b40ae88c1f2daf608622a1489b8fb82190f52eec 100644 --- a/src/main/java/org/olat/ims/qti21/pool/QTI12To21Converter.java +++ b/src/main/java/org/olat/ims/qti21/pool/QTI12To21Converter.java @@ -60,6 +60,7 @@ import org.olat.ims.qti.editor.QTIEditHelper; import org.olat.ims.qti.editor.QTIEditorPackage; import org.olat.ims.qti.editor.beecom.objects.Assessment; import org.olat.ims.qti.editor.beecom.objects.ChoiceQuestion; +import org.olat.ims.qti.editor.beecom.objects.ChoiceResponse; import org.olat.ims.qti.editor.beecom.objects.Control; import org.olat.ims.qti.editor.beecom.objects.Duration; import org.olat.ims.qti.editor.beecom.objects.EssayQuestion; @@ -76,6 +77,7 @@ import org.olat.ims.qti.editor.beecom.objects.SelectionOrdering; import org.olat.ims.qti.fileresource.TestFileResource; import org.olat.ims.qti.qpool.QTI12HtmlHandler; import org.olat.ims.qti21.QTI21Constants; +import org.olat.ims.qti21.QTI21DeliveryOptions; import org.olat.ims.qti21.model.IdentifierGenerator; import org.olat.ims.qti21.model.xml.AssessmentHtmlBuilder; import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; @@ -85,6 +87,10 @@ import org.olat.ims.qti21.model.xml.AssessmentTestFactory; import org.olat.ims.qti21.model.xml.ManifestBuilder; import org.olat.ims.qti21.model.xml.ManifestMetadataBuilder; import org.olat.ims.qti21.model.xml.ModalFeedbackBuilder; +import org.olat.ims.qti21.model.xml.ModalFeedbackBuilder.ModalFeedbackType; +import org.olat.ims.qti21.model.xml.ModalFeedbackCondition; +import org.olat.ims.qti21.model.xml.ModalFeedbackCondition.Operator; +import org.olat.ims.qti21.model.xml.ModalFeedbackCondition.Variable; import org.olat.ims.qti21.model.xml.QtiNodesExtractor; import org.olat.ims.qti21.model.xml.interactions.EssayAssessmentItemBuilder; import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder; @@ -149,12 +155,12 @@ public class QTI12To21Converter { manifest = ManifestBuilder.createAssessmentTestBuilder(); } - public AssessmentTest convert(QTIEditorPackage qtiEditorPackage) + public AssessmentTest convert(QTIEditorPackage qtiEditorPackage, QTI21DeliveryOptions qti21Options) throws URISyntaxException { - return convert(qtiEditorPackage.getBaseDir(), qtiEditorPackage.getQTIDocument()); + return convert(qtiEditorPackage.getBaseDir(), qtiEditorPackage.getQTIDocument(), qti21Options); } - public AssessmentTest convert(VFSContainer originalContainer, QTIDocument doc) + public AssessmentTest convert(VFSContainer originalContainer, QTIDocument doc, QTI21DeliveryOptions qti21Options) throws URISyntaxException { Assessment assessment = doc.getAssessment(); @@ -172,12 +178,17 @@ public class QTI12To21Converter { TestPart testPart = AssessmentTestFactory.createTestPart(assessmentTest); ItemSessionControl itemSessionControl = testPart.getItemSessionControl(); Control tmpControl = QTIEditHelper.getControl(assessment); - if(tmpControl.getFeedback() == Control.CTRL_YES) { - itemSessionControl.setShowFeedback(Boolean.TRUE); - } if(tmpControl.getSolution() == Control.CTRL_YES) { itemSessionControl.setShowSolution(Boolean.TRUE); } + + if(qti21Options != null) { + qti21Options.setHideFeedbacks(false); + + if(assessment.isInheritControls() && tmpControl.getFeedback() != Control.CTRL_YES) { + qti21Options.setHideFeedbacks(true); + } + } AssessmentTestBuilder assessmentTestBuilder = new AssessmentTestBuilder(assessmentTest); @@ -425,6 +436,7 @@ public class QTI12To21Converter { convertOrientation(question, itemBuilder); List<Response> responses = question.getResponses(); + Map<String,Identifier> identToIdentifier = new HashMap<>(); for(Response response:responses) { String responseText = response.getContent().renderAsHtmlForEditor(); responseText = blockedHtml(responseText); @@ -438,12 +450,15 @@ public class QTI12To21Converter { .createSimpleChoice(interaction, responseText, itemBuilder.getQuestionType().getPrefix()); } itemBuilder.addSimpleChoice(newChoice); + identToIdentifier.put(response.getIdent(), newChoice.getIdentifier()); if(response.isCorrect()) { itemBuilder.setCorrectAnswer(newChoice.getIdentifier()); } } + convertFeedbackPerAnswers(item, itemBuilder, identToIdentifier); + double correctScore = question.getSingleCorrectScore(); if(correctScore >= 0.0d) { itemBuilder.setMinScore(0.0d); @@ -474,6 +489,7 @@ public class QTI12To21Converter { } boolean singleCorrect = question.isSingleCorrect(); + Map<String, Identifier> identToIdentifier = new HashMap<>(); for(Response response:responses) { String responseText = response.getContent().renderAsHtmlForEditor(); responseText = blockedHtml(responseText); @@ -489,6 +505,7 @@ public class QTI12To21Converter { } itemBuilder.addSimpleChoice(newChoice); + identToIdentifier.put(response.getIdent(), newChoice.getIdentifier()); double score = response.getPoints(); if(singleCorrect) { @@ -506,6 +523,8 @@ public class QTI12To21Converter { } } + convertFeedbackPerAnswers(item, itemBuilder, identToIdentifier); + if(singleCorrect) { itemBuilder.setScoreEvaluationMode(ScoreEvaluation.allCorrectAnswers); } else { @@ -682,21 +701,53 @@ public class QTI12To21Converter { String solutionText = question.getSolutionText(); if(StringHelper.containsNonWhitespace(solutionText)) { ModalFeedbackBuilder solution = itemBuilder.createCorrectSolutionFeedback(); + solutionText = blockedHtml(solutionText); solution.setText(solutionText); } String feedbackMastery = QTIEditHelper.getFeedbackMasteryText(item); if(StringHelper.containsNonWhitespace(feedbackMastery)) { ModalFeedbackBuilder feedback = itemBuilder.createCorrectFeedback(); + feedbackMastery = blockedHtml(feedbackMastery); feedback.setText(feedbackMastery); } String feedbackFail = QTIEditHelper.getFeedbackFailText(item); if(StringHelper.containsNonWhitespace(feedbackFail)) { ModalFeedbackBuilder feedback = itemBuilder.createIncorrectFeedback(); + feedbackFail = blockedHtml(feedbackFail); feedback.setText(feedbackFail); } + + } + + private void convertFeedbackPerAnswers(Item item, AssessmentItemBuilder itemBuilder, Map<String,Identifier> identToIdentifier) { + Question question = item.getQuestion(); + + List<ModalFeedbackBuilder> additionalFeedbacks = new ArrayList<>(); + for (Response response : question.getResponses()) { + if(response instanceof ChoiceResponse) { + Material responseFeedbackMat = QTIEditHelper.getFeedbackOlatRespMaterial(item, response.getIdent()); + if(responseFeedbackMat != null) { + String feedbackCondition = responseFeedbackMat.renderAsHtmlForEditor(); + feedbackCondition = blockedHtml(feedbackCondition); + + ModalFeedbackCondition condition = new ModalFeedbackCondition(); + condition.setVariable(Variable.response); + condition.setOperator(Operator.equals); + condition.setValue(identToIdentifier.get(response.getIdent()).toString()); + List<ModalFeedbackCondition> conditions = new ArrayList<>(1); + conditions.add(condition); + + ModalFeedbackBuilder feedback = new ModalFeedbackBuilder(itemBuilder.getAssessmentItem(), ModalFeedbackType.additional); + feedback.setFeedbackConditions(conditions); + feedback.setText(feedbackCondition); + additionalFeedbacks.add(feedback); + } + } + } + itemBuilder.setAdditionalFeedbackBuilders(additionalFeedbacks); } private void convertDuration(Duration duration, ControlObject<?> parent) { 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 95e4dc25d7427def4aa5aed248b798f54d9d3041..2cdd962474834b781c4ba9ae3de88d0eb7b82966 100644 --- a/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java +++ b/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java @@ -55,7 +55,10 @@ import org.olat.ims.qti21.model.QTI21QuestionType; import org.olat.ims.qti21.model.xml.AssessmentItemMetadata; import org.olat.ims.qti21.model.xml.ManifestBuilder; import org.olat.ims.qti21.model.xml.ManifestMetadataBuilder; +import org.olat.ims.qti21.model.xml.AssessmentItemChecker; import org.olat.ims.qti21.model.xml.OnyxToQtiWorksHandler; +import org.olat.ims.qti21.model.xml.QTI21Infos; +import org.olat.ims.qti21.repository.handlers.QTI21IMSManifestExplorerVisitor; import org.olat.imscp.xml.manifest.ResourceType; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionType; @@ -142,6 +145,17 @@ public class QTI21ImportProcessor { return items; } + private QTI21Infos getInfos(Path imsmanifestPath) { + try { + QTI21IMSManifestExplorerVisitor visitor = new QTI21IMSManifestExplorerVisitor(); + Files.walkFileTree(imsmanifestPath, visitor); + return visitor.getInfos(); + } catch (IOException e) { + log.error("", e); + return null; + } + } + private QuestionItem processResource(ResourceType resource, Path imsmanifestPath, ManifestMetadataBuilder metadataBuilder) { try { String href = resource.getHref(); @@ -158,7 +172,8 @@ public class QTI21ImportProcessor { if(!outputFile.getParentFile().exists()) { outputFile.getParentFile().mkdirs(); } - convertXmlFile(assessmentItemPath, outputFile.toPath()); + QTI21Infos infos = getInfos(imsmanifestPath); + convertXmlFile(assessmentItemPath, outputFile.toPath(), infos); QtiXmlReader qtiXmlReader = new QtiXmlReader(qtiService.jqtiExtensionManager()); ResourceLocator fileResourceLocator = new FileResourceLocator(); @@ -170,6 +185,10 @@ public class QTI21ImportProcessor { ResolvedAssessmentItem resolvedAssessmentItem = assessmentObjectXmlLoader.loadAndResolveAssessmentItem(assessmentObjectSystemId); AssessmentItem assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful(); + if(!AssessmentItemChecker.checkAndCorrect(assessmentItem)) { + qtiService.persistAssessmentObject(outputFile, assessmentItem); + } + AssessmentItemMetadata metadata = new AssessmentItemMetadata(metadataBuilder); String editor = null; @@ -207,14 +226,14 @@ public class QTI21ImportProcessor { } } - private void convertXmlFile(Path inputFile, Path outputFile) { + private void convertXmlFile(Path inputFile, Path outputFile, QTI21Infos infos) { try(InputStream in = Files.newInputStream(inputFile); Writer out = Files.newBufferedWriter(outputFile, Charset.forName("UTF-8"))) { XMLOutputFactory xof = XMLOutputFactory.newInstance(); XMLStreamWriter xtw = xof.createXMLStreamWriter(out); SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); - OnyxToQtiWorksHandler myHandler = new OnyxToQtiWorksHandler(xtw, null); + OnyxToQtiWorksHandler myHandler = new OnyxToQtiWorksHandler(xtw, infos); saxParser.setProperty("http://xml.org/sax/properties/lexical-handler", myHandler); saxParser.parse(in, myHandler); } catch(Exception e) { diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java b/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java index 283e5e0ff9348349cb4d92781911f3fba379b2fe..e1f8f7674c4445d1b4a88ddb89e0b653044bf417 100644 --- a/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java +++ b/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -61,6 +62,7 @@ import org.olat.ims.qti.editor.QTIEditHelper; import org.olat.ims.qti.editor.QTIEditorPackage; import org.olat.ims.qti.editor.beecom.objects.Item; import org.olat.ims.qti21.QTI21Constants; +import org.olat.ims.qti21.QTI21DeliveryOptions; import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.model.QTI21QuestionType; import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; @@ -175,11 +177,6 @@ public class QTI21QPoolServiceProvider implements QPoolSPI { boolean ok = new AssessmentItemFileResourceValidator().validate(filename, file); return ok; } - @Override - public boolean isCompatible(String filename, VFSLeaf file) { - boolean ok = new AssessmentItemFileResourceValidator().validate(filename, file); - return ok; - } @Override public boolean isConversionPossible(QuestionItemShort item) { @@ -215,6 +212,10 @@ public class QTI21QPoolServiceProvider implements QPoolSPI { VFSItem file = container.resolve(item.getRootFilename()); if(file instanceof VFSLeaf) { VFSLeaf leaf = (VFSLeaf)file; + if(leaf.getSize() <= 0l) { + return ""; + } + QTI21SAXHandler handler = new QTI21SAXHandler(); try(InputStream is = leaf.getInputStream()) { XMLReader parser = XMLReaderFactory.createXMLReader(); @@ -223,7 +224,7 @@ public class QTI21QPoolServiceProvider implements QPoolSPI { parser.setFeature("http://xml.org/sax/features/validation", false); parser.parse(new InputSource(is)); } catch (Exception e) { - log.error("", e); + log.error("Cannot read the XML file of the question item: " + leaf, e); } return handler.toString(); } @@ -526,10 +527,10 @@ public class QTI21QPoolServiceProvider implements QPoolSPI { * * @param qtiEditorPackage */ - public boolean convertFromEditorPackage(QTIEditorPackage qtiEditorPackage, File unzippedDirRoot, Locale locale) { + public boolean convertFromEditorPackage(QTIEditorPackage qtiEditorPackage, File unzippedDirRoot, Locale locale, QTI21DeliveryOptions qti21Options) { try { QTI12To21Converter converter = new QTI12To21Converter(unzippedDirRoot, locale); - converter.convert(qtiEditorPackage); + converter.convert(qtiEditorPackage, qti21Options); return true; } catch (URISyntaxException e) { log.error("", e); diff --git a/src/main/java/org/olat/ims/qti21/questionimport/CSVToAssessmentItemConverter.java b/src/main/java/org/olat/ims/qti21/questionimport/CSVToAssessmentItemConverter.java index 9c53d51a6f27427501fa6deb5f407913e7c93c49..1f37625ad1990448693deb7001653253d7fb5a92 100644 --- a/src/main/java/org/olat/ims/qti21/questionimport/CSVToAssessmentItemConverter.java +++ b/src/main/java/org/olat/ims/qti21/questionimport/CSVToAssessmentItemConverter.java @@ -55,6 +55,7 @@ public class CSVToAssessmentItemConverter { private static final OLog log = Tracing.createLoggerFor(CSVToAssessmentItemConverter.class); + private int currentLine; private int kprimPosition = 0; private ImportOptions options; private final QtiSerializer qtiSerializer; @@ -70,10 +71,16 @@ public class CSVToAssessmentItemConverter { return items; } + public int getCurrentLine() { + return currentLine; + } + public void parse(String input) { String[] lines = input.split("\r?\n"); for (int i = 0; i<lines.length; i++) { + currentLine = i+1; + String line = lines[i]; if (line.equals("")) { continue; diff --git a/src/main/java/org/olat/ims/qti21/questionimport/TextInputController.java b/src/main/java/org/olat/ims/qti21/questionimport/TextInputController.java index 2fed63b45d768f1d1c13687aa54a4fe992ddff88..5faaab251d81625bb19238f3e03588c8cd4f4b5a 100644 --- a/src/main/java/org/olat/ims/qti21/questionimport/TextInputController.java +++ b/src/main/java/org/olat/ims/qti21/questionimport/TextInputController.java @@ -51,7 +51,6 @@ public class TextInputController extends StepFormBasicController { private String validatedInp; private TextElement inputElement; - private List<AssessmentItemAndMetadata> parsedItems; private final AssessmentItemsPackage importedItems; private final ImportOptions options; @@ -92,8 +91,18 @@ public class TextInputController extends StepFormBasicController { String inp = inputElement.getValue(); if(validatedInp == null || !validatedInp.equals(inp)) { - boolean errors = convertInputField(); - allOk &= !errors; + CSVToAssessmentItemConverter converter = new CSVToAssessmentItemConverter(options, qtiService.qtiSerializer()); + try { + converter.parse(inputElement.getValue()); + List<AssessmentItemAndMetadata> items = converter.getItems(); + if(items == null || items.isEmpty()) { + inputElement.setErrorKey("form.mandatory.hover", null); + allOk &= false; + } + } catch (Exception e) { + inputElement.setErrorKey("error.at.line", new String[] { Integer.toString(converter.getCurrentLine()) }); + allOk &= false; + } } return allOk & super.validateFormLogic(ureq); @@ -101,16 +110,10 @@ public class TextInputController extends StepFormBasicController { @Override protected void formOK(UserRequest ureq) { - importedItems.setItems(parsedItems); - fireEvent(ureq, StepsEvent.ACTIVATE_NEXT); - } - - private boolean convertInputField() { - boolean importDataError = false; CSVToAssessmentItemConverter converter = new CSVToAssessmentItemConverter(options, qtiService.qtiSerializer()); converter.parse(inputElement.getValue()); - parsedItems = converter.getItems(); - return importDataError; + importedItems.setItems(converter.getItems()); + fireEvent(ureq, StepsEvent.ACTIVATE_NEXT); } private static class ExampleMapper implements Mapper { diff --git a/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_de.properties index c4bdb8bdc07a426c401ec63d9054b8428bddec7d..7b90d6b01b38bbe0df60c7d5bc924183652195d6 100644 --- a/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_de.properties @@ -14,3 +14,4 @@ item.type.fib=$org.olat.ims.qti.editor\:item.type.fib item.type.kprim=$org.olat.ims.qti.editor\:item.type.kprim item.type.mc=$org.olat.ims.qti.editor\:item.type.mc item.type.sc=$org.olat.ims.qti.editor\:item.type.sc +error.at.line=Problem auf Zeile {0} diff --git a/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_en.properties index 9dd0dabfd55398edfdba12048bfb8a60acd3c96c..0373ba6cb2117befecbe86577a235b0da089160a 100644 --- a/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_en.properties @@ -13,4 +13,5 @@ item.type.essay=$org.olat.ims.qti.editor\:item.type.essay item.type.fib=$org.olat.ims.qti.editor\:item.type.fib item.type.kprim=$org.olat.ims.qti.editor\:item.type.kprim item.type.mc=$org.olat.ims.qti.editor\:item.type.mc -item.type.sc=$org.olat.ims.qti.editor\:item.type.sc \ No newline at end of file +item.type.sc=$org.olat.ims.qti.editor\:item.type.sc +error.at.line=Issue with line {0} \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_fr.properties index 9dd0dabfd55398edfdba12048bfb8a60acd3c96c..7d7701b21f484eac3a91c0a98557238fbfad8309 100644 --- a/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_fr.properties @@ -1,16 +1,17 @@ -#Mon Aug 25 16:10:51 CEST 2014 +#Tue Aug 15 17:19:04 CEST 2017 download.example=$org.olat.ims.qti.questionimport\:download.example -wizard.import.input.title=$org.olat.ims.qti.questionimport\:wizard.import.input.title -wizard.import.input.description=$org.olat.ims.qti.questionimport\:wizard.import.input.description -wizard.import.overview.title=$org.olat.ims.qti.questionimport\:wizard.import.overview.title -input.title=$org.olat.ims.qti.questionimport\:input.title +error.at.line=Erreur ligne {0} form.importdata=$org.olat.ims.qti.questionimport\:form.importdata -table.header.status=$org.olat.ims.qti.questionimport\:table.header.status -table.header.type=$org.olat.ims.qti.questionimport\:table.header.type -table.header.title=$org.olat.ims.qti.questionimport\:table.header.title -table.header.points=$org.olat.ims.qti.questionimport\:table.header.points +input.title=$org.olat.ims.qti.questionimport\:input.title item.type.essay=$org.olat.ims.qti.editor\:item.type.essay item.type.fib=$org.olat.ims.qti.editor\:item.type.fib item.type.kprim=$org.olat.ims.qti.editor\:item.type.kprim item.type.mc=$org.olat.ims.qti.editor\:item.type.mc -item.type.sc=$org.olat.ims.qti.editor\:item.type.sc \ No newline at end of file +item.type.sc=$org.olat.ims.qti.editor\:item.type.sc +table.header.points=$org.olat.ims.qti.questionimport\:table.header.points +table.header.status=$org.olat.ims.qti.questionimport\:table.header.status +table.header.title=$org.olat.ims.qti.questionimport\:table.header.title +table.header.type=$org.olat.ims.qti.questionimport\:table.header.type +wizard.import.input.description=$org.olat.ims.qti.questionimport\:wizard.import.input.description +wizard.import.input.title=$org.olat.ims.qti.questionimport\:wizard.import.input.title +wizard.import.overview.title=$org.olat.ims.qti.questionimport\:wizard.import.overview.title diff --git a/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_pt_BR.properties index 29f166476525386ec73f175d3ad75cdff6b1936c..416277e03a0ed4e350b62618d3147e5336554601 100644 --- a/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/ims/qti21/questionimport/_i18n/LocalStrings_pt_BR.properties @@ -1,5 +1,6 @@ -#Mon Jan 16 19:49:07 CET 2017 +#Tue Jul 25 22:13:31 CEST 2017 download.example=$org.olat.ims.qti.questionimport\:download.example +error.at.line=Problema com a linha {0} form.importdata=$org.olat.ims.qti.questionimport\:form.importdata input.title=$org.olat.ims.qti.questionimport\:input.title item.type.essay=$org.olat.ims.qti.editor\:item.type.essay diff --git a/src/main/java/org/olat/ims/qti21/repository/handlers/CopyAndConvertVisitor.java b/src/main/java/org/olat/ims/qti21/repository/handlers/CopyAndConvertVisitor.java index 1761b8b2664d3684dbc3bd9e2315f4a4e24b977a..388a144d3efad0a5c4f20b7539679471e3b90d7d 100644 --- a/src/main/java/org/olat/ims/qti21/repository/handlers/CopyAndConvertVisitor.java +++ b/src/main/java/org/olat/ims/qti21/repository/handlers/CopyAndConvertVisitor.java @@ -20,6 +20,7 @@ package org.olat.ims.qti21.repository.handlers; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Writer; @@ -42,12 +43,16 @@ import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamWriter; +import org.olat.core.CoreSpringFactory; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.WebappHelper; +import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; +import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.model.xml.BadRessourceHelper; import org.olat.ims.qti21.model.xml.Onyx38ToQtiWorksHandler; +import org.olat.ims.qti21.model.xml.AssessmentItemChecker; import org.olat.ims.qti21.model.xml.OnyxToQtiWorksHandler; import org.olat.ims.qti21.model.xml.QTI21ExplorerHandler; import org.olat.ims.qti21.model.xml.QTI21Infos; @@ -57,6 +62,7 @@ import org.xml.sax.helpers.DefaultHandler; import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; import uk.ac.ed.ph.jqtiplus.node.RootNode; +import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; import uk.ac.ed.ph.jqtiplus.provision.BadResourceException; import uk.ac.ed.ph.jqtiplus.reading.AssessmentObjectXmlLoader; import uk.ac.ed.ph.jqtiplus.reading.QtiXmlInterpretationException; @@ -65,6 +71,7 @@ import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentTest; import uk.ac.ed.ph.jqtiplus.validation.ItemValidationResult; import uk.ac.ed.ph.jqtiplus.validation.TestValidationResult; +import uk.ac.ed.ph.jqtiplus.xmlutils.locators.FileResourceLocator; import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; /** @@ -136,6 +143,11 @@ class CopyAndConvertVisitor extends SimpleFileVisitor<Path> { try { boolean validated = true; QTI21Infos fileInfos = scanFile(inputFile); + //inherit from test if needed + if(fileInfos.getEditor() == null && infos.getEditor() != null) { + fileInfos.setEditor(infos.getEditor()); + fileInfos.setVersion(infos.getVersion()); + } if(onyx38Family(fileInfos)) { validated = convertXmlFile(inputFile, outputFile, fileInfos.getType(), new HandlerProvider() { @Override @@ -144,12 +156,17 @@ class CopyAndConvertVisitor extends SimpleFileVisitor<Path> { } }); } else if(onyxWebFamily(fileInfos)) { - validated = convertXmlFile(inputFile, outputFile, infos.getType(), new HandlerProvider() { + validated = convertXmlFile(inputFile, outputFile, fileInfos.getType(), new HandlerProvider() { @Override public DefaultHandler2 create(XMLStreamWriter xtw) { return new OnyxToQtiWorksHandler(xtw, infos); } }); + + if(validated && fileInfos.getType() == InputType.assessmentItem) { + //check templateVariables + checkAssessmentItem(outputFile); + } } else { Files.copy(inputFile, outputFile, StandardCopyOption.REPLACE_EXISTING); } @@ -245,6 +262,27 @@ class CopyAndConvertVisitor extends SimpleFileVisitor<Path> { } } + private void checkAssessmentItem(Path outputFile) { + QTI21Service qtiService = CoreSpringFactory.getImpl(QTI21Service.class); + QtiXmlReader qtiXmlReader = new QtiXmlReader(qtiService.jqtiExtensionManager()); + ResourceLocator fileResourceLocator = new FileResourceLocator(); + ResourceLocator inputResourceLocator = + ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator); + + URI assessmentObjectSystemId = outputFile.toFile().toURI(); + AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, inputResourceLocator); + ResolvedAssessmentItem resolvedAssessmentItem = assessmentObjectXmlLoader.loadAndResolveAssessmentItem(assessmentObjectSystemId); + AssessmentItem assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful(); + + if(!AssessmentItemChecker.checkAndCorrect(assessmentItem)) { + try(FileOutputStream out = new FileOutputStream(outputFile.toFile())) { + qtiService.qtiSerializer().serializeJqtiObject(assessmentItem, out); + } catch(Exception e) { + log.error("", e); + } + } + } + public interface HandlerProvider { public DefaultHandler2 create(XMLStreamWriter xtw); diff --git a/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java index 600bb1f800f07128b879f171b4ec25e92b1367fc..c3e38028320e9b58a8133f37c451bb96c4099fe0 100644 --- a/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java +++ b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.Locale; import org.olat.core.CoreSpringFactory; @@ -52,7 +53,6 @@ import org.olat.core.util.coordinate.LockResult; import org.olat.course.assessment.AssessmentMode; import org.olat.course.assessment.manager.UserCourseInformationsManager; import org.olat.fileresource.FileResourceManager; -import org.olat.fileresource.ZippedDirectoryMediaResource; import org.olat.fileresource.types.FileResource; import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.fileresource.types.ResourceEvaluation; @@ -147,7 +147,9 @@ public class QTI21AssessmentTestHandler extends FileHandler { qpoolServiceProvider.exportToEditorPackage(repositoryDir, itemToImport.getItems(), locale); } else if(createObject instanceof QTIEditorPackage) { QTIEditorPackage testToConvert = (QTIEditorPackage)createObject; - qpoolServiceProvider.convertFromEditorPackage(testToConvert, repositoryDir, locale); + QTI21DeliveryOptions options = qtiService.getDeliveryOptions(re); + qpoolServiceProvider.convertFromEditorPackage(testToConvert, repositoryDir, locale, options); + qtiService.setDeliveryOptions(re, options); } else if(createObject instanceof OLATResource) { //convert a Onyx test in QTI 2.1 OLATResource onyxResource = (OLATResource)createObject; @@ -156,8 +158,10 @@ public class QTI21AssessmentTestHandler extends FileHandler { if(OnyxModule.isOnyxTest((OLATResource)createObject)) { copyOnyxResources(onyxResource, repositoryDir); } else { + QTI21DeliveryOptions options = qtiService.getDeliveryOptions(re); QTIEditorPackage testToConvert = TestFileResource.getQTIEditorPackageReader(onyxResource); - qpoolServiceProvider.convertFromEditorPackage(testToConvert, repositoryDir, locale); + qpoolServiceProvider.convertFromEditorPackage(testToConvert, repositoryDir, locale, options); + qtiService.setDeliveryOptions(re, options); } copyMetadata(onyxRe, re, repositoryDir); } else { @@ -265,9 +269,19 @@ public class QTI21AssessmentTestHandler extends FileHandler { boolean withReferences, Locale locale, File file, String filename) { ImsQTI21Resource ores = new ImsQTI21Resource(); OLATResource resource = OLATResourceManager.getInstance().createAndPersistOLATResourceInstance(ores); - File fResourceFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(resource).getBasefile(); + File fResourceFileroot = FileResourceManager.getInstance().getFileResourceRoot(resource); File zipDir = new File(fResourceFileroot, FileResourceManager.ZIPDIR); copyResource(file, filename, zipDir); + + File optionsFile = new File(zipDir, QTI21Service.PACKAGE_CONFIG_FILE_NAME); + if(optionsFile.exists()) { + try {// move the options to the root directory + File target = new File(fResourceFileroot, QTI21Service.PACKAGE_CONFIG_FILE_NAME); + Files.move(optionsFile.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + log.error("", e); + } + } RepositoryEntry re = CoreSpringFactory.getImpl(RepositoryService.class) .create(initialAuthor, null, "", displayname, description, resource, RepositoryEntry.ACC_OWNERS); @@ -295,10 +309,7 @@ public class QTI21AssessmentTestHandler extends FileHandler { @Override public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) { - File unzippedDir = FileResourceManager.getInstance().unzipFileResource(res); - String displayName = CoreSpringFactory.getImpl(RepositoryManager.class) - .lookupDisplayNameByOLATResourceableId(res.getResourceableId()); - return new ZippedDirectoryMediaResource(displayName, unzippedDir); + return new QTI21AssessmentTestMediaResource(res); } @Override @@ -308,6 +319,10 @@ public class QTI21AssessmentTestHandler extends FileHandler { File sourceDir = new File(sourceRootFile, FileResourceManager.ZIPDIR); File targetDir = new File(targetRootDir, FileResourceManager.ZIPDIR); FileUtils.copyDirContentsToDir(sourceDir, targetDir, false, "Copy"); + File sourceOptionsFile = new File(sourceRootFile, QTI21Service.PACKAGE_CONFIG_FILE_NAME); + if(sourceOptionsFile.exists()) { + FileUtils.copyFileToDir(sourceOptionsFile, targetRootDir, "Copy QTI 2.1 Options"); + } return target; } diff --git a/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestMediaResource.java b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestMediaResource.java new file mode 100644 index 0000000000000000000000000000000000000000..a7c7958eaddd386ec179c59809d45eec048f0fd6 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestMediaResource.java @@ -0,0 +1,110 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.repository.handlers; + +import java.io.File; +import java.io.InputStream; +import java.util.zip.ZipOutputStream; + +import javax.servlet.http.HttpServletResponse; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.id.OLATResourceable; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.ZipUtil; +import org.olat.fileresource.FileResourceManager; +import org.olat.ims.qti21.QTI21Service; +import org.olat.repository.RepositoryManager; + +/** + * + * Initial date: 14 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QTI21AssessmentTestMediaResource implements MediaResource { + + private static final OLog log = Tracing.createLoggerFor(QTI21AssessmentTestMediaResource.class); + + private final OLATResourceable resource; + + public QTI21AssessmentTestMediaResource(OLATResourceable resource) { + this.resource = resource; + } + + @Override + public boolean acceptRanges() { + return false; + } + + @Override + public String getContentType() { + return "application/zip"; + } + + @Override + public Long getSize() { + return null; + } + + @Override + public InputStream getInputStream() { + return null; + } + + @Override + public Long getLastModified() { + return null; + } + + @Override + public void prepare(HttpServletResponse hres) { + File unzipDir = FileResourceManager.getInstance().unzipFileResource(resource); + File rootDir = FileResourceManager.getInstance().getFileResourceRoot(resource); + + String displayName = CoreSpringFactory.getImpl(RepositoryManager.class) + .lookupDisplayNameByOLATResourceableId(resource.getResourceableId()); + + String label = StringHelper.transformDisplayNameToFileSystemName(displayName) + ".zip"; + String urlEncodedLabel = StringHelper.urlEncodeUTF8(label); + hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + urlEncodedLabel); + hres.setHeader("Content-Description", urlEncodedLabel); + + try(ZipOutputStream zout = new ZipOutputStream(hres.getOutputStream())) { + zout.setLevel(9); + ZipUtil.addPathToZip(unzipDir.toPath(), zout); + + File sourceOptionsFile = new File(rootDir, QTI21Service.PACKAGE_CONFIG_FILE_NAME); + if(sourceOptionsFile.exists()) { + ZipUtil.addFileToZip(QTI21Service.PACKAGE_CONFIG_FILE_NAME, sourceOptionsFile, zout); + } + } catch (Exception e) { + log.error("", e); + } + } + + @Override + public void release() { + // + } +} diff --git a/src/main/java/org/olat/ims/qti21/resultexport/_content/qti21results.html b/src/main/java/org/olat/ims/qti21/resultexport/_content/qti21results.html index 8440db543e322e61088dd7958d1b83e2c3051505..010af363694a44c5ef88ef923598c1199e3d6ccc 100644 --- a/src/main/java/org/olat/ims/qti21/resultexport/_content/qti21results.html +++ b/src/main/java/org/olat/ims/qti21/resultexport/_content/qti21results.html @@ -26,29 +26,30 @@ function setFlexiFormDirtyByListener(e){ // } function o_mathjax() { - jQuery.ajax("${r.mathJaxCdnFullUrl()}MathJax.js?config=TeX-AMS-MML_HTMLorMML", { + window.MathJax = { + extensions: ["jsMath2jax.js"], + messageStyle: 'none', + showProcessingMessages: false, + showMathMenu: false, + menuSettings: { }, + jsMath2jax: { + preview: "none" + }, + tex2jax: { + ignoreClass: "math" + }, + "HTML-CSS": { + EqnChunk: 5, EqnChunkFactor: 1, EqnChunkDelay: 100 + }, + "fast-preview": { + disabled: true + } + } + jQuery.ajax("${r.mathJaxCdnFullUrl()}MathJax.js?config=${r.mathJaxConfig()}", { cache: true, dataType: "script", + crossDomain: true, success: function() { - MathJax.Hub.Config({ - extensions: ["jsMath2jax.js"], - messageStyle: 'none', - showProcessingMessages: false, - showMathMenu: false, - menuSettings: { }, - jsMath2jax: { - preview: "none" - }, - tex2jax: { - ignoreClass: "math" - }, - "HTML-CSS": { - EqnChunk: 5, EqnChunkFactor: 1, EqnChunkDelay: 100 - }, - "fast-preview": { - disabled: true - } - }); } }); } @@ -70,4 +71,4 @@ jQuery(function() { <body class="o_page_margins"> <div id="o_main">$r.render("results")</div> </body> -</html> \ No newline at end of file +</html> diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentEntryOutcomesListener.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentEntryOutcomesListener.java index 93ecfed65f55e410543ce675469107aef7fa10b5..0a7bd1e8fe0c2b534223b3dbad45b5c197d16e33 100644 --- a/src/main/java/org/olat/ims/qti21/ui/AssessmentEntryOutcomesListener.java +++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentEntryOutcomesListener.java @@ -51,14 +51,20 @@ public class AssessmentEntryOutcomesListener implements OutcomesListener { private AssessmentEntry assessmentEntry; private final AssessmentService assessmentService; + private final RepositoryEntry entry; + private final RepositoryEntry testEntry; + private final boolean authorMode; private final boolean needManualCorrection; private AtomicBoolean start = new AtomicBoolean(true); private AtomicBoolean close = new AtomicBoolean(true); - public AssessmentEntryOutcomesListener(AssessmentEntry assessmentEntry, boolean needManualCorrection, + public AssessmentEntryOutcomesListener(RepositoryEntry entry, RepositoryEntry testEntry, + AssessmentEntry assessmentEntry, boolean needManualCorrection, AssessmentService assessmentService, boolean authorMode) { + this.entry = entry; + this.testEntry = testEntry; this.assessmentEntry = assessmentEntry; this.assessmentService = assessmentService; this.authorMode = authorMode; @@ -67,10 +73,11 @@ public class AssessmentEntryOutcomesListener implements OutcomesListener { @Override public void decorateConfirmation(AssessmentTestSession candidateSession, DigitalSignatureOptions options, Date timestamp, Locale locale) { - decorateResourceConfirmation(candidateSession, options, timestamp, locale); + decorateResourceConfirmation(entry, testEntry, candidateSession, options, timestamp, locale); } - public static void decorateResourceConfirmation(AssessmentTestSession candidateSession, DigitalSignatureOptions options, Date timestamp, Locale locale) { + public static void decorateResourceConfirmation(RepositoryEntry entry, RepositoryEntry testEntry, AssessmentTestSession candidateSession, + DigitalSignatureOptions options, Date timestamp, Locale locale) { MailBundle bundle = new MailBundle(); bundle.setToId(candidateSession.getIdentity()); String fullname = CoreSpringFactory.getImpl(UserManager.class).getUserDisplayName(candidateSession.getIdentity()); @@ -78,8 +85,6 @@ public class AssessmentEntryOutcomesListener implements OutcomesListener { Translator translator = Util.createPackageTranslator(QTI21RuntimeController.class, locale); - RepositoryEntry entry = candidateSession.getRepositoryEntry(); - RepositoryEntry testEntry = candidateSession.getTestEntry(); String[] args = new String[] { entry.getDisplayname(), // {0} entry.getKey().toString(), // {1} diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentItemDisplayController.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentItemDisplayController.java index c658fd6b07c3e55fb003df3d9675f1edb0e07fe6..723e7ce44be01dc7929d4b56869f39b725140608 100644 --- a/src/main/java/org/olat/ims/qti21/ui/AssessmentItemDisplayController.java +++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentItemDisplayController.java @@ -72,6 +72,7 @@ import uk.ac.ed.ph.jqtiplus.running.ItemSessionController; import uk.ac.ed.ph.jqtiplus.running.ItemSessionControllerSettings; import uk.ac.ed.ph.jqtiplus.state.ItemProcessingMap; import uk.ac.ed.ph.jqtiplus.state.ItemSessionState; +import uk.ac.ed.ph.jqtiplus.state.TestPlanNode; import uk.ac.ed.ph.jqtiplus.types.FileResponseData; import uk.ac.ed.ph.jqtiplus.types.Identifier; import uk.ac.ed.ph.jqtiplus.types.ResponseData; @@ -241,6 +242,16 @@ public class AssessmentItemDisplayController extends BasicController implements return false; } + @Override + public boolean isRubricHidden(Identifier sectionKey) { + return false; + } + + @Override + public int getNumber(TestPlanNode node) { + return 1; + } + @Override protected void event(UserRequest ureq, Component source, Event event) { currentRequestTimestamp = ureq.getRequestTimestamp(); diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java index 54da0a8e8313f67acece9db3b113b6e61e71ddc6..1fb9eb9f30739b87c9ae1c9fcfe0e07283ff46d8 100644 --- a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java +++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java @@ -34,6 +34,7 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; @@ -176,6 +177,7 @@ public class AssessmentTestDisplayController extends BasicController implements private AssessmentTestSession candidateSession; private ResolvedAssessmentTest resolvedAssessmentTest; private AssessmentTestMarks marks; + private final Map<TestPlanNode, Integer> numbering = new HashMap<>(); private RepositoryEntry testEntry; private RepositoryEntry entry; @@ -244,7 +246,7 @@ public class AssessmentTestDisplayController extends BasicController implements fUnzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource()); resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(fUnzippedDirRoot, false, false); if(resolvedAssessmentTest == null || resolvedAssessmentTest.getRootNodeLookup().extractIfSuccessful() == null) { - mainVC = createVelocityContainer("error"); + mainVC = createVelocityContainer("error"); } else { currentRequestTimestamp = ureq.getRequestTimestamp(); @@ -258,11 +260,14 @@ public class AssessmentTestDisplayController extends BasicController implements /* Handle immediate end of test session */ if (testSessionController.getTestSessionState() != null && testSessionController.getTestSessionState().isEnded()) { - immediateEndTestSession(ureq); - mainVC = createVelocityContainer("end"); + immediateEndTestSession(ureq); + mainVC = createVelocityContainer("end"); } else { - mainVC = createVelocityContainer("run"); - initQtiWorks(ureq); + mainVC = createVelocityContainer("run"); + initQtiWorks(ureq); + if(!deliveryOptions.isShowTitles()) { + initNumbering(); + } } OLATResourceable sessionOres = OresHelper @@ -273,6 +278,18 @@ public class AssessmentTestDisplayController extends BasicController implements mainPanel = putInitialPanel(mainVC); } + private void initNumbering() { + AtomicInteger number = new AtomicInteger(0); + List<TestPlanNode> nodes = testSessionController.getTestSessionState().getTestPlan().getTestPlanNodeList(); + for(TestPlanNode node:nodes) { + if(node.getTestNodeType() == TestNodeType.ASSESSMENT_ITEM_REF) { + numbering.put(node, number.incrementAndGet()); + } else if(node.getTestNodeType() == TestNodeType.TEST_PART) { + number.set(0); + } + } + } + private void immediateEndTestSession(UserRequest ureq) { AssessmentResult assessmentResult = qtiService.getAssessmentResult(candidateSession); if(assessmentResult == null) { @@ -310,7 +327,7 @@ public class AssessmentTestDisplayController extends BasicController implements AssessmentEntry assessmentEntry = assessmentService.getOrCreateAssessmentEntry(assessedIdentity, anonymousIdentifier, entry, subIdent, testEntry); if(outcomesListener == null) { boolean manualCorrections = AssessmentTestHelper.needManualCorrection(resolvedAssessmentTest); - outcomesListener = new AssessmentEntryOutcomesListener(assessmentEntry, manualCorrections, assessmentService, authorMode); + outcomesListener = new AssessmentEntryOutcomesListener(entry, testEntry, assessmentEntry, manualCorrections, assessmentService, authorMode); } AssessmentTestSession lastSession = qtiService.getResumableAssessmentTestSession(assessedIdentity, anonymousIdentifier, entry, subIdent, testEntry, authorMode); @@ -367,8 +384,8 @@ public class AssessmentTestDisplayController extends BasicController implements private void initQtiWorks(UserRequest ureq) { qtiWorksCtrl = new QtiWorksController(ureq, getWindowControl()); - listenTo(qtiWorksCtrl); - mainVC.put("qtirun", qtiWorksCtrl.getInitialComponent()); + listenTo(qtiWorksCtrl); + mainVC.put("qtirun", qtiWorksCtrl.getInitialComponent()); } @Override @@ -378,11 +395,21 @@ public class AssessmentTestDisplayController extends BasicController implements .createOLATResourceableInstance(AssessmentTestSession.class, candidateSession.getKey()); CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(this, sessionOres); } - + + /** + * @return true if the termination time is set. + */ @Override public boolean isTerminated() { return candidateSession.getTerminationTime() != null; } + + /** + * @return true if the termination time or the finished time is set. + */ + public boolean isEnded() { + return candidateSession.getTerminationTime() != null || candidateSession.getFinishTime() != null; + } @Override public AssessmentTestSession getCandidateSession() { @@ -400,7 +427,7 @@ public class AssessmentTestDisplayController extends BasicController implements } public boolean isResultsVisible() { - return qtiWorksCtrl.isResultsVisible(); + return qtiWorksCtrl != null && qtiWorksCtrl.isResultsVisible(); } @Override @@ -651,17 +678,14 @@ public class AssessmentTestDisplayController extends BasicController implements case mark: toogleMark(qe.getSubCommand()); break; + case rubric: + toogleRubric(qe.getSubCommand()); + break; } } private void toogleMark(String itemRef) { - if(marks == null) { - if(anonym) { - marks = new InMemoryAssessmentTestMarks(itemRef); - } else { - marks = qtiService.createMarks(assessedIdentity, entry, subIdent, testEntry, ""); - } - } + marks = getMarkerObject(); String currentMarks = marks.getMarks(); if(currentMarks == null) { @@ -676,11 +700,50 @@ public class AssessmentTestDisplayController extends BasicController implements } } + private void toogleRubric(String sectionRef) { + marks = getMarkerObject(); + + String hiddenRubrics = marks.getHiddenRubrics(); + if(hiddenRubrics == null) { + marks.setHiddenRubrics(sectionRef); + } else if(hiddenRubrics.indexOf(sectionRef) >= 0) { + marks.setHiddenRubrics(hiddenRubrics.replace(sectionRef, "")); + } else { + marks.setHiddenRubrics(hiddenRubrics + " " + sectionRef); + } + if(marks instanceof Persistable) { + marks = qtiService.updateMarks(marks); + } + } + + private final AssessmentTestMarks getMarkerObject() { + if(marks == null) { + if(anonym) { + marks = new InMemoryAssessmentTestMarks(); + } else { + marks = qtiService.createMarks(assessedIdentity, entry, subIdent, testEntry, ""); + } + } + return marks; + } + @Override public boolean isMarked(String itemKey) { if(marks == null || marks.getMarks() == null) return false; return marks.getMarks().indexOf(itemKey) >= 0; } + + @Override + public boolean isRubricHidden(Identifier sectionKey) { + if(marks == null || marks.getHiddenRubrics() == null || sectionKey == null) return false; + return marks.getHiddenRubrics().indexOf(sectionKey.toString()) >= 0; + } + + @Override + public int getNumber(TestPlanNode node) { + Integer number = numbering.get(node); + return number == null ? -1 : number.intValue(); + } private void processSelectItem(UserRequest ureq, String key) { TestPlanNodeKey nodeKey = TestPlanNodeKey.fromString(key); @@ -840,7 +903,7 @@ public class AssessmentTestDisplayController extends BasicController implements /* If we ended the testPart and there are now no more available testParts, then finish the session now */ if (nextItemNode==null && testSessionController.findNextEnterableTestPart()==null) { - candidateSession = qtiService.finishTestSession(candidateSession, testSessionState, assessmentResult, + candidateSession = qtiService.finishTestSession(candidateSession, testSessionState, assessmentResult, requestTimestamp, getDigitalSignatureOptions(), getIdentity()); } @@ -1462,21 +1525,23 @@ public class AssessmentTestDisplayController extends BasicController implements final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); TestSessionController controller = createTestSessionController(notificationRecorder); - controller.unsuspendTestSession(requestTimestamp); - - TestSessionState testSessionState = controller.getTestSessionState(); - TestPlanNodeKey currentItemKey = testSessionState.getCurrentItemKey(); - if(currentItemKey != null) { - TestPlanNode currentItemNode = testSessionState.getTestPlan().getNode(currentItemKey); - ItemProcessingContext itemProcessingContext = controller.getItemProcessingContext(currentItemNode); - ItemSessionState itemSessionState = itemProcessingContext.getItemSessionState(); - if(itemProcessingContext instanceof ItemSessionController - && itemSessionState.isSuspended()) { - ItemSessionController itemSessionController = (ItemSessionController)itemProcessingContext; - itemSessionController.unsuspendItemSession(requestTimestamp); - } - } - + if(!controller.getTestSessionState().isEnded() && !controller.getTestSessionState().isExited()) { + controller.unsuspendTestSession(requestTimestamp); + + TestSessionState testSessionState = controller.getTestSessionState(); + TestPlanNodeKey currentItemKey = testSessionState.getCurrentItemKey(); + if(currentItemKey != null) { + TestPlanNode currentItemNode = testSessionState.getTestPlan().getNode(currentItemKey); + ItemProcessingContext itemProcessingContext = controller.getItemProcessingContext(currentItemNode); + ItemSessionState itemSessionState = itemProcessingContext.getItemSessionState(); + if(itemProcessingContext instanceof ItemSessionController + && itemSessionState.isSuspended()) { + ItemSessionController itemSessionController = (ItemSessionController)itemProcessingContext; + itemSessionController.unsuspendItemSession(requestTimestamp); + } + } + } + return controller; } @@ -1688,6 +1753,7 @@ public class AssessmentTestDisplayController extends BasicController implements qtiTreeEl.setAssessmentObjectUri(qtiService.createAssessmentTestUri(fUnzippedDirRoot)); qtiTreeEl.setCandidateSessionContext(AssessmentTestDisplayController.this); qtiTreeEl.setMapperUri(mapperUri); + qtiTreeEl.setShowTitles(deliveryOptions.isShowTitles()); if(formLayout instanceof FormLayoutContainer) { FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; @@ -1875,7 +1941,7 @@ public class AssessmentTestDisplayController extends BasicController implements @Override protected void propagateDirtinessToContainer(FormItem fiSrc, FormEvent fe) { - if(!"mark".equals(fe.getCommand())) { + if(!"mark".equals(fe.getCommand()) && !"rubric".equals(fe.getCommand())) { super.propagateDirtinessToContainer(fiSrc, fe); } } diff --git a/src/main/java/org/olat/ims/qti21/ui/CandidateSessionContext.java b/src/main/java/org/olat/ims/qti21/ui/CandidateSessionContext.java index ed650a38eaa9d63a31bdc85d657a151f232c5ab2..03286e2ebaf6c60e48c2a4081453a9cb23177082 100644 --- a/src/main/java/org/olat/ims/qti21/ui/CandidateSessionContext.java +++ b/src/main/java/org/olat/ims/qti21/ui/CandidateSessionContext.java @@ -24,6 +24,9 @@ import java.util.Date; import org.olat.ims.qti21.AssessmentTestSession; import org.olat.ims.qti21.model.audit.CandidateEvent; +import uk.ac.ed.ph.jqtiplus.state.TestPlanNode; +import uk.ac.ed.ph.jqtiplus.types.Identifier; + /** * * Initial date: 04.03.2016<br> @@ -41,6 +44,8 @@ public interface CandidateSessionContext { public Date getCurrentRequestTimestamp(); public boolean isMarked(String itemKey); + + public boolean isRubricHidden(Identifier sectionKey); - + public int getNumber(TestPlanNode node); } diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21AdminController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21AdminController.java index 390a6808043cc364722fefaf7561fb30582d4fcf..7f5f951d1593ccaa34ad45871b3f3134082336dc 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21AdminController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21AdminController.java @@ -39,6 +39,7 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle import org.olat.core.util.StringHelper; import org.olat.core.util.crypto.CryptoUtil; import org.olat.core.util.crypto.X509CertificatePrivateKeyPair; +import org.olat.ims.qti.QTIModule; import org.olat.ims.qti21.QTI21Module; import org.olat.ims.qti21.ui.assessment.ValidationXmlSignatureController; import org.springframework.beans.factory.annotation.Autowired; @@ -58,15 +59,18 @@ public class QTI21AdminController extends FormBasicController { private static final String[] onValues = new String[]{ "" }; private FormLink validationButton; - private MultipleSelectionElement mathExtensionEl, digitalSignatureEl; + private MultipleSelectionElement mathExtensionEl, digitalSignatureEl, createQTI12resourcesEl; private FileElement certificateEl; private TextElement certificatePasswordEl; private CloseableModalController cmc; private ValidationXmlSignatureController validationCtrl; - + + + @Autowired + private QTIModule qti12Module; @Autowired - private QTI21Module qtiModule; + private QTI21Module qti21Module; public QTI21AdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl, "admin"); @@ -75,16 +79,30 @@ public class QTI21AdminController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - validationButton = uifactory.addFormLink("validate.xml.signature", formLayout, Link.BUTTON); + FormLayoutContainer qti12LayoutCont = FormLayoutContainer.createDefaultFormLayout("optionsFor12", getTranslator()); + qti12LayoutCont.setRootForm(mainForm); + formLayout.add("optionsFor12", qti12LayoutCont); + qti12LayoutCont.setFormTitle(translate("admin.12.title")); + + createQTI12resourcesEl = uifactory.addCheckboxesHorizontal("create.12.resources", "create.12.resources", qti12LayoutCont, + onKeys, onValues); + if(qti12Module.isCreateResourcesEnabled()) { + createQTI12resourcesEl.select(onKeys[0], true); + } + FormLayoutContainer layoutCont = FormLayoutContainer.createDefaultFormLayout("options", getTranslator()); layoutCont.setRootForm(mainForm); formLayout.add("options", layoutCont); layoutCont.setFormTitle(translate("admin.title")); + + validationButton = uifactory.addFormLink("validate.xml.signature", layoutCont, Link.BUTTON); + validationButton.setCustomEnabledLinkCSS("btn btn-default pull-right"); + validationButton.getComponent().setSuppressDirtyFormWarning(true); digitalSignatureEl = uifactory.addCheckboxesHorizontal("digital.signature", "digital.signature", layoutCont, onKeys, onValues); - if(qtiModule.isDigitalSignatureEnabled()) { + if(qti21Module.isDigitalSignatureEnabled()) { digitalSignatureEl.select(onKeys[0], true); } digitalSignatureEl.setExampleKey("digital.signature.text", null); @@ -93,12 +111,12 @@ public class QTI21AdminController extends FormBasicController { certificateEl = uifactory.addFileElement(getWindowControl(), "digital.signature.certificate", "digital.signature.certificate", layoutCont); certificateEl.setExampleKey("digital.signature.certificate.example", null); certificateEl.setHelpText(translate("digital.signature.certificate.hint")); - if(StringHelper.containsNonWhitespace(qtiModule.getDigitalSignatureCertificate())) { - File certificate = qtiModule.getDigitalSignatureCertificateFile(); + if(StringHelper.containsNonWhitespace(qti21Module.getDigitalSignatureCertificate())) { + File certificate = qti21Module.getDigitalSignatureCertificateFile(); certificateEl.setInitialFile(certificate); } - String certificatePassword = qtiModule.getDigitalSignatureCertificatePassword(); + String certificatePassword = qti21Module.getDigitalSignatureCertificatePassword(); String password = StringHelper.containsNonWhitespace(certificatePassword) ? PASSWORD_PLACEHOLDER : ""; certificatePasswordEl = uifactory.addPasswordElement("digital.signature.certificate.password", "digital.signature.certificate.password", 256, password, layoutCont); @@ -106,7 +124,7 @@ public class QTI21AdminController extends FormBasicController { mathExtensionEl = uifactory.addCheckboxesHorizontal("math.extension", "math.extension", layoutCont, onKeys, onValues); - if(qtiModule.isMathAssessExtensionEnabled()) { + if(qti21Module.isMathAssessExtensionEnabled()) { mathExtensionEl.select(onKeys[0], true); } mathExtensionEl.setExampleKey("math.extension.text", null); @@ -168,6 +186,13 @@ public class QTI21AdminController extends FormBasicController { return allOk; } + + @Override + protected void propagateDirtinessToContainer(FormItem source, FormEvent fe) { + if(source != this.validationButton) { + super.propagateDirtinessToContainer(source, fe); + } + } @Override protected void event(UserRequest ureq, Controller source, Event event) { @@ -192,19 +217,21 @@ public class QTI21AdminController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { - qtiModule.setMathAssessExtensionEnabled(mathExtensionEl.isSelected(0)); - qtiModule.setDigitalSignatureEnabled(digitalSignatureEl.isSelected(0)); + qti12Module.setCreateResourcesEnabled(createQTI12resourcesEl.isSelected(0)); + + qti21Module.setMathAssessExtensionEnabled(mathExtensionEl.isSelected(0)); + qti21Module.setDigitalSignatureEnabled(digitalSignatureEl.isSelected(0)); if(digitalSignatureEl.isSelected(0)) { File uploadedCertificate = certificateEl.getUploadFile(); if(uploadedCertificate != null && uploadedCertificate.exists()) { - qtiModule.setDigitalSignatureCertificateFile(uploadedCertificate, certificateEl.getUploadFileName()); - File newFile = qtiModule.getDigitalSignatureCertificateFile(); + qti21Module.setDigitalSignatureCertificateFile(uploadedCertificate, certificateEl.getUploadFileName()); + File newFile = qti21Module.getDigitalSignatureCertificateFile(); certificateEl.reset();// make sure the same certificate is not load twice certificateEl.setInitialFile(newFile); } String password = certificatePasswordEl.getValue(); if(!PASSWORD_PLACEHOLDER.equals(password)) { - qtiModule.setDigitalSignatureCertificatePassword(password); + qti21Module.setDigitalSignatureCertificatePassword(password); } } } diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessableResource.java b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessableResource.java index b14b35085e1bc7164185dec6245c6b93359b6b91..ce773a7f4e86cde824d3a99b26329ddd33fcc946 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessableResource.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessableResource.java @@ -22,12 +22,10 @@ package org.olat.ims.qti21.ui; import java.util.ArrayList; import java.util.List; -import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.stack.TooledStackedPanel; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; -import org.olat.ims.qti21.QTI21Service; import org.olat.modules.assessment.AssessmentToolOptions; import org.olat.modules.assessment.ui.AssessableResource; import org.olat.repository.RepositoryEntry; @@ -53,13 +51,8 @@ public class QTI21AssessableResource extends AssessableResource { List<Controller> toolsCtrl = new ArrayList<>(1); toolsCtrl.add(resetToolCtrl); - boolean isRunningSession = CoreSpringFactory.getImpl(QTI21Service.class) - .isRunningAssessmentTestSession(entry, null, entry); - if(isRunningSession) { - Controller retrieveToolCtrl = new QTI21RetrieveTestsToolController(ureq, wControl, entry, options); - toolsCtrl.add(retrieveToolCtrl); - } - + Controller retrieveToolCtrl = new QTI21RetrieveTestsToolController(ureq, wControl, entry, options); + toolsCtrl.add(retrieveToolCtrl); return toolsCtrl; } } diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java index 00dbae274541982eaabf3f69e9d9d72bed8e60c7..11c6728fd9fff522c877fc75e9f9b161f00f44df 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java @@ -28,6 +28,8 @@ import java.util.Comparator; import java.util.Date; import java.util.List; +import javax.servlet.http.HttpServletResponse; + import org.olat.core.commons.persistence.DB; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; @@ -50,8 +52,10 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.gui.media.FileMediaResource; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; +import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; @@ -77,6 +81,7 @@ import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentService; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.model.RepositoryEntrySecurity; @@ -216,7 +221,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.correction.i18nHeaderKey(), TSCols.correction.ordinal(), "correction", new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("correction"), "correction"), null))); } - + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("download.log", translate("download.log"), "log")); tableModel = new QTI21AssessmentTestSessionTableModel(columnsModel, getTranslator()); tableEl = uifactory.addTableElement(getWindowControl(), "sessions", tableModel, 20, false, getTranslator(), formLayout); @@ -341,6 +346,8 @@ public class QTI21AssessmentDetailsController extends FormBasicController { } } else if("correction".equals(cmd)) { doCorrection(ureq, testSession); + } else if("log".equals(cmd)) { + doDownloadLog(ureq, testSession); } } } @@ -367,7 +374,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController { Float score = finalScore == null ? null : finalScore.floatValue(); ScoreEvaluation manualScoreEval = new ScoreEvaluation(score, scoreEval.getPassed(), scoreEval.getAssessmentStatus(), null, scoreEval.getFullyAssessed(), session.getKey()); - courseNode.updateUserScoreEvaluation(manualScoreEval, assessedUserCourseEnv, getIdentity(), false); + courseNode.updateUserScoreEvaluation(manualScoreEval, assessedUserCourseEnv, getIdentity(), false, Role.coach); } private void doUpdateEntry(AssessmentTestSession session) { @@ -434,7 +441,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController { DigitalSignatureOptions options = new DigitalSignatureOptions(digitalSignature, sendMail, entry, testEntry); if(digitalSignature) { if(courseNode == null) { - AssessmentEntryOutcomesListener.decorateResourceConfirmation(session, options, null, getLocale()); + AssessmentEntryOutcomesListener.decorateResourceConfirmation(entry, testEntry, session, options, null, getLocale()); } else { CourseEnvironment courseEnv = CourseFactory.loadCourse(entry).getCourseEnvironment(); QTI21AssessmentRunController.decorateCourseConfirmation(session, options, courseEnv, courseNode, sessionTestEntry, null, getLocale()); @@ -462,6 +469,53 @@ public class QTI21AssessmentDetailsController extends FormBasicController { listenTo(cmc); } + private void doDownloadLog(UserRequest ureq, AssessmentTestSession session) { + File logFile = qtiService.getAssessmentSessionAuditLogFile(session); + if(logFile != null && logFile.exists()) { + String filename = "auditlog_"; + if(session.getAnonymousIdentifier() != null) { + filename += session.getAnonymousIdentifier(); + } else { + filename += session.getIdentity().getUser().getFirstName() + + "_" + session.getIdentity().getUser().getLastName(); + } + filename += "_" + entry.getDisplayname(); + if(courseNode != null) { + if(StringHelper.containsNonWhitespace(courseNode.getShortTitle())) { + filename += "_" + courseNode.getShortTitle(); + } else { + filename += "_" + courseNode.getLongTitle(); + } + } + + filename += ".log"; + ureq.getDispatchResult().setResultingMediaResource(new LogDownload(logFile, filename)); + } else { + showWarning("warning.download.log"); + } + } + + private static class LogDownload extends FileMediaResource { + + private final String filename; + + public LogDownload(File file, String filename) { + super(file, true); + this.filename = filename; + } + + @Override + public String getContentType() { + return "application/octet-stream"; + } + + @Override + public void prepare(HttpServletResponse hres) { + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(filename)); + hres.setHeader("Content-Description", StringHelper.urlEncodeUTF8(filename)); + } + } + public static class AssessmentTestSessionComparator implements Comparator<QTI21AssessmentTestSessionDetails> { @Override diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java index 2353e8c1cd9223ba3595a13364b3e90270b4ab7c..99ab6726ce9bffbc021edbb810ea3ee37db2a40c 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java @@ -63,6 +63,7 @@ import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.manager.archive.QTI21ArchiveFormat; import org.olat.ims.qti21.model.QTI21StatisticSearchParams; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; import org.springframework.beans.factory.annotation.Autowired; @@ -200,7 +201,7 @@ public class QTI21ResetToolController extends BasicController { ScoreEvaluation scoreEval = new ScoreEvaluation(null, null); IdentityEnvironment ienv = new IdentityEnvironment(identity, studentRoles); UserCourseEnvironment uce = new UserCourseEnvironmentImpl(ienv, courseEnv); - testCourseNode.updateUserScoreEvaluation(scoreEval, uce, getIdentity(), false); + testCourseNode.updateUserScoreEvaluation(scoreEval, uce, getIdentity(), false, Role.coach); } } else if(assessedEntry != null) { archiveData(assessedEntry); diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21RetrieveTestsToolController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21RetrieveTestsToolController.java index 6993fac5ed277197feb2b7efd05655daff492dba..5b401f0185c024c912e2c2fa1bca05dba082c0c0 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21RetrieveTestsToolController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21RetrieveTestsToolController.java @@ -47,7 +47,6 @@ import org.olat.core.util.Util; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.resource.OresHelper; import org.olat.course.archiver.ScoreAccountingHelper; -import org.olat.course.nodes.ArchiveOptions; import org.olat.course.nodes.IQTESTCourseNode; import org.olat.course.run.environment.CourseEnvironment; import org.olat.group.BusinessGroupService; @@ -110,9 +109,37 @@ public class QTI21RetrieveTestsToolController extends BasicController implements initButton(); } + private List<Identity> getIdentities() { + List<Identity> identities; + if(asOptions.getGroup() == null && asOptions.getIdentities() == null) { + if(courseEnv != null) { + identities = ScoreAccountingHelper.loadUsers(courseEnv); + } else { + identities = repositoryService.getMembers(assessedEntry, GroupRoles.participant.name()); + } + } else if (asOptions.getIdentities() != null) { + identities = asOptions.getIdentities(); + } else { + identities = businessGroupService.getMembers(asOptions.getGroup()); + } + return identities; + } + private void initButton() { + boolean enabled; + List<Identity> identities = getIdentities(); + if(identities == null || identities.isEmpty()) { + enabled = false; + } else if(courseEnv != null) { + enabled = qtiService.isRunningAssessmentTestSession(courseEnv.getCourseGroupManager().getCourseEntry(), + courseNode.getIdent(), courseNode.getReferencedRepositoryEntry(), getIdentities()); + } else { + enabled = qtiService.isRunningAssessmentTestSession(assessedEntry, null, assessedEntry, getIdentities()); + } + pullButton = LinkFactory.createButton("menu.retrieve.tests.title", null, this); pullButton.setTranslator(getTranslator()); + pullButton.setEnabled(enabled); putInitialPanel(pullButton); getInitialComponent().setSpanAsDomReplaceable(true); // override to wrap panel as span to not break link layout } @@ -158,24 +185,7 @@ public class QTI21RetrieveTestsToolController extends BasicController implements sessions = qtiService.getRunningAssessmentTestSession(assessedEntry, null, assessedEntry); } - ArchiveOptions options = new ArchiveOptions(); - List<Identity> identities = null; - if(asOptions.getGroup() == null && asOptions.getIdentities() == null) { - if(courseEnv != null) { - identities = ScoreAccountingHelper.loadUsers(courseEnv); - options.setIdentities(identities); - } else { - identities = repositoryService.getMembers(assessedEntry, GroupRoles.participant.name()); - options.setIdentities(identities); - } - } else if (asOptions.getIdentities() != null) { - identities = asOptions.getIdentities(); - options.setIdentities(identities); - } else { - identities = businessGroupService.getMembers(asOptions.getGroup()); - options.setGroup(asOptions.getGroup()); - } - + List<Identity> identities = getIdentities(); List<AssessmentTestSession> sessionsToRetrieve = new ArrayList<>(); Set<Identity> assessedIdentites = new HashSet<>(identities); for(AssessmentTestSession session:sessions) { diff --git a/src/main/java/org/olat/ims/qti21/ui/QTIWorksAssessmentTestEvent.java b/src/main/java/org/olat/ims/qti21/ui/QTIWorksAssessmentTestEvent.java index eea61875d9d50109327809e326341cc1e9e2c181..854391ea9d0a98728b685bd4488c2203c23a2dc9 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTIWorksAssessmentTestEvent.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTIWorksAssessmentTestEvent.java @@ -55,7 +55,8 @@ public class QTIWorksAssessmentTestEvent extends FormEvent { exitTest("exit-test", "exit-test"),//impl timesUp("times-up", "times-up"), tmpResponse("response-tmp", "response-tmp"), - mark("mark", "mark"); + mark("mark", "mark"), + rubric("rubric", "rubric"); private final String path; private final String event; diff --git a/src/main/java/org/olat/ims/qti21/ui/_content/admin.html b/src/main/java/org/olat/ims/qti21/ui/_content/admin.html index 15634a7db2399a5a56fcbf7be696a3fd3021d718..f8552ac9a2e455e9d4412fa55be8c22f0debcb9e 100644 --- a/src/main/java/org/olat/ims/qti21/ui/_content/admin.html +++ b/src/main/java/org/olat/ims/qti21/ui/_content/admin.html @@ -1,4 +1,2 @@ -<div class="o_button_group o_button_group_right"> -$r.render("validate.xml.signature") -</div> +$r.render("optionsFor12") $r.render("options") \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties index c7116fbf9a9af9d60cc5d31d580261bfab2da46e..023f04cdb8b58f091c71b15ada00631a46b6270b 100644 --- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties @@ -3,6 +3,7 @@ actualPoints=$org.olat.modules.iq\:actualPoints admin.menu.title=QTI 2.1 admin.menu.title.alt=QTI 2.1 Einstellungen admin.title=QTI 2.1 Einstellungen +admin.12.title=QTI 1.2 Einstellungen anonym.not.allowed.descr=Anonyme Benutzer d\u00FCrfen diesen Test nicht durchf\u00FChren anonym.not.allowed.title=Anonyme Benutzer anonym.user=Anonym Benutzer @@ -65,6 +66,7 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend confirmation=Best\u00E4tigung correct.solution=Korrekte L\u00F6sung correction=Korrigieren +create.12.resources=Neue QTI 1.2 Tests und Fragen zulassen debug.outcomes=Output Daten debug.responses=Antworten Daten digital.signature=Testquittung der Testergebnisse @@ -79,6 +81,7 @@ digital.signature.download=Testquittung digital.signature.download.link=Herunterladen digital.signature.test.option=Testquittung erstellen digital.signature.mail.test.option=Testquittung per Mail schicken +download.log=Logdatei drawing.brushsize=Pinselgr\u00F6sse drawing.opacity=Deckkraft error.as.directed=Alle 4 Antwortm\u00F6glichkeiten m\u00FCssen entweder mit Richtig oder Falsch beantwortet werden. @@ -89,7 +92,8 @@ error.choice=Sie m\u00FCssen ein von den folgenden Optionen w\u00E4hlen. error.digital.certificate.noX509=Es wurde kein X509 Zertifikat gefunden. error.digital.certificate.noPrivateKey=Es wurde kein "Private key" im Zertifikat gefunden. Sie ist erforderlich. error.digital.certificate.cannotread=Zertifikat konnte nicht gelesen werden. -error.double=Falsches Zahlenformat. Beispiele\: 15.0, 5.5, 10 +error.double=F\u00FCr Dezimalzahlen wird das Trennzeichen Punkt und nicht Komma verwendet. Beispiele\: 15.0, 5.5, 10 +error.integer=Falsches Zahlenformat. Beispiele\: 15, 5, 1 error.input.choice.max=W\u00E4hlen Sie die {0} zutreffenden Antworten. error.input.choice.min=W\u00E4hlen Sie mindestens {0} Antwort(en). error.input.choice.min.max=W\u00E4hlen Sie mindestens {0} und maximal {1} Antworten. @@ -108,6 +112,8 @@ form.metadata.title=Title graphic.gap.explanation=Platzieren Sie die unten stehende Grafik auf den Ort im obigen Bild, der die gesuchte Antwort am besten wieder gibt. head.assessment.details=$org.olat.ims.qti\:head.ass.details head.assessment.overview=$org.olat.ims.qti\:head.ass.details +hide.rubric=Beschreibung ausblenden +hide.rubric.short=Ausblenden interaction.order.drag.msg=Ziehen Sie die nicht verwendete Elemente von hier... interaction.order.drop.msg=Drop and order your selected items here... interaction.order.source=Quelle @@ -157,6 +163,7 @@ questions=Anzahl Fragen im Test question.progress.answered=Beantwortet question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore question.progress.score=$org.olat.modules.iq\:actualPoints +question.title=Frage {0} last.saved=Zuletzt gepeichert um: reset.data=Daten zur\u00FCcksetzen reset.test.data.acknowledge=Ich verstehe, dass die Daten werden endg\u00FCltig gel\u00F6scht. @@ -199,8 +206,9 @@ serialize.error=Unerwarte Fehler w\u00E4hrend Speicherung von Datei settings.profile=Standardeinstellungen settings.choose.descr=Sie k\u00F6nnen die Standardeinstellung f\u00FCr summative oder formative Tests \u00FCbernehmen und anpassen oder Sie setzen die Optionen selbst. settings.choose.profile=Konfiguration \u00FCbernehmen +show.rubric=Beschreibung anzeigen solution=L\u00F6sung -submit=Antwort senden +submit=Antwort speichern suspend.test=$org.olat.modules.iq\:suspendAssess tab.options=Optionen tab.reset.data=Daten zur\u00FCcksetzen @@ -230,6 +238,7 @@ upload.explanation=Datei auf lokalem Computer f\u00FCr \u00DCbertragung w\u00E4h validate.xml.signature=Testquittung validieren validate.xml.signature.file=XML Datei validate.xml.signature.ok=Testquittung und Datei konnte erfolgreich validiert werden. +warning.download.log=Es gibt leider kein Logdatei f\u00FCr diesen Test. warning.xml.signature.notok=Unterschrift und Datei konnte nicht validiert werden. warning.xml.signature.session.not.found=Die Resultaten konnte nicht gefunden werden. warning.reset.test.data.nobody=Es gibt kein Teilnehmer zu zur\u00FCcksetzen diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties index a8cc64a710d1010c3e95d4fb5d406ff3cc6c17c6..5d317cdc117ffa94803779e7a28567f034f25e49 100644 --- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties @@ -1,5 +1,6 @@ -#Wed Jan 11 13:33:25 CET 2017 +#Mon Sep 04 18:16:12 CEST 2017 actualPoints=$org.olat.modules.iq\:actualPoints +admin.12.title=QTI 1.2 settings admin.menu.title=QTI 2.1 admin.menu.title.alt=QTI 2.1 settings admin.title=QTI 2.1 settings @@ -10,6 +11,7 @@ answer.correct=$org.olat.ims.qti.statistics.ui\:answer.correct answer.false=$org.olat.ims.qti.statistics.ui\:answer.false answer.noanswer=$org.olat.ims.qti.statistics.ui\:answer.noanswer assessment.comment.legend=Please use the following text box if you need to provide any additional information, comments or feedback during this test\: +assessment.item.mark=Add personal marking as a reminder to review this question assessment.item.status.answered=Answered assessment.item.status.finished=Completed assessment.item.status.modelSolution=Model solution @@ -21,7 +23,6 @@ assessment.item.status.reviewInvalidAnswer=Review (Invalid Answer) assessment.item.status.reviewNot=Not Reviewable assessment.item.status.reviewNotAnswered=Review (Not Answered) assessment.item.status.reviewNotSeen=Review (Not Seen) -assessment.item.mark=Add personal marking as a reminder to review this question assessment.section.config=Section assessment.section.expert.config=Expert assessment.solution.hide=Hide solution @@ -65,6 +66,7 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend confirmation=Confirmation correct.solution=Correct solution correction=Grade +create.12.resources=Allow new QTI 1.2 tests and questions debug.outcomes=Output data debug.responses=Responses data digital.signature=Receipt of test results @@ -72,13 +74,14 @@ digital.signature.certificate=Certificate digital.signature.certificate.example=A certificate in .pfx format with "private key". digital.signature.certificate.hint=The certificate must be saved in .pfx format and contain the "private key". digital.signature.certificate.password=Certificate password -digital.signature.text=Receipt of test results -digital.signature.mail.subject=Test receipt -digital.signature.mail.body=As attachment in this email, you find the digitally signed receipt for the following online test:\n\nTest {0} ({1})\nDate: {6}\n\nRetain the test receipt carefully. It proves that you have completed this test at the time mentioned and contains information to confirm the authenticity of the saved informations. digital.signature.download=Test receipt digital.signature.download.link=Download -digital.signature.test.option=Generate a test receipt +digital.signature.mail.body=As attachment in this email, you find the digitally signed receipt for the following online test\:\n\nTest {0} ({1})\nDate\: {6}\n\nRetain the test receipt carefully. It proves that you have completed this test at the time mentioned and contains information to confirm the authenticity of the saved informations. +digital.signature.mail.subject=Test receipt digital.signature.mail.test.option=Send the test receipt per mail +digital.signature.test.option=Generate a test receipt +digital.signature.text=Receipt of test results +download.log=Log file drawing.brushsize=Brush size drawing.opacity=Opacity error.as.directed=Please complete this interaction as directed. @@ -86,10 +89,10 @@ error.as.directed.kprim=Please complete this interaction as directed. error.assessment.item=The file cannot be interpreted. It seems corrupted or with the wrong format. error.assessment.item.missing=The file of the question cannot be read. error.choice=You must select one of the following options -error.digital.certificate.noX509=The X509 certificate could not be found in the uploaded file. -error.digital.certificate.noPrivateKey=The "private key" could not be found. It is mandatory. error.digital.certificate.cannotread=The certificate could not be read. -error.double=Need to be a double +error.digital.certificate.noPrivateKey=The "private key" could not be found. It is mandatory. +error.digital.certificate.noX509=The X509 certificate could not be found in the uploaded file. +error.double=For decimal numbers point and not comma is used as separator. Examples\: 15.0, 5.5, 10 error.input.choice.max=You must select at the most {0} choices. error.input.choice.min=You must select at least {0} choice(s). error.input.choice.min.max=You must select at least {0} and at the most {1} choices. @@ -98,6 +101,7 @@ error.input.choice.minax.one=You must select one choice. error.input.extendedText.max=Write a text with at the most {0} words. error.input.extendedText.min=Write a text with at least {0} words. error.input.extendedText.min.max=Write a text with at least {0} and at the most {1} words. +error.integer=Need to be an integer. Example\: 15, 5, 1 error.mimetype=$org.olat.core.commons.modules.bc\:WrongMimeType error.required.format=Your input is not of the required format. error.textEntry.invalid=Your input is not valid @@ -108,6 +112,8 @@ form.metadata.title=Title graphic.gap.explanation=Place the graphic below on the position in the image above that best describes or depicts the correct answer. head.assessment.details=$org.olat.ims.qti\:head.ass.details head.assessment.overview=$org.olat.ims.qti\:head.ass.details +hide.rubric=Hide description +hide.rubric.short=Hide interaction.order.drag.msg=Drag unused items from here... interaction.order.drop.msg=Drop and order your selected items here... interaction.order.source=Source @@ -115,6 +121,7 @@ interaction.order.target=Target item.comment=Comment kprim.minus=False kprim.plus=True +last.saved=Last saved at\: math.extension=QtiWorks Math extension math.extension.text=Need Maxima installed on the server menu.reset.title=Reset data of test @@ -147,17 +154,17 @@ qti.form.showfeedbacks=Show feedbacks qti.form.summary=$org.olat.course.nodes.iq\:qti.form.summary qti.form.summary.help=$org.olat.course.nodes.iq\:qti.form.summary.help qti.form.summary.metadata=$org.olat.course.nodes.iq\:qti.form.summary.metadata -qti.form.summary.sections=$org.olat.course.nodes.iq\:qti.form.summary.sections qti.form.summary.questions=$org.olat.course.nodes.iq\:qti.form.summary.questions qti.form.summary.questions.metadata=$org.olat.course.nodes.iq\:qti.form.summary.questions.metadata qti.form.summary.responses=$org.olat.course.nodes.iq\:qti.form.summary.responses +qti.form.summary.sections=$org.olat.course.nodes.iq\:qti.form.summary.sections qti.form.summary.solutions=$org.olat.course.nodes.iq\:qti.form.summary.solutions question=Question -questions=Number of questions in test question.progress.answered=Answered question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore question.progress.score=$org.olat.modules.iq\:actualPoints -last.saved=Last saved at: +question.title=Question {0} +questions=Number of questions in test reset.data=Reset data reset.test.data.acknowledge=I understand that the data will be definitely deleted. reset.test.data.text=Do you really want to reset the assessment data of test? The results of <strong>{0} users</strong> will be definitively deleted. @@ -169,6 +176,13 @@ results.duration=Duration results.empty=No results found that could be displayed. results.end.time=End date results.entry.time=Start date +results.goto.overview=go back to overview +results.goto.section=go to section +results.of=of +results.of.points=points +results.of.questions=questions +results.points=points +results.questions.overview=Question overview results.score.yourscore=$org.olat.course.nodes.iq\:score.yourscore results.session.status=Status results.session.status.final=Answered @@ -176,43 +190,37 @@ results.session.status.initial=Not started results.session.status.pendingResponseProcessing=$\:results.session.status.pendingSubmission results.session.status.pendingSubmission=Seen but not answered results.summary.title=$org.olat.course.nodes\:personal.title -results.title.failed=Sorry, you have failed the test! -results.title.generic=This are your test results -results.title.passed=You have passed the test! +results.title.failed=Sorry, you have failed the test\! results.title.for=for {0} -results.of=of -results.of.questions=questions -results.points=points -results.of.points=points -results.questions.overview=Question overview -results.goto.section=go to section -results.goto.overview=go back to overview +results.title.generic=This are your test results +results.title.passed=You have passed the test\! retrievetest.confirm.text=$org.olat.ims.qti\:retrievetest.confirm.text retrievetest.confirm.text.plural=$org.olat.ims.qti.statistics.ui\:retrievetest.confirm.text.plural retrievetest.confirm.title=$org.olat.ims.qti.statistics.ui\:retrievetest.confirm.title retrievetest.nothing.todo=$org.olat.ims.qti.statistics.ui\:retrievetest.nothing.todo review.responses=Review your responses review.responses.desc=You may review your responses to some (or all) questions. These are listed below. -score.max=$org.olat.ims.qti\:score.max score.cut=$org.olat.ims.qti\:score.cut +score.max=$org.olat.ims.qti\:score.max serialize.error=An unexpected happens while saving the file. -settings.profile=Standard settings settings.choose.descr=You can chose a default setting for summative or formative tests and adapt it afterward or you set the options by yourself. settings.choose.profile=Apply configuration +settings.profile=Standard settings +show.rubric=Show description solution=Solution -submit=Submit response +submit=Submit answer suspend.test=$org.olat.modules.iq\:suspendAssess tab.options=Options tab.reset.data=Reset data table.header.action=Action -table.header.duration=Duration -table.header.lastModified=Last modified -table.header.results=Score table.header.corrected=Corrected +table.header.duration=Duration table.header.finalScore=Final score table.header.itemSessions=\# questions +table.header.lastModified=Last modified table.header.manualScore=Manual score table.header.responded=Responded +table.header.results=Score table.header.score=Score table.header.terminationTime=Finished at terminated.msg=The test is finished. @@ -220,16 +228,17 @@ test.complete=Test complete test.entry.page.text=This test consists of up to {0} parts. test.entry.page.title=Begin test test.part.complete=Test part complete +timelimit.1.minute=Less than als 1 minute left in this test. Please, send your answers. Not sent answers will not be saved. timelimit.10.minutes=Less than 10 minutes left in this test timelimit.5.minutes=Less than 5 minutes left in this test -timelimit.1.minute=Less than als 1 minute left in this test. Please, send your answers. Not sent answers will not be saved. -timelimit.running=Test time limit: {1} (ending at {2}) {0} timelimit.finished=Time is up +timelimit.running=Test time limit\: {1} (ending at {2}) {0} unsupported.custom.interaction=Unsupported custom interaction upload.explanation=Select a file from your computer to upload it validate.xml.signature=Validate test receipt validate.xml.signature.file=XML file validate.xml.signature.ok=Test receipt and results was successfully validated. +warning.download.log=There is not a log file for this test. +warning.reset.test.data.nobody=There isn't any participant which data can be reseted. warning.xml.signature.notok=Signature and results cannot be validate each other. warning.xml.signature.session.not.found=Tests results cannot be found. -warning.reset.test.data.nobody=There isn't any participant which data can be reseted. diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_fr.properties index 4adb18fd63231227c3f5f5d68863df1ed36d7476..59a54f9fafbcfc2a59182952546820c1802acdb7 100644 --- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_fr.properties @@ -1,5 +1,6 @@ -#Wed Jun 28 13:33:10 CEST 2017 +#Tue Aug 15 17:23:07 CEST 2017 actualPoints=$org.olat.modules.iq\:actualPoints +admin.12.title=Configuration QTI 1.2 admin.menu.title=QTI 2.1 admin.menu.title.alt=Configuration QTI 2.1 admin.title=Configuration QTI 2.1 @@ -65,6 +66,7 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend confirmation=Confirmation correct.solution=Solution correcte correction=Corriger +create.12.resources=Autoriser de nouveaux test et questions au format QTI 1.2 debug.outcomes=Donn\u00E9es et variables debug.responses=Donn\u00E9es de la r\u00E9ponse digital.signature=Signature digitale des r\u00E9sultats du test @@ -84,11 +86,12 @@ drawing.opacity=Opacit\u00E9 error.as.directed=Veuillez r\u00E9pondre \u00E0 la question comme indiqu\u00E9. error.as.directed.kprim=Veuillez r\u00E9pondre \u00E0 la question comme indiqu\u00E9. error.assessment.item=Le fichier n'a pas pu \u00EAtre lu. Il semble soit corrompu soit au mauvais format. +error.assessment.item.missing=Le fichier de la question n'a pas \u00EAtre d\u00E9chiffr\u00E9. error.choice=Vous devez choisir une des options suivantes. error.digital.certificate.cannotread=Le certificat n'a pas pu \u00EAtre lu. error.digital.certificate.noPrivateKey=La "cl\u00E9 priv\u00E9e" n'a pas \u00E9t\u00E9 trouv\u00E9e. Elle est obligatoire. error.digital.certificate.noX509=Le certificat X509 n'a pas pu \u00EAtre trouv\u00E9 dans le fichier t\u00E9l\u00E9charg\u00E9. -error.double=Format incorrect. Example\: 15.0, 5.5, 10 +error.double=Pour les nombres d\u00E9cimaux, le point est utilis\u00E9 comme s\u00E9parateur et non la virgule. Examples\: 15.0, 5.5, 10 error.input.choice.max=Vous pouvez s\u00E9lectionner {0} choix au plus. error.input.choice.min=Vous devez s\u00E9lectionner au moins {0} choix. error.input.choice.min.max=Vous devez s\u00E9lectionner au minimum {0} choix et au maximum {1}. @@ -107,6 +110,8 @@ form.metadata.title=Titre graphic.gap.explanation=Positionnez l'\u00E9l\u00E9ment graphique ci-dessous dans l'image au-dessus de mani\u00E8re \u00E0 repr\u00E9senter la r\u00E9ponse correcte. head.assessment.details=$org.olat.ims.qti\:head.ass.details head.assessment.overview=$org.olat.ims.qti\:head.ass.details +hide.rubric=Cacher la description +hide.rubric.short=Cacher interaction.order.drag.msg=Glissez les \u00E9l\u00E9ments inutilis\u00E9s depuis ici... interaction.order.drop.msg=D\u00E9posez et ordonnez les \u00E9l\u00E9ments s\u00E9lectionn\u00E9s ici... interaction.order.source=Source @@ -142,7 +147,7 @@ qti.form.results.onfinish=$org.olat.course.nodes.iq\:qti.form.results.onfinish qti.form.scoreprogress=$org.olat.course.nodes.iq\:qti.form.scoreprogress qti.form.setting.choose=Choisir un profile... qti.form.setting.formative=Formatif (exercice) -qti.form.setting.summative=Normatif (test r\u00E9el) +qti.form.setting.summative=Somatif (test r\u00E9el) qti.form.showfeedbacks=Montrer le retour d'informations qti.form.summary=$org.olat.course.nodes.iq\:qti.form.summary qti.form.summary.help=$org.olat.course.nodes.iq\:qti.form.summary.help @@ -156,6 +161,7 @@ question=Question question.progress.answered=R\u00E9pondu question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore question.progress.score=$org.olat.modules.iq\:actualPoints +question.title=Question {0} questions=Nombre de questions du test reset.data=R\u00E9initialiser les donn\u00E9es reset.test.data.acknowledge=Je comprends que les donn\u00E9es seront d\u00E9finitivement effac\u00E9es. @@ -198,6 +204,7 @@ serialize.error=Une erreur inattendue s'est produite lors de la sauvegarde du fi settings.choose.descr=Vous pouvez s\u00E9lectionner une s\u00E9rie de configurations pour les tests somatifs ou normatifs et les adapter ensuite ou de s\u00E9lectionner les diff\u00E9rentes options par vous-m\u00EAme. settings.choose.profile=Appliquer la configuration settings.profile=Options standards +show.rubric=Montrer la description solution=Solution submit=Envoyer la r\u00E9ponse suspend.test=$org.olat.modules.iq\:suspendAssess diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties index a9f273f2e0a217bd8ac8e0089007d3ad0ce00faa..1aa91162e4a351877410b3eedebfe162ffd5eeaf 100644 --- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,5 +1,6 @@ -#Wed Jun 21 23:35:02 CEST 2017 +#Tue Sep 05 19:11:10 CEST 2017 actualPoints=$org.olat.modules.iq\:actualPoints +admin.12.title=Configura\u00E7\u00F5es QTI 1.2 admin.menu.title=QTI 2.1 admin.menu.title.alt=Defini\u00E7\u00F5es do QTI 2.1 admin.title=Defini\u00E7\u00F5es do QTI 2.1 @@ -65,6 +66,7 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend confirmation=Confirma\u00E7\u00E3o correct.solution=Solu\u00E7\u00E3o correta correction=Grau +create.12.resources=Permitir novos testes QTI 1.2 e perguntas debug.outcomes=Dados de sa\u00EDda debug.responses=Dados de respostas digital.signature=Recibo dos resultados dos testes @@ -84,6 +86,7 @@ drawing.opacity=Opacidade error.as.directed=Por favor, preencha esta intera\u00E7\u00E3o como indicado. error.as.directed.kprim=Por favor complete esta intera\u00E7\u00E3o conforme a orienta\u00E7\u00E3o. error.assessment.item=O arquivo n\u00E3o pode ser interpretado. Parece corrompido ou com o formato errado. +error.assessment.item.missing=O arquivo da pergunta n\u00E3o pode ser lido. error.choice=Voc\u00EA deve selecionar uma das seguintes op\u00E7\u00F5es error.digital.certificate.cannotread=N\u00E3o foi poss\u00EDvel ler o certificado. error.digital.certificate.noPrivateKey=A "chave privada" n\u00E3o p\u00F4de ser encontrada. \u00C9 obrigat\u00F3rio. @@ -107,6 +110,8 @@ form.metadata.title=T\u00EDtulo graphic.gap.explanation=Coloque o gr\u00E1fico abaixo na posi\u00E7\u00E3o na imagem acima que melhor descreve ou representa a resposta correta. head.assessment.details=$org.olat.ims.qti\:head.ass.details head.assessment.overview=$org.olat.ims.qti\:head.ass.details +hide.rubric=Esconder descri\u00E7\u00E3o +hide.rubric.short=Esconder interaction.order.drag.msg=Arraste itens n\u00E3o utilizados daqui ... interaction.order.drop.msg=Solte e ordene os itens selecionados aqui ... interaction.order.source=Fonte @@ -156,6 +161,7 @@ question=Quest\u00E3o question.progress.answered=Respondido question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore question.progress.score=$org.olat.modules.iq\:actualPoints +question.title=Pergunta {0} questions=N\u00FAmero de perguntas no teste reset.data=Resetar dados reset.test.data.acknowledge=Eu entendo que os dados ser\u00E3o exclu\u00EDdos definitivamente. @@ -198,6 +204,7 @@ serialize.error=Ocorre algo inesperado ao salvar o arquivo. settings.choose.descr=Voc\u00EA pode escolher uma configura\u00E7\u00E3o padr\u00E3o para testes sum\u00E1rios ou formativos e adapt\u00E1-lo posteriormente ou definir as op\u00E7\u00F5es por si mesmo. settings.choose.profile=Aplicar configura\u00E7\u00E3o settings.profile=Configura\u00E7\u00F5es padr\u00E3o +show.rubric=Mostrar descri\u00E7\u00E3o solution=Solu\u00E7\u00E3o submit=Enviar resposta suspend.test=$org.olat.modules.iq\:suspendAssess diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/IdentitiesAssessmentTestCorrectionController.java b/src/main/java/org/olat/ims/qti21/ui/assessment/IdentitiesAssessmentTestCorrectionController.java index 4e50236254391b429a1f3e16d95b1c061bdd58ad..a20fd3f78ba0388a839ab09bd7e4dcca31d0c4c7 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/IdentitiesAssessmentTestCorrectionController.java +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/IdentitiesAssessmentTestCorrectionController.java @@ -21,6 +21,7 @@ package org.olat.ims.qti21.ui.assessment; import java.io.File; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -39,6 +40,7 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.id.Identity; +import org.olat.core.util.StringHelper; import org.olat.course.archiver.ScoreAccountingHelper; import org.olat.course.nodes.IQTESTCourseNode; import org.olat.course.run.environment.CourseEnvironment; @@ -73,7 +75,7 @@ import uk.ac.ed.ph.jqtiplus.types.Identifier; public class IdentitiesAssessmentTestCorrectionController extends BasicController { private final VelocityContainer mainVC; - private final Link previousItemLink, currentItemLink, nextItemLink, overviewLink; + private NavigationController navigationCtrl; private IdentitiesAssessmentTestOverviewController overviewCtrl; private IdentitiesAssessmentItemCorrectionController itemCorrectionCtrl; @@ -119,19 +121,17 @@ public class IdentitiesAssessmentTestCorrectionController extends BasicControlle assessmentEntries = getAssessmentEntries(lastSessions.keySet()); mainVC = createVelocityContainer("corrections"); - - previousItemLink = LinkFactory.createButton("previous.item", mainVC, this); - previousItemLink.setIconLeftCSS("o_icon o_icon_previous"); - currentItemLink = LinkFactory.createButton("current.item", mainVC, this); - nextItemLink = LinkFactory.createButton("next.item", mainVC, this); - nextItemLink.setIconRightCSS("o_icon o_icon_next"); - overviewLink = LinkFactory.createButton("overview.tests", mainVC, this); - + itemRefs = calculateAssessmentItemToCorrect(); testCorrections = collectAssessedIdentityForItem(itemRefs); + + navigationCtrl = new NavigationController(ureq, getWindowControl()); + listenTo(navigationCtrl); + mainVC.put("navigation", navigationCtrl.getInitialComponent()); + if(itemRefs.size() > 0) { currentItemRef = itemRefs.get(0); - updatePreviousNext(); + navigationCtrl.updatePreviousNext(); updateIdentitiesAssessmentItem(ureq); } putInitialPanel(mainVC); @@ -152,33 +152,6 @@ public class IdentitiesAssessmentTestCorrectionController extends BasicControlle return resolvedAssessmentTest.getAssessmentItemRefs(); } - private void updatePreviousNext() { - int index = itemRefs.indexOf(currentItemRef); - - if(index > 0) { - AssessmentItemRef itemRef = itemRefs.get(index - 1); - String itemTitle = AssessmentTestHelper.getAssessmentItemTitle(itemRef, resolvedAssessmentTest); - previousItemLink.setCustomDisplayText(itemTitle); - previousItemLink.setEnabled(true); - } else { - previousItemLink.setCustomDisplayText(translate("previous.item")); - previousItemLink.setEnabled(false); - } - - String currentItemTitle = AssessmentTestHelper.getAssessmentItemTitle(currentItemRef, resolvedAssessmentTest); - currentItemLink.setCustomDisplayText(currentItemTitle); - - if(index + 1 < itemRefs.size()) { - AssessmentItemRef itemRef = itemRefs.get(index + 1); - String itemTitle = AssessmentTestHelper.getAssessmentItemTitle(itemRef, resolvedAssessmentTest); - nextItemLink.setCustomDisplayText(itemTitle); - nextItemLink.setEnabled(true); - } else { - nextItemLink.setCustomDisplayText(translate("next.item")); - nextItemLink.setEnabled(false); - } - } - private void updateIdentitiesAssessmentItem(UserRequest ureq) { removeAsListenerAndDispose(itemCorrectionCtrl); @@ -308,22 +281,20 @@ public class IdentitiesAssessmentTestCorrectionController extends BasicControlle @Override protected void event(UserRequest ureq, Component source, Event event) { - if(previousItemLink == source) { - doPreviousAssessmentItem(ureq); - } else if(nextItemLink == source) { - doNextAssessmentItem(ureq); - } else if(currentItemLink == source) { - updateIdentitiesAssessmentItem(ureq); - } else if(overviewLink == source) { - mainVC.put("itemCorrection", overviewCtrl.getInitialComponent()); - } + // } private void doPreviousAssessmentItem(UserRequest ureq) { - int previousIndex = itemRefs.indexOf(currentItemRef) - 1; + int previousIndex = -1; + if(currentItemRef == null) { + previousIndex = itemRefs.size() - 1; + } else { + previousIndex = itemRefs.indexOf(currentItemRef) - 1; + } + if(previousIndex >= 0 && itemRefs.size() > previousIndex) { currentItemRef = itemRefs.get(previousIndex); - updatePreviousNext(); + navigationCtrl.updatePreviousNext(); updateIdentitiesAssessmentItem(ureq); } else if(itemRefs.size() > 0) { currentItemRef = itemRefs.get(0); @@ -334,10 +305,141 @@ public class IdentitiesAssessmentTestCorrectionController extends BasicControlle int nextIndex = itemRefs.indexOf(currentItemRef) + 1; if(nextIndex >= 0 && itemRefs.size() > nextIndex) { currentItemRef = itemRefs.get(nextIndex); - updatePreviousNext(); + navigationCtrl.updatePreviousNext(); updateIdentitiesAssessmentItem(ureq); } else if(itemRefs.size() > 0) { currentItemRef = itemRefs.get(itemRefs.size() - 1); } } + + private void doSelectByIndex(UserRequest ureq, int index) { + currentItemRef = itemRefs.get(index); + navigationCtrl.updatePreviousNext(); + updateIdentitiesAssessmentItem(ureq); + mainVC.setDirty(true); + } + + private void doOverview() { + currentItemRef = null; + mainVC.put("itemCorrection", overviewCtrl.getInitialComponent()); + navigationCtrl.overview(); + } + + private class NavigationController extends BasicController { + + private final VelocityContainer navigationVC; + private Link previousItemLink, nextItemLink, overviewLink; + + public NavigationController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + navigationVC = createVelocityContainer("corrections_navigation"); + + List<SelectPair> itemRefKeys = new ArrayList<>(itemRefs.size()); + for(int i=0; i<itemRefs.size(); i++) { + String itemTitle = AssessmentTestHelper.getAssessmentItemTitle(itemRefs.get(i), resolvedAssessmentTest); + itemRefKeys.add(new SelectPair(Integer.toString(i), itemTitle)); + } + itemRefKeys.add(new SelectPair("overview", translate("overview.tests"))); + navigationVC.contextPut("itemRefKeys", itemRefKeys); + + previousItemLink = LinkFactory.createButton("previous.item", navigationVC, this); + previousItemLink.setIconLeftCSS("o_icon o_icon_previous"); + nextItemLink = LinkFactory.createButton("next.item", navigationVC, this); + nextItemLink.setIconRightCSS("o_icon o_icon_next"); + overviewLink = LinkFactory.createButton("overview.tests", navigationVC, this); + + putInitialPanel(navigationVC); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if(previousItemLink == source) { + doPreviousAssessmentItem(ureq); + } else if(nextItemLink == source) { + doNextAssessmentItem(ureq); + } else if(overviewLink == source) { + doOverview(); + } else if(navigationVC == source) { + String cmd = ureq.getParameter("cid"); + if("sel".equals(cmd)) { + String selectedKey = ureq.getParameter("item"); + if("overview".equals(selectedKey)) { + doOverview(); + } else if(StringHelper.isLong(selectedKey)) { + try { + doSelectByIndex(ureq, Integer.parseInt(selectedKey)); + } catch (NumberFormatException e) { + logError("Cannot parse select index: " + selectedKey, e); + } + } + } + } + } + + protected void overview() { + navigationVC.contextPut("selectedValue", "overview"); + + if(itemRefs.size() > 0) { + AssessmentItemRef itemRef = itemRefs.get(itemRefs.size() - 1); + String itemTitle = AssessmentTestHelper.getAssessmentItemTitle(itemRef, resolvedAssessmentTest); + previousItemLink.setCustomDisplayText(itemTitle); + previousItemLink.setEnabled(true); + } + + nextItemLink.setCustomDisplayText(translate("next.item")); + nextItemLink.setEnabled(false); + } + + protected void updatePreviousNext() { + int index = itemRefs.indexOf(currentItemRef); + + if(index > 0) { + AssessmentItemRef itemRef = itemRefs.get(index - 1); + String itemTitle = AssessmentTestHelper.getAssessmentItemTitle(itemRef, resolvedAssessmentTest); + previousItemLink.setCustomDisplayText(itemTitle); + previousItemLink.setEnabled(true); + } else { + previousItemLink.setCustomDisplayText(translate("previous.item")); + previousItemLink.setEnabled(false); + } + + navigationVC.contextPut("selectedValue", index); + navigationVC.setDirty(true); + + if(index + 1 < itemRefs.size()) { + AssessmentItemRef itemRef = itemRefs.get(index + 1); + String itemTitle = AssessmentTestHelper.getAssessmentItemTitle(itemRef, resolvedAssessmentTest); + nextItemLink.setCustomDisplayText(itemTitle); + nextItemLink.setEnabled(true); + } else { + nextItemLink.setCustomDisplayText(translate("next.item")); + nextItemLink.setEnabled(false); + } + } + } + + public class SelectPair { + + private final String text; + private final String value; + + public SelectPair(String value, String text) { + this.text = text; + this.value = value; + } + + public String getText() { + return text; + } + + public String getValue() { + return value; + } + } } \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/QTI21CorrectionToolController.java b/src/main/java/org/olat/ims/qti21/ui/assessment/QTI21CorrectionToolController.java index d288a34f8f7ac2b13ca1c1d3a03b994a96e24934..4f9369b4f2568534f88db56a394cba0a7fd2204d 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/QTI21CorrectionToolController.java +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/QTI21CorrectionToolController.java @@ -40,6 +40,7 @@ import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.ims.qti21.AssessmentTestSession; import org.olat.modules.assessment.AssessmentToolOptions; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.ui.event.CompleteAssessmentTestSessionEvent; /** @@ -138,7 +139,7 @@ public class QTI21CorrectionToolController extends BasicController { Float score = finalScore == null ? null : finalScore.floatValue(); ScoreEvaluation manualScoreEval = new ScoreEvaluation(score, scoreEval.getPassed(), scoreEval.getAssessmentStatus(), scoreEval.getUserVisible(), scoreEval.getFullyAssessed(), testSession.getKey()); - courseNode.updateUserScoreEvaluation(manualScoreEval, assessedUserCourseEnv, getIdentity(), false); + courseNode.updateUserScoreEvaluation(manualScoreEval, assessedUserCourseEnv, getIdentity(), false, Role.coach); } } } diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/TerminatedStaticCandidateSessionContext.java b/src/main/java/org/olat/ims/qti21/ui/assessment/TerminatedStaticCandidateSessionContext.java index e228d5db6671d1aa54a4190f1a17ae5804c6a852..9a9e14d99f37d91a488244d8e400619eea2cf088 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/TerminatedStaticCandidateSessionContext.java +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/TerminatedStaticCandidateSessionContext.java @@ -25,6 +25,9 @@ import org.olat.ims.qti21.AssessmentTestSession; import org.olat.ims.qti21.model.audit.CandidateEvent; import org.olat.ims.qti21.ui.CandidateSessionContext; +import uk.ac.ed.ph.jqtiplus.state.TestPlanNode; +import uk.ac.ed.ph.jqtiplus.types.Identifier; + /** * * Initial date: 16.08.2016<br> @@ -63,4 +66,14 @@ public class TerminatedStaticCandidateSessionContext implements CandidateSession public boolean isMarked(String itemKey) { return false; } + + @Override + public boolean isRubricHidden(Identifier sectionKey) { + return false; + } + + @Override + public int getNumber(TestPlanNode node) { + return 0; + } } diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_content/corrections.html b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/corrections.html index c8925dc301af159bf99cd2beb63b4f0742d8e80e..9152d5dc70d4fb818a13ed1921b3d7b2af17aa55 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/_content/corrections.html +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/corrections.html @@ -1,9 +1,2 @@ -<div class="o_button_group clearfix"> - <div class="btn-group"> - $r.render("previous.item") - $r.render("current.item") - $r.render("next.item") - </div> - $r.render("overview.tests") -</div> +$r.render("navigation") $r.render("itemCorrection") \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_content/corrections_navigation.html b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/corrections_navigation.html new file mode 100644 index 0000000000000000000000000000000000000000..a7f5f645c64dac23874d0ac872787ffbe6027c65 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/corrections_navigation.html @@ -0,0 +1,13 @@ +<div class="o_sel_correction_navigation clearfix"> + $r.render("previous.item") + <div id="o_cocurrent_item_SELBOX"> + <select class="form-control" onchange="var current = jQuery(this).val(); jQuery(this).val('$selectedValue'); $r.openJavaScriptCommand("sel", true, false), 'item', current);"> + #foreach($itemRef in $itemRefKeys) + <option value="$itemRef.value" #if($selectedValue == $itemRef.value) selected #end>$itemRef.text</option> + #end + </select> + </div> + $r.render("next.item") + $r.render("overview.tests") +</div> + diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java index cb818c9beece90163883d49abaa2501b898ae748..babfb5de6d43a476fd8d65b0cfbfe869d5146070 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java @@ -192,10 +192,14 @@ public abstract class AssessmentObjectComponent extends AbstractComponent implem jsa.addRequiredStaticJsFile("assessment/rendering/javascript/UpConversionAjaxController.js"); jsa.addRequiredStaticJsFile("js/jquery/maphilight/jquery.maphilight.js"); + // drawing needs slider, slider need it too + // order needs sortable + // drag and drop used a lot... jsa.addRequiredStaticJsFile("js/jquery/ui/jquery-ui-1.11.4.custom.qti.min.js"); jsa.addRequiredStaticJsFile("js/jquery/openolat/jquery.paint.js"); - + + jsa.addRequiredStaticJsFile("js/jquery/qti/jquery.choice.js"); jsa.addRequiredStaticJsFile("js/jquery/qti/jquery.associate.js"); jsa.addRequiredStaticJsFile("js/jquery/qti/jquery.graphicAssociate.js"); jsa.addRequiredStaticJsFile("js/jquery/qti/jquery.graphicGap.js"); @@ -208,6 +212,7 @@ public abstract class AssessmentObjectComponent extends AbstractComponent implem jsa.addRequiredStaticJsFile("js/jquery/qti/jquery.match_dnd.js"); jsa.addRequiredStaticJsFile("js/jquery/qti/jquery.gapMatch.js"); jsa.addRequiredStaticJsFile("js/jquery/qti/jquery.hotspot.js"); + jsa.addRequiredStaticJsFile("js/jquery/qti/jquery.hotspot.responsive.js"); } diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java index 22cce086e3a2de7d6c8f3046066e2ef88dbf2763..e5b8d647bd2b05dba5eb0775a77db4f42bd98bbe 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java @@ -90,6 +90,7 @@ import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.QTI21Module; import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.XmlUtilities; +import org.olat.ims.qti21.model.xml.AssessmentItemFactory; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; @@ -334,7 +335,9 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent Value feedbackBasic = itemSessionState.getOutcomeValue(QTI21Constants.FEEDBACKBASIC_IDENTIFIER); if(feedbackBasic != null && feedbackBasic.hasBaseType(BaseType.IDENTIFIER) && feedbackBasic instanceof IdentifierValue) { IdentifierValue identifierValue = (IdentifierValue)feedbackBasic; - if(QTI21Constants.CORRECT_IDENTIFIER_VALUE.equals(identifierValue)) { + if(AssessmentItemFactory.matchAdditionalFeedback(resolvedAssessmentItem.getRootNodeLookup().extractAssumingSuccessful(), modalFeedback)) { + sb.append(" o_additional_modal_feedback"); + } else if(QTI21Constants.CORRECT_IDENTIFIER_VALUE.equals(identifierValue)) { sb.append(" o_correct_modal_feedback"); } else if(QTI21Constants.INCORRECT_IDENTIFIER_VALUE.equals(identifierValue)) { sb.append(" o_incorrect_modal_feedback"); @@ -1023,6 +1026,8 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent interactionName += "_kprim"; } else if(hasClass(matchInteraction, QTI21Constants.CSS_MATCH_DRAG_AND_DROP)) { interactionName += "_dnd"; + } else if(hasClass(matchInteraction, QTI21Constants.CSS_MATCH_KPRIM)) { + interactionName += "_kprim"; } break; } diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java index 05fdaed97ee277fc36b9a18c4521076c8ac39f93..8f4a4aa8ee8def609f01a2b3ddfd069c299e4be8 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java @@ -55,6 +55,7 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.GapMatchInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.GraphicAssociateInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.GraphicGapMatchInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.GraphicOrderInteraction; +import uk.ac.ed.ph.jqtiplus.node.item.interaction.HottextInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.InlineChoiceInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.MatchInteraction; @@ -240,6 +241,14 @@ public class AssessmentObjectVelocityRenderDecorator extends VelocityRenderDecor return false; } return sc; + } else if(interaction instanceof HottextInteraction) { + HottextInteraction hottextInteraction = (HottextInteraction)interaction; + boolean sc = hottextInteraction.getMaxChoices() == 1; + ResponseDeclaration responseDeclaration = assessmentItem.getResponseDeclaration(hottextInteraction.getResponseIdentifier()); + if(responseDeclaration != null && responseDeclaration.hasCardinality(Cardinality.MULTIPLE)) { + return false; + } + return sc; } return false; } diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java index 94438a7f5f99a8791f2093831b5acf3250779b30..ca80af498c025af9e4b73f2208e09686b1b4bca7 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java @@ -297,7 +297,37 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe } if(writeRubrics) { - sb.append("<div class='o_info o_assessmentsection_rubrics'>"); + boolean show = true; + for(int i=sectionParentLine.size(); i-->0; ) { + AssessmentSection selectedSection = sectionParentLine.get(i); + if(component.getCandidateSessionContext().isRubricHidden(selectedSection.getIdentifier())) { + show = false; + } + } + + String key = sectionParentLine.get(0).getIdentifier().toString(); + Form form = component.getQtiItem().getRootForm(); + String dispatchId = component.getQtiItem().getFormDispatchId(); + + sb.append("<a href='javascript:;' onclick=\"") + .append(FormJSHelper.getXHRNFFnCallFor(form, dispatchId, 1, + new NameValuePair("cid", Event.rubric.name()), new NameValuePair("section", key))) + .append("; return false;\" class='o_toogle_rubrics translated'><i class='o_icon o_icon-fw "); + if(show) { + sb.append("o_icon_close_togglebox'> </i> <span>").append(translator.translate("hide.rubric")); + } else { + sb.append("o_icon_open_togglebox'> </i> <span>").append(translator.translate("show.rubric")); + } + sb.append("</span></a>"); + + sb.append("<div class='o_info o_assessmentsection_rubrics clearfix"); + if(show) { + sb.append(" o_show"); + } else { + sb.append(" o_hide"); + } + sb.append("'>"); + //write the titles first if(writeTitles) { sb.append("<h4>"); @@ -316,7 +346,6 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe sb.append("</h4>"); } - for(int i=sectionParentLine.size(); i-->0; ) { AssessmentSection selectedSection = sectionParentLine.get(i); for(RubricBlock rubricBlock:selectedSection.getRubricBlocks()) { @@ -325,7 +354,34 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe sb.append("</div>"); } } - sb.append("</div>"); + + sb.append("<a href='javascript:;' onclick=\"") + .append(FormJSHelper.getXHRNFFnCallFor(form, dispatchId, 1, + new NameValuePair("cid", Event.rubric.name()), new NameValuePair("section", key))) + .append("; return false;\" class='o_toogle_rubrics o_hide'><span>") + .append(translator.translate("hide.rubric.short")) + .append("</span></a>"); + // script to show/hide the rubrics with the translated linked + sb.append("<script type=\"text/javascript\">\n") + .append("/* <![CDATA[ */ \n") + .append("jQuery(function() {\n") + .append(" jQuery('.o_toogle_rubrics').on('click', function() {\n") + .append(" jQuery('.o_assessmentsection_rubrics').each(function(index, el) {\n") + .append(" var current = jQuery(el).attr('class');\n") + .append(" if(current.indexOf('o_hide') >= 0) {\n") + .append(" jQuery(el).removeClass('o_hide').addClass('o_show');\n") + .append(" jQuery('a.o_toogle_rubrics.translated i').removeClass('o_icon_open_togglebox').addClass('o_icon_close_togglebox');\n") + .append(" jQuery('a.o_toogle_rubrics.translated span').html('").append(translator.translate("hide.rubric")).append("');") + .append(" } else {\n") + .append(" jQuery(el).removeClass('o_show').addClass('o_hide');\n") + .append(" jQuery('a.o_toogle_rubrics.translated i').removeClass('o_icon_close_togglebox').addClass('o_icon_open_togglebox');\n") + .append(" jQuery('a.o_toogle_rubrics.translated span').html('").append(translator.translate("show.rubric")).append("');") + .append(" }\n") + .append(" });") + .append(" });") + .append("});\n /* ]]> */") + .append("</script>") + .append("</div>"); } } @@ -348,7 +404,15 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe //title + status sb.append("<h4 class='itemTitle'>"); renderItemStatus(sb, itemSessionState, options, translator); - sb.append(StringHelper.escapeHtml(itemNode.getSectionPartTitle()), component.isShowTitles()) + + String title; + if(component.isShowTitles()) { + title = StringHelper.escapeHtml(itemNode.getSectionPartTitle()); + } else { + int num = component.getCandidateSessionContext().getNumber(itemNode); + title = translator.translate("question.title", new String[] { Integer.toString(num) }); + } + sb.append(title) .append("</h4>") .append("<div id='itemBody' class='clearfix'>"); diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestFormItem.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestFormItem.java index 73619c0acbc64da7dc477197a1321413bb0a8ed0..d14bdb825938ea1c2304cb9071a0724342bc4205 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestFormItem.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestFormItem.java @@ -27,6 +27,7 @@ import static org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event.itemSoluti import static org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event.nextItem; import static org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event.reviewItem; import static org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event.reviewTestPart; +import static org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event.rubric; import static org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event.selectItem; import static org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event.testPartNavigation; import static org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event.timesUp; @@ -187,6 +188,11 @@ public class AssessmentTestFormItem extends AssessmentObjectFormItem { event = new QTIWorksAssessmentTestEvent(tmpResponse, this); break; } + case rubric: { + String selectedSection = ureq.getParameter("section"); + event = new QTIWorksAssessmentTestEvent(rubric, selectedSection, this); + break; + } default: { event = null; } diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponent.java index 12399985ac7d1bcbfc22f22d000a1aefa98a2e78..40e636dc29be8af9ddd8b843ce65234ef5c35896 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponent.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponent.java @@ -45,6 +45,7 @@ public class AssessmentTreeComponent extends AssessmentObjectComponent { private TestSessionController testSessionController; private ResolvedAssessmentTest resolvedAssessmentTest; + private boolean showTitles; private final AssessmentTreeFormItem qtiItem; public AssessmentTreeComponent(String name, AssessmentTreeFormItem qtiItem) { @@ -52,6 +53,14 @@ public class AssessmentTreeComponent extends AssessmentObjectComponent { this.qtiItem = qtiItem; } + public boolean isShowTitles() { + return showTitles; + } + + public void setShowTitles(boolean showTitles) { + this.showTitles = showTitles; + } + @Override public String relativePathTo(ResolvedAssessmentItem resolvedAssessmentItem) { return ""; diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponentRenderer.java index be216e669d9906d5d8f67d5283ddd874b42885f1..3c9f3930c53cd21eee9cd4e1834afc24e9d9ca3f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponentRenderer.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponentRenderer.java @@ -160,7 +160,7 @@ public class AssessmentTreeComponentRenderer extends AssessmentObjectComponentRe renderAssessmentItemMark(sb, component, itemNode, translator); renderAssessmentItemAttempts(sb, component, itemNode, translator); renderItemStatus(sb, component, itemNode, translator, options); - renderAssessmentItemLink(sb, component, itemNode); + renderAssessmentItemLink(sb, component, itemNode, translator); sb.append("</li>"); } @@ -171,7 +171,7 @@ public class AssessmentTreeComponentRenderer extends AssessmentObjectComponentRe * @param itemNode * @return The event used or null */ - private Event renderAssessmentItemLink(StringOutput sb, AssessmentTreeComponent component, TestPlanNode itemNode) { + private Event renderAssessmentItemLink(StringOutput sb, AssessmentTreeComponent component, TestPlanNode itemNode, Translator translator) { String key = itemNode.getKey().toString(); Form form = component.getQtiItem().getRootForm(); String dispatchId = component.getQtiItem().getFormDispatchId(); @@ -205,7 +205,14 @@ public class AssessmentTreeComponentRenderer extends AssessmentObjectComponentRe new NameValuePair("cid", event.name()), new NameValuePair("item", key))) .append(";\" class='o_sel_assessmentitem'>"); } - sb.append("<span class='questionTitle'>").append(StringHelper.escapeHtml(itemNode.getSectionPartTitle())).append("</span>"); + String title; + if(component.isShowTitles()) { + title = StringHelper.escapeHtml(itemNode.getSectionPartTitle()); + } else { + int num = component.getCandidateSessionContext().getNumber(itemNode); + title = translator.translate("question.title", new String[] { Integer.toString(num) }); + } + sb.append("<span class='questionTitle'>").append(title).append("</span>"); if(event == null) { sb.append("</span>"); @@ -262,9 +269,6 @@ public class AssessmentTreeComponentRenderer extends AssessmentObjectComponentRe sb.append("'>").append(numOfAttempts); } sb.append("</span>"); - - - } @Override diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeFormItem.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeFormItem.java index 37405e3365d3cb1bf0a7a56e0bc5908e689e0a33..d093c27c7e7268c2dad38a3976b297800dd57ff5 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeFormItem.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeFormItem.java @@ -52,6 +52,14 @@ public class AssessmentTreeFormItem extends AssessmentObjectFormItem { public AssessmentTreeComponent getComponent() { return component; } + + public boolean getShowTitles() { + return component.isShowTitles(); + } + + public void setShowTitles(boolean showTitles) { + component.setShowTitles(showTitles); + } public ResolvedAssessmentTest getResolvedAssessmentTest() { return component.getResolvedAssessmentTest(); diff --git a/src/main/java/org/olat/ims/qti21/ui/components/FlowComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/FlowComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..3229682ed8386b7faa33b8371d42a1775c17950b --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/components/FlowComponent.java @@ -0,0 +1,120 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.ui.components; + +import java.io.File; +import java.net.URI; +import java.nio.file.Path; +import java.util.List; + +import uk.ac.ed.ph.jqtiplus.node.content.basic.FlowStatic; +import uk.ac.ed.ph.jqtiplus.node.content.basic.InlineStatic; +import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction; +import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; +import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentTest; +import uk.ac.ed.ph.jqtiplus.state.ItemSessionState; + +/** + * + * Initial date: 10 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class FlowComponent extends AssessmentObjectComponent { + + private final static FlowComponentRenderer RENDERER = new FlowComponentRenderer(); + + private ResolvedAssessmentTest resolvedAssessmentTest; + private final File assessmentItemFile; + + private final FlowFormItem qtiItem; + private List<FlowStatic> flowStatics; + private List<InlineStatic> inlineStatics; + + public FlowComponent(String name, File assessmentItemFile, FlowFormItem qtiItem) { + super(name); + this.qtiItem = qtiItem; + this.assessmentItemFile = assessmentItemFile; + setDomReplacementWrapperRequired(false); + } + + public List<FlowStatic> getFlowStatics() { + return flowStatics; + } + + public void setFlowStatics(List<FlowStatic> flowStatics) { + this.flowStatics = flowStatics; + } + + public List<InlineStatic> getInlineStatics() { + return inlineStatics; + } + + public void setInlineStatics(List<InlineStatic> inlineStatics) { + this.inlineStatics = inlineStatics; + } + + public ResolvedAssessmentTest getResolvedAssessmentTest() { + return resolvedAssessmentTest; + } + + public void setResolvedAssessmentTest(ResolvedAssessmentTest resolvedAssessmentTest) { + this.resolvedAssessmentTest = resolvedAssessmentTest; + } + + @Override + public FlowFormItem getQtiItem() { + return qtiItem; + } + + @Override + public String getResponseUniqueIdentifier(ItemSessionState itemSessionState, Interaction interaction) { + return null; + } + + @Override + public Interaction getInteractionOfResponseUniqueIdentifier(String responseUniqueId) { + return null; + } + + @Override + public String relativePathTo(ResolvedAssessmentItem rAssessmentItem) { + + String relativePathString = ""; + if(resolvedAssessmentTest != null) { + URI testUri = resolvedAssessmentTest.getTestLookup().getSystemId(); + File testFile = new File(testUri); + Path relativePath = testFile.toPath().getParent().relativize(assessmentItemFile.toPath().getParent()); + relativePathString = relativePath.toString(); + } + + if(relativePathString.isEmpty()) { + return relativePathString; + } else if(relativePathString.endsWith("/")) { + return relativePathString; + } + return relativePathString.concat("/"); + } + + @Override + public FlowComponentRenderer getHTMLRendererSingleton() { + return RENDERER; + } +} diff --git a/src/main/java/org/olat/ims/qti21/ui/components/FlowComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/FlowComponentRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..fdde7a396a21c498e145f834062845fe0d337a0c --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/components/FlowComponentRenderer.java @@ -0,0 +1,75 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.ui.components; + +import org.olat.core.gui.components.Component; +import org.olat.core.gui.render.RenderResult; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; + +import uk.ac.ed.ph.jqtiplus.node.content.variable.PrintedVariable; +import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; +import uk.ac.ed.ph.jqtiplus.state.ItemSessionState; + +/** + * + * Initial date: 10 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class FlowComponentRenderer extends AssessmentObjectComponentRenderer { + + private static final OLog log = Tracing.createLoggerFor(FlowComponentRenderer.class); + + @Override + public void render(Renderer renderer, StringOutput target, Component source, URLBuilder ubu, Translator translator, + RenderResult renderResult, String[] args) { + FlowComponent avc = (FlowComponent)source; + AssessmentRenderer aRenderer = new AssessmentRenderer(renderer); + if(avc.getFlowStatics() != null) { + try { + avc.getFlowStatics().forEach((flow) + -> avc.getHTMLRendererSingleton().renderFlow(aRenderer, target, avc, (ResolvedAssessmentItem)null, (ItemSessionState)null, flow, ubu, translator)); + } catch (Exception e) { + log.error("", e); + } + } + if(avc.getInlineStatics() != null) { + try { + avc.getInlineStatics().forEach((inline) + -> avc.getHTMLRendererSingleton().renderInline(aRenderer, target, avc, (ResolvedAssessmentItem)null, (ItemSessionState)null, inline, ubu, translator)); + } catch (Exception e) { + log.error("", e); + } + } + } + + @Override + protected void renderPrintedVariable(AssessmentRenderer renderer, StringOutput sb, + AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, + ItemSessionState itemSessionState, PrintedVariable printedVar) { + //do nothing + } + +} diff --git a/src/main/java/org/olat/ims/qti21/ui/components/FlowFormItem.java b/src/main/java/org/olat/ims/qti21/ui/components/FlowFormItem.java new file mode 100644 index 0000000000000000000000000000000000000000..b22dae9ed6ec3aa60e65ac579cfddf9f3d469d9f --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/components/FlowFormItem.java @@ -0,0 +1,87 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.ui.components; + +import java.io.File; +import java.util.List; + +import org.olat.core.gui.UserRequest; + +import uk.ac.ed.ph.jqtiplus.node.content.basic.FlowStatic; +import uk.ac.ed.ph.jqtiplus.node.content.basic.InlineStatic; + +/** + * + * Initial date: 10 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class FlowFormItem extends AssessmentObjectFormItem { + + private final FlowComponent component; + + public FlowFormItem(String name, File assessmentItemFile) { + super(name, null); + component = new FlowComponent(name, assessmentItemFile, this); + } + + public List<FlowStatic> getFlowStatics() { + return component.getFlowStatics(); + } + + public void setFlowStatics(List<FlowStatic> flowStatics) { + component.setFlowStatics(flowStatics); + } + + public List<InlineStatic> getInlineStatics() { + return component.getInlineStatics(); + } + + public void setInlineStatics(List<InlineStatic> inlineStatics) { + component.setInlineStatics(inlineStatics); + } + + @Override + public FlowComponent getComponent() { + return component; + } + + @Override + protected FlowComponent getFormItemComponent() { + return component; + } + + @Override + protected void rootFormAvailable() { + // + } + + @Override + public void evalFormRequest(UserRequest ureq) { + // + } + + @Override + public void reset() { + // + } + + +} diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/choiceInteraction.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/choiceInteraction.html index 3da9353a7059b6c29cfd80e36c00d9002a2e64db..a86b464c4d89af5d10860f1e657ad13643c238db 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/_content/choiceInteraction.html +++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/choiceInteraction.html @@ -1,6 +1,6 @@ #set($responseIdentifier = $r.responseUniqueId($interaction)) <input name="qtiworks_presented_${responseIdentifier}" type="hidden" value="1"/> -<div class="choiceInteraction $r.renderClassAttr($interaction)"> +<div id="qti_container_${responseIdentifier}" class="choiceInteraction $r.renderClassAttr($interaction)"> #if($r.isInvalidResponse($interaction.responseIdentifier)) <div class="badResponse"> #if($interaction.minChoices == $interaction.maxChoices && $interaction.minChoices > 0) @@ -74,3 +74,14 @@ </table> #end </div> +#if(!$r.isSingleChoice($interaction) && $r.isItemSessionOpen()) +<script type='text/javascript'> + jQuery(function() { + jQuery('#qti_container_${responseIdentifier}').choiceInteraction({ + responseIdentifier: '$responseIdentifier', + formDispatchFieldId: '$r.formDispatchFieldId', + maxChoices: $interaction.maxChoices + }); + }); +</script> +#end \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/drawingInteraction.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/drawingInteraction.html index 294e1487b95805bb937d2d15a070215e1e57fb4c..6f15b98e6c4151f24f12921c0e3cf68549cdc2aa 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/_content/drawingInteraction.html +++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/drawingInteraction.html @@ -38,11 +38,11 @@ <div class="btn-group"> <canvas id="brush_size" width="50" height="50"> </canvas> </div> - <div class="btn-group"> - <input type="range" id="width_range" value="10">$r.translate("drawing.brushsize") + <div class="btn-group o_slider_width_range"> + <div id="width_range_ui"></div>$r.translate("drawing.brushsize") </div> - <div class="btn-group"> - <input type="range" id="opacity_range" value="100">$r.translate("drawing.opacity") + <div class="btn-group o_slider_opacity_range"> + <div id="opacity_range_ui"></div>$r.translate("drawing.opacity") </div> </div> #end diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/hotspotInteraction.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/hotspotInteraction.html index f9b50d33366c8f55f265f4a2e94baead42b5bedb..429eea6d4f0413769193b73b74ba2cd2eea8648d 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/_content/hotspotInteraction.html +++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/hotspotInteraction.html @@ -1,6 +1,7 @@ #set($responseIdentifier = $r.responseUniqueId($interaction)) #set($qtiContainerId = "oc_" + $responseIdentifier) #set($responseValue = $r.getResponseValue($interaction.responseIdentifier)) +#set($isResponsive = $r.hasCssClass($interaction, "interaction-responsive")) <input name="qtiworks_presented_${responseIdentifier}" type="hidden" value="1"/> <div class="$localName"> @@ -12,8 +13,8 @@ <div class="o_error badResponse">$r.translate("error.as.directed")</div> #end - <div id="${qtiContainerId}" style="width:${interaction.object.width}px; height:${interaction.object.height}px"> - <img id="${qtiContainerId}_img" width="${interaction.object.width}" height="${interaction.object.height}" src="${r.convertLinkFull($interaction.object.data)}" usemap="#${qtiContainerId}_map"></img> + <div id="${qtiContainerId}" #if($r.isFalse($isResponsive)) style="width:${interaction.object.width}px; height:${interaction.object.height}px" #end> + <img id="${qtiContainerId}_img" #if($r.isTrue($isResponsive)) class="o_hotspot_responsive" #end width="${interaction.object.width}" height="${interaction.object.height}" src="${r.convertLinkFull($interaction.object.data)}" usemap="#${qtiContainerId}_map"></img> <map name="${qtiContainerId}_map"> #foreach($hotspotChoice in $interaction.getHotspotChoices()) <!-- Match group, label --> @@ -23,15 +24,21 @@ </map> </div> <script type="text/javascript"> + /* <![CDATA[ */ jQuery(function() { - jQuery('#${qtiContainerId}_img').maphilight({ - fillColor: 'bbbbbb', - fillOpacity: 0.5, - strokeColor: '666666', - strokeOpacity: 0.8, - strokeWidth: 3, - alwaysOn: true - }); + #if($r.isTrue($isResponsive)) + //rwdImageMaps make maphilight onload + jQuery('#${qtiContainerId}_img').rwdImageMaps(); + #else + jQuery('#${qtiContainerId}_img').maphilight({ + fillColor: 'bbbbbb', + fillOpacity: 0.5, + strokeColor: '666666', + strokeOpacity: 0.8, + strokeWidth: 3, + alwaysOn: true + }); + #end jQuery('#${qtiContainerId}').hotspotInteraction({ responseIdentifier: '$responseIdentifier', @@ -41,5 +48,6 @@ opened: $isItemSessionOpen }); }); + /* ]]> */ </script> -</div> +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/hottextInteraction.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/hottextInteraction.html index 56a5221183e06c5f09c736f21091e0bbd08ad2a4..84e1630c3b5ff0b8e685a9071b41380a0d956096 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/_content/hottextInteraction.html +++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/hottextInteraction.html @@ -1,7 +1,7 @@ #set($responseIdentifier = $r.responseUniqueId($interaction)) <input name="qtiworks_presented_${responseIdentifier}" type="hidden" value="1"/> -<div class="$localName"> +<div id="qti_container_${responseIdentifier}" class="$localName"> #if($interaction.getPrompt()) <div class="prompt">$r.renderPrompt($interaction.getPrompt())</div> #end @@ -26,3 +26,14 @@ $r.renderBlockStatics($interaction.getBlockStatics()) </div> +#if(!$r.isSingleChoice($interaction) && $r.isItemSessionOpen()) +<script type='text/javascript'> + jQuery(function() { + jQuery('#qti_container_${responseIdentifier}').choiceInteraction({ + responseIdentifier: '$responseIdentifier', + formDispatchFieldId: '$r.formDispatchFieldId', + maxChoices: $interaction.maxChoices + }); + }); +</script> +#end \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/matchInteraction_dnd.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/matchInteraction_dnd.html index e7bdb9da110604fe6b36a7dfc1f0b87c7edd3dcd..e452477c293262d8c58db6db4db09b98d66d48fa 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/_content/matchInteraction_dnd.html +++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/matchInteraction_dnd.html @@ -25,7 +25,8 @@ <ul class="list-unstyled o_match_dnd_targets target-bottom clearfix"> #foreach($choice in $orderedSet2) #set($choiceIdentifier = $r.toString($choice.identifier)) - <li class="o_match_dnd_target" data-qti-match-max="${choice.matchMax}">$r.renderFlowStatics($choice.getFlowStatics()) + <li class="o_match_dnd_target" data-qti-match-max="${choice.matchMax}"> + <div class="clearfix">$r.renderFlowStatics($choice.getFlowStatics())</div> <ul class="o_match_dnd_target_drop_zone list-unstyled clearfix" data-qti-id="${choiceIdentifier}" data-qti-match-max="${choice.matchMax}"></ul> </li> #end @@ -35,7 +36,8 @@ <ul class="list-unstyled o_match_dnd_targets target-right"> #foreach($choice in $orderedSet2) #set($choiceIdentifier = $r.toString($choice.identifier)) - <li class="o_match_dnd_target" data-qti-match-max="${choice.matchMax}">$r.renderFlowStatics($choice.getFlowStatics()) + <li class="o_match_dnd_target" data-qti-match-max="${choice.matchMax}"> + <div class="clearfix">$r.renderFlowStatics($choice.getFlowStatics())</div> <ul class="o_match_dnd_target_drop_zone list-unstyled" data-qti-id="${choiceIdentifier}" data-qti-match-max="${choice.matchMax}"></ul> </li> #end @@ -51,7 +53,8 @@ <ul class="list-unstyled o_match_dnd_targets target-top clearfix"> #foreach($choice in $orderedSet2) #set($choiceIdentifier = $r.toString($choice.identifier)) - <li class="o_match_dnd_target" data-qti-match-max="${choice.matchMax}">$r.renderFlowStatics($choice.getFlowStatics()) + <li class="o_match_dnd_target" data-qti-match-max="${choice.matchMax}"> + <div class="clearfix">$r.renderFlowStatics($choice.getFlowStatics())</div> <ul class="o_match_dnd_target_drop_zone list-unstyled clearfix" data-qti-id="${choiceIdentifier}" data-qti-match-max="${choice.matchMax}"></ul> </li> #end @@ -73,8 +76,9 @@ <ul class="list-unstyled o_match_dnd_targets target-right"> #foreach($choice in $orderedSet2) #set($choiceIdentifier = $r.toString($choice.identifier)) - <li class="o_match_dnd_target" data-qti-match-max="${choice.matchMax}">$r.renderFlowStatics($choice.getFlowStatics()) - <ul class="o_match_dnd_target_drop_zone list-unstyled" data-qti-id="${choiceIdentifier}" data-qti-match-max="${choice.matchMax}"></ul> + <li class="o_match_dnd_target" data-qti-match-max="${choice.matchMax}"> + <div class="clearfix">$r.renderFlowStatics($choice.getFlowStatics())</div> + <ul class="o_match_dnd_target_drop_zone list-unstyled clearfix" data-qti-id="${choiceIdentifier}" data-qti-match-max="${choice.matchMax}"></ul> </li> #end </ul> diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/orderInteraction.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/orderInteraction.html index 0bd1632cb2b52a4727a7d51fa74e1744b619caa5..f3238d8c83b7b04ce64b5b1414623cc4992c6e44 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/_content/orderInteraction.html +++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/orderInteraction.html @@ -18,34 +18,28 @@ <div id="qtiworks_response_${responseIdentifier}"> ## Create holder for hidden form fields that will contain the actual data to pass back <div class="hiddenInputContainer"></div> - - <!-- Now generate selection widget --> - <h4>$r.translate("interaction.order.source")</h4> <div class="source box ${orientation}"> #if($r.isItemSessionOpen()) <span class="info">$r.translate("interaction.order.drag.msg")</span> #end - <ul class="${orientation}"> + <ul> #foreach($unselectedChoice in $unselectedVisibleChoices) <li id="qtiworks_response_${unselectedChoice.identifier}" class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span> - $r.renderFlowStatics($unselectedChoice.getFlowStatics()) - </li> + $r.renderFlowStatics($unselectedChoice.getFlowStatics())</li> #end </ul> - </div> - <h4>$r.translate("interaction.order.target")</h4> + </div> <div class="target box ${orientation}"> #if($r.isItemSessionOpen()) <span class="info">$r.translate("interaction.order.drop.msg")</span> #end - <ul class="${orientation}"> + <ul class="clearfix"> #foreach($respondedChoice in $respondedVisibleChoices) <li id="qtiworks_response_${respondedChoice.identifier}" class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span> - $r.renderFlowStatics($respondedChoice.getFlowStatics()) - </li> - #end - </ul><br /><br /> - </div><br /><br /> + $r.renderFlowStatics($respondedChoice.getFlowStatics())</li> + #end + </ul> + </div> <script type="text/javascript"> jQuery(function() { jQuery('#qtiworks_response_${responseIdentifier}').orderInteraction({ @@ -56,8 +50,8 @@ minChoices: #if($interaction.minChoices) $interaction.minChoices #else null #end, maxChoices: #if($interaction.maxChoices) $interaction.maxChoices #else null #end, opened: $isItemSessionOpen - }); - }); + }); + }); </script> </div> </div> diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java index 05d5eae1279a8763c527ead495f0d56f91119fef..72411509ed018c22a856cbb7a7ebec0413c6c1b5 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java @@ -57,7 +57,6 @@ import org.olat.ims.qti21.ui.editor.interactions.HotspotChoiceScoreController; import org.olat.ims.qti21.ui.editor.interactions.HotspotEditorController; import org.olat.ims.qti21.ui.editor.interactions.HottextEditorController; import org.olat.ims.qti21.ui.editor.interactions.KPrimEditorController; -import org.olat.ims.qti21.ui.editor.interactions.LobFeedbackEditorController; import org.olat.ims.qti21.ui.editor.interactions.MatchEditorController; import org.olat.ims.qti21.ui.editor.interactions.MatchScoreController; import org.olat.ims.qti21.ui.editor.interactions.MultipleChoiceEditorController; @@ -235,11 +234,11 @@ public class AssessmentItemEditorController extends BasicController { itemEditor = new SingleChoiceEditorController(ureq, getWindowControl(), scItemBuilder, rootDirectory, rootContainer, itemFile, restrictedEdit); listenTo(itemEditor); - scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), scItemBuilder, itemRef, restrictedEdit, + scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), scItemBuilder, itemRef, itemFile, restrictedEdit, "Test editor QTI 2.1 in detail#details_testeditor_score"); listenTo(scoreEditor); - feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), scItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), scItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.standardFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.choice"), itemEditor); @@ -253,11 +252,11 @@ public class AssessmentItemEditorController extends BasicController { itemEditor = new MultipleChoiceEditorController(ureq, getWindowControl(), mcItemBuilder, rootDirectory, rootContainer, itemFile, restrictedEdit); listenTo(itemEditor); - scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), mcItemBuilder, itemRef, restrictedEdit, + scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), mcItemBuilder, itemRef, itemFile, restrictedEdit, "Test editor QTI 2.1 in detail#details_testeditor_score"); listenTo(scoreEditor); - feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), mcItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), mcItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.standardFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.choice"), itemEditor); @@ -274,8 +273,8 @@ public class AssessmentItemEditorController extends BasicController { scoreEditor = new MinimalScoreController(ureq, getWindowControl(), kprimItemBuilder, itemRef, restrictedEdit, "Test editor QTI 2.1 in detail#details_testeditor_score"); listenTo(scoreEditor); - feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), kprimItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), kprimItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.standardFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.kprim"), itemEditor); @@ -289,10 +288,10 @@ public class AssessmentItemEditorController extends BasicController { itemEditor = new MatchEditorController(ureq, getWindowControl(), matchItemBuilder, rootDirectory, rootContainer, itemFile, restrictedEdit); listenTo(itemEditor); - scoreEditor = new MatchScoreController(ureq, getWindowControl(), matchItemBuilder, itemRef, restrictedEdit); + scoreEditor = new MatchScoreController(ureq, getWindowControl(), matchItemBuilder, itemRef, itemFile, restrictedEdit); listenTo(scoreEditor); - feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), matchItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), matchItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.standardFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.match"), itemEditor); @@ -306,10 +305,10 @@ public class AssessmentItemEditorController extends BasicController { itemEditor = new MatchEditorController(ureq, getWindowControl(), matchItemBuilder, rootDirectory, rootContainer, itemFile, restrictedEdit); listenTo(itemEditor); - scoreEditor = new MatchScoreController(ureq, getWindowControl(), matchItemBuilder, itemRef, restrictedEdit); + scoreEditor = new MatchScoreController(ureq, getWindowControl(), matchItemBuilder, itemRef, itemFile, restrictedEdit); listenTo(scoreEditor); - feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), matchItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), matchItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.standardFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.match"), itemEditor); @@ -325,8 +324,8 @@ public class AssessmentItemEditorController extends BasicController { listenTo(itemEditor); scoreEditor = new FIBScoreController(ureq, getWindowControl(), fibItemBuilder, itemRef, restrictedEdit); listenTo(scoreEditor); - feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), fibItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), fibItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.standardFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.fib"), itemEditor); @@ -342,8 +341,8 @@ public class AssessmentItemEditorController extends BasicController { listenTo(itemEditor); scoreEditor = new HotspotChoiceScoreController(ureq, getWindowControl(), hotspotItemBuilder, itemRef, itemFile, restrictedEdit); listenTo(scoreEditor); - feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), hotspotItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), hotspotItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.standardFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.hotspot"), itemEditor); @@ -360,8 +359,8 @@ public class AssessmentItemEditorController extends BasicController { scoreEditor = new MinimalScoreController(ureq, getWindowControl(), essayItemBuilder, itemRef, restrictedEdit, "Test editor QTI 2.1 in detail#details_testeditor_score"); listenTo(scoreEditor); - feedbackEditor = new LobFeedbackEditorController(ureq, getWindowControl(), essayItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), essayItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.lobFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.essay"), itemEditor); @@ -378,8 +377,8 @@ public class AssessmentItemEditorController extends BasicController { scoreEditor = new MinimalScoreController(ureq, getWindowControl(), uploadItemBuilder, itemRef, restrictedEdit, "Test editor QTI 2.1 in detail#details_testeditor_score"); listenTo(scoreEditor); - feedbackEditor = new LobFeedbackEditorController(ureq, getWindowControl(), uploadItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), uploadItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.lobFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.upload"), itemEditor); @@ -396,8 +395,8 @@ public class AssessmentItemEditorController extends BasicController { scoreEditor = new MinimalScoreController(ureq, getWindowControl(), uploadItemBuilder, itemRef, restrictedEdit, "Test and Questionnaire Editor in Detail#details_testeditor_fragetypen_ft"); listenTo(scoreEditor); - feedbackEditor = new LobFeedbackEditorController(ureq, getWindowControl(), uploadItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), uploadItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.lobFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.drawing"), itemEditor); @@ -411,11 +410,11 @@ public class AssessmentItemEditorController extends BasicController { itemEditor = new HottextEditorController(ureq, getWindowControl(), hottextItemBuilder, rootDirectory, rootContainer, itemFile, restrictedEdit); listenTo(itemEditor); - scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), hottextItemBuilder, itemRef, restrictedEdit, + scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), hottextItemBuilder, itemRef, itemFile, restrictedEdit, "Test editor QTI 2.1 in detail#details_testeditor_score"); listenTo(scoreEditor); - feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), hottextItemBuilder, - rootDirectory, rootContainer, itemFile, restrictedEdit); + feedbackEditor = new FeedbacksEditorController(ureq, getWindowControl(), hottextItemBuilder, + rootDirectory, rootContainer, itemFile, FeedbacksEnabler.standardFeedbacks(), restrictedEdit); listenTo(feedbackEditor); tabbedPane.addTab(translate("form.hottext"), itemEditor); @@ -453,13 +452,13 @@ public class AssessmentItemEditorController extends BasicController { @Override protected void event(UserRequest ureq, Controller source, Event event) { if(event instanceof AssessmentItemEvent) { - if(event instanceof AssessmentItemEvent) { - AssessmentItemEvent aie = (AssessmentItemEvent)event; - if(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED.equals(aie.getCommand())) { - doBuildAndSaveAssessmentItem(); - doBuildAndCommitMetadata(); - fireEvent(ureq, new AssessmentItemEvent(aie.getCommand(), aie.getAssessmentItem(), itemRef, aie.getQuestionType())); - } + AssessmentItemEvent aie = (AssessmentItemEvent)event; + if(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED.equals(aie.getCommand())) { + doBuildAndSaveAssessmentItem(); + doBuildAndCommitMetadata(); + fireEvent(ureq, new AssessmentItemEvent(aie.getCommand(), aie.getAssessmentItem(), itemRef, aie.getQuestionType())); + } else if(AssessmentItemEvent.ASSESSMENT_ITEM_NEED_RELOAD.equals(aie.getCommand())) { + fireEvent(ureq, event); } } else if(metadataEditor == source) { if(event == Event.CHANGED_EVENT) { diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEditorController.java index 3289b05ecbb24afb9d62df65da32e27bd15a4e78..ddf06f62955c65ead81087c91170330f98c425ed 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionEditorController.java @@ -19,6 +19,8 @@ */ package org.olat.ims.qti21.ui.editor; +import java.io.File; + import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.tabbedpane.TabbedPane; @@ -28,6 +30,7 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.util.Util; +import org.olat.core.util.vfs.VFSContainer; import org.olat.ims.qti21.ui.AssessmentTestDisplayController; import org.olat.ims.qti21.ui.editor.events.AssessmentSectionEvent; @@ -44,6 +47,10 @@ public class AssessmentSectionEditorController extends BasicController { private final TabbedPane tabbedPane; private final VelocityContainer mainVC; + private final File testFile; + private final File rootDirectory; + private final VFSContainer rootContainer; + private final AssessmentSection section; private final boolean editable; @@ -53,10 +60,14 @@ public class AssessmentSectionEditorController extends BasicController { private AssessmentSectionExpertOptionsEditorController expertOptionsCtrl; public AssessmentSectionEditorController(UserRequest ureq, WindowControl wControl, - AssessmentSection section, boolean restrictedEdit, boolean editable) { + AssessmentSection section, File rootDirectory, VFSContainer rootContainer, File testFile, + boolean restrictedEdit, boolean editable) { super(ureq, wControl, Util.createPackageTranslator(AssessmentTestDisplayController.class, ureq.getLocale())); this.section = section; this.editable = editable; + this.testFile = testFile; + this.rootDirectory = rootDirectory; + this.rootContainer = rootContainer; this.restrictedEdit = restrictedEdit; mainVC = createVelocityContainer("assessment_test_editor"); @@ -71,7 +82,7 @@ public class AssessmentSectionEditorController extends BasicController { } private void initSectionEditor(UserRequest ureq) { - optionsCtrl = new AssessmentSectionOptionsEditorController(ureq, getWindowControl(), section, restrictedEdit, editable); + optionsCtrl = new AssessmentSectionOptionsEditorController(ureq, getWindowControl(), section, rootDirectory, rootContainer, testFile, restrictedEdit, editable); listenTo(optionsCtrl); expertOptionsCtrl = new AssessmentSectionExpertOptionsEditorController(ureq, getWindowControl(), section, restrictedEdit, editable); listenTo(expertOptionsCtrl); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionOptionsEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionOptionsEditorController.java index a38369ed5fb82c7b100d7934f61321f3346c9db9..9b67a4ecb88f7a86092aec572e7bb74c816f131c 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionOptionsEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentSectionOptionsEditorController.java @@ -19,6 +19,7 @@ */ package org.olat.ims.qti21.ui.editor; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -35,6 +36,7 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; +import org.olat.core.util.vfs.VFSContainer; import org.olat.ims.qti21.model.xml.AssessmentHtmlBuilder; import org.olat.ims.qti21.ui.AssessmentTestDisplayController; import org.olat.ims.qti21.ui.editor.events.AssessmentSectionEvent; @@ -57,6 +59,10 @@ public class AssessmentSectionOptionsEditorController extends FormBasicControlle private SingleSelection shuffleEl, randomSelectedEl; private List<RichTextElement> rubricEls = new ArrayList<>(); + private final File testFile; + private final File rootDirectory; + private final VFSContainer rootContainer; + private final AssessmentSection section; private final AssessmentHtmlBuilder htmlBuilder; @@ -66,10 +72,14 @@ public class AssessmentSectionOptionsEditorController extends FormBasicControlle private static final String[] yesnoKeys = new String[]{ "y", "n"}; public AssessmentSectionOptionsEditorController(UserRequest ureq, WindowControl wControl, - AssessmentSection section, boolean restrictedEdit, boolean editable) { + AssessmentSection section, File rootDirectory, VFSContainer rootContainer, File testFile, + boolean restrictedEdit, boolean editable) { super(ureq, wControl, Util.createPackageTranslator(AssessmentTestDisplayController.class, ureq.getLocale())); this.section = section; this.editable = editable; + this.testFile = testFile; + this.rootDirectory = rootDirectory; + this.rootContainer = rootContainer; this.restrictedEdit = restrictedEdit; htmlBuilder = new AssessmentHtmlBuilder(); initForm(ureq); @@ -87,9 +97,11 @@ public class AssessmentSectionOptionsEditorController extends FormBasicControlle titleEl = uifactory.addTextElement("title", "form.metadata.title", 255, title, formLayout); titleEl.setEnabled(editable); titleEl.setMandatory(true); - + + String relativePath = rootDirectory.toPath().relativize(testFile.toPath().getParent()).toString(); + VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath); if(section.getRubricBlocks().isEmpty()) { - RichTextElement rubricEl = uifactory.addRichTextElementForQTI21("rubric" + counter++, "form.imd.rubric", "", 8, -1, null, + RichTextElement rubricEl = uifactory.addRichTextElementForQTI21("rubric" + counter++, "form.imd.rubric", "", 12, -1, itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); rubricEl.getEditorConfiguration().setFileBrowserUploadRelPath("media"); rubricEl.setEnabled(editable); @@ -97,7 +109,7 @@ public class AssessmentSectionOptionsEditorController extends FormBasicControlle } else { for(RubricBlock rubricBlock:section.getRubricBlocks()) { String rubric = htmlBuilder.blocksString(rubricBlock.getBlocks()); - RichTextElement rubricEl = uifactory.addRichTextElementForQTI21("rubric" + counter++, "form.imd.rubric", rubric, 8, -1, null, + RichTextElement rubricEl = uifactory.addRichTextElementForQTI21("rubric" + counter++, "form.imd.rubric", rubric, 12, -1, itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); rubricEl.getEditorConfiguration().setFileBrowserUploadRelPath("media"); rubricEl.setEnabled(editable); @@ -191,7 +203,7 @@ public class AssessmentSectionOptionsEditorController extends FormBasicControlle //rubrics List<RubricBlock> rubricBlocks = new ArrayList<>(); for(RichTextElement rubricEl:rubricEls) { - String rubric = rubricEl.getValue(); + String rubric = rubricEl.getRawValue(); if(htmlBuilder.containsSomething(rubric)) { RubricBlock rubricBlock = (RubricBlock)rubricEl.getUserObject(); if(rubricBlock == null) { diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java index bd2159fa6e1f8ea8a288696d8360e960516407d0..db26374cff6271e52d5e849333c310331f8805a0 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java @@ -418,6 +418,8 @@ public class AssessmentTestComposerController extends MainLayoutBasicController doSaveManifest(); } else if(AssessmentItemEvent.ASSESSMENT_ITEM_METADATA_CHANGED.equals(aie.getCommand())) { doSaveManifest(); + } else if(AssessmentItemEvent.ASSESSMENT_ITEM_NEED_RELOAD.equals(aie.getCommand())) { + doReloadItem(ureq); } } else if(selectQItemCtrl == source) { cmc.deactivate(); @@ -836,6 +838,15 @@ public class AssessmentTestComposerController extends MainLayoutBasicController return null; } + private TreeNode doReloadItem(UserRequest ureq) { + TreeNode selectedNode = menuTree.getSelectedNode(); + updateTreeModel(false); + menuTree.setSelectedNodeId(selectedNode.getIdent()); + selectedNode = menuTree.getSelectedNode(); + partEditorFactory(ureq, selectedNode); + return selectedNode; + } + /** * Create a new test part and a section. Test part need a section, * section ref as children, it's mandatory. @@ -1120,8 +1131,10 @@ public class AssessmentTestComposerController extends MainLayoutBasicController currentEditorCtrl = new AssessmentTestPartEditorController(ureq, getWindowControl(), (TestPart)uobject, restrictedEdit, assessmentTestBuilder.isEditable()); } else if(uobject instanceof AssessmentSection) { + URI testURI = resolvedAssessmentTest.getTestLookup().getSystemId(); + File testFile = new File(testURI); currentEditorCtrl = new AssessmentSectionEditorController(ureq, getWindowControl(), (AssessmentSection)uobject, - restrictedEdit, assessmentTestBuilder.isEditable()); + unzippedDirRoot, unzippedContRoot, testFile, restrictedEdit, assessmentTestBuilder.isEditable()); } else if(uobject instanceof AssessmentItemRef) { AssessmentItemRef itemRef = (AssessmentItemRef)uobject; ResolvedAssessmentItem item = resolvedAssessmentTest.getResolvedAssessmentItem(itemRef); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestFeedbackEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestFeedbackEditorController.java index 362514545953b2a8faac182588c363730fc5ab40..8b98737ccece7507a7eb225ccfae811ac6dd4b7f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestFeedbackEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestFeedbackEditorController.java @@ -28,6 +28,7 @@ import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit; +import org.olat.core.gui.components.form.flexible.impl.elements.richText.TextMode; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; @@ -84,6 +85,7 @@ public class AssessmentTestFeedbackEditorController extends FormBasicController String passedText = passedFeedback == null ? "" : passedFeedback.getText(); feedbackPassedTextEl = uifactory.addRichTextElementForQTI21("correctText", "form.test.correct.text", passedText, 8, -1, itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); + feedbackPassedTextEl.getEditorConfiguration().setSimplestTextModeAllowed(TextMode.oneLine); feedbackPassedTextEl.setEnabled(!restrictedEdit); feedbackPassedTextEl.getEditorConfiguration().setFileBrowserUploadRelPath("media"); @@ -96,6 +98,7 @@ public class AssessmentTestFeedbackEditorController extends FormBasicController String fialedText = failedFeedback == null ? "" : failedFeedback.getText(); feedbackFailedTextEl = uifactory.addRichTextElementForQTI21("incorrectText", "form.test.incorrect.text", fialedText, 8, -1, itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); + feedbackFailedTextEl.getEditorConfiguration().setSimplestTextModeAllowed(TextMode.oneLine); feedbackFailedTextEl.setEnabled(!restrictedEdit); feedbackFailedTextEl.getEditorConfiguration().setFileBrowserUploadRelPath("media"); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/FeedbackEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/FeedbackEditorController.java deleted file mode 100644 index c3523cad7a370d6f46379b921faccd57f1099d59..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/ims/qti21/ui/editor/FeedbackEditorController.java +++ /dev/null @@ -1,226 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.ims.qti21.ui.editor; - -import java.io.File; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.form.flexible.FormItemContainer; -import org.olat.core.gui.components.form.flexible.elements.RichTextElement; -import org.olat.core.gui.components.form.flexible.elements.TextElement; -import org.olat.core.gui.components.form.flexible.impl.FormBasicController; -import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; -import org.olat.core.gui.components.form.flexible.impl.elements.richText.RichTextConfiguration; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.util.StringHelper; -import org.olat.core.util.filter.FilterFactory; -import org.olat.core.util.vfs.VFSContainer; -import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; -import org.olat.ims.qti21.model.xml.ModalFeedbackBuilder; -import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; - -/** - * - * Initial date: 09.12.2015<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class FeedbackEditorController extends FormBasicController { - - private TextElement hintTitleEl; - private RichTextElement hintTextEl; - private TextElement feedbackCorrectSolutionTitleEl; - private RichTextElement feedbackCorrectSolutionTextEl; - private TextElement feedbackCorrectTitleEl, feedbackIncorrectTitleEl; - private RichTextElement feedbackCorrectTextEl, feedbackIncorrectTextEl; - - private final File itemFile; - private final File rootDirectory; - private final VFSContainer rootContainer; - private final boolean restrictedEdit; - private final AssessmentItemBuilder itemBuilder; - - public FeedbackEditorController(UserRequest ureq, WindowControl wControl, AssessmentItemBuilder itemBuilder, - File rootDirectory, VFSContainer rootContainer, File itemFile, boolean restrictedEdit) { - super(ureq, wControl, LAYOUT_DEFAULT_2_10); - this.itemBuilder = itemBuilder; - this.restrictedEdit = restrictedEdit; - this.itemFile = itemFile; - this.rootDirectory = rootDirectory; - this.rootContainer = rootContainer; - initForm(ureq); - } - - @Override - protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - setFormContextHelp("Test editor QTI 2.1 in detail#details_testeditor_feedback"); - formLayout.setElementCssClass("o_sel_assessment_item_feedbacks"); - - String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString(); - VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath); - - {//hint - ModalFeedbackBuilder hint = itemBuilder.getHint(); - String hintTitle = hint == null ? "" : hint.getTitle(); - hintTitleEl = uifactory.addTextElement("hintTitle", "form.imd.hint.title", -1, hintTitle, formLayout); - hintTitleEl.setUserObject(hint); - hintTitleEl.setEnabled(!restrictedEdit); - hintTitleEl.setElementCssClass("o_sel_assessment_item_hint_title"); - String hintText = hint == null ? "" : hint.getText(); - hintTextEl = uifactory.addRichTextElementForQTI21("hintText", "form.imd.hint.text", hintText, 8, -1, - itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); - hintTextEl.setEnabled(!restrictedEdit); - hintTextEl.setHelpTextKey("feedback.hint.help", null); - hintTextEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); - hintTextEl.setElementCssClass("o_sel_assessment_item_hint"); - RichTextConfiguration hintConfig = hintTextEl.getEditorConfiguration(); - hintConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir - } - - {//correct solution feedback - ModalFeedbackBuilder correctSolutionFeedback = itemBuilder.getCorrectSolutionFeedback(); - String correctSolutionTitle = correctSolutionFeedback == null ? "" : correctSolutionFeedback.getTitle(); - feedbackCorrectSolutionTitleEl = uifactory.addTextElement("correctSolutionTitle", "form.imd.correct.solution.title", -1, correctSolutionTitle, formLayout); - feedbackCorrectSolutionTitleEl.setUserObject(correctSolutionFeedback); - feedbackCorrectSolutionTitleEl.setEnabled(!restrictedEdit); - feedbackCorrectSolutionTitleEl.setElementCssClass("o_sel_assessment_item_correct_solution_title"); - String correctSolutionText = correctSolutionFeedback == null ? "" : correctSolutionFeedback.getText(); - feedbackCorrectSolutionTextEl = uifactory.addRichTextElementForQTI21("correctSolutionText", "form.imd.correct.solution.text", correctSolutionText, 8, -1, - itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); - feedbackCorrectSolutionTextEl.setEnabled(!restrictedEdit); - feedbackCorrectSolutionTextEl.setHelpTextKey("feedback.correctsolution.help", null); - feedbackCorrectSolutionTextEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); - feedbackCorrectSolutionTextEl.setElementCssClass("o_sel_assessment_item_correct_solution"); - RichTextConfiguration richTextConfig2 = feedbackCorrectSolutionTextEl.getEditorConfiguration(); - richTextConfig2.setFileBrowserUploadRelPath("media");// set upload dir to the media dir - } - - {//correct feedback - ModalFeedbackBuilder correctFeedback = itemBuilder.getCorrectFeedback(); - String correctTitle = correctFeedback == null ? "" : correctFeedback.getTitle(); - feedbackCorrectTitleEl = uifactory.addTextElement("correctTitle", "form.imd.correct.title", -1, correctTitle, formLayout); - feedbackCorrectTitleEl.setUserObject(correctFeedback); - feedbackCorrectTitleEl.setEnabled(!restrictedEdit); - feedbackCorrectTitleEl.setElementCssClass("o_sel_assessment_item_correct_feedback_title"); - String correctText = correctFeedback == null ? "" : correctFeedback.getText(); - feedbackCorrectTextEl = uifactory.addRichTextElementForQTI21("correctText", "form.imd.correct.text", correctText, 8, -1, - itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); - feedbackCorrectTextEl.setEnabled(!restrictedEdit); - feedbackCorrectTextEl.setHelpTextKey("feedback.correct.help", null); - feedbackCorrectTextEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); - feedbackCorrectTextEl.setElementCssClass("o_sel_assessment_item_correct_feedback"); - RichTextConfiguration richTextConfig = feedbackCorrectTextEl.getEditorConfiguration(); - richTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir - } - - //incorrect feedback - { - ModalFeedbackBuilder incorrectFeedback = itemBuilder.getIncorrectFeedback(); - String incorrectTitle = incorrectFeedback == null ? "" : incorrectFeedback.getTitle(); - feedbackIncorrectTitleEl = uifactory.addTextElement("incorrectTitle", "form.imd.incorrect.title", -1, incorrectTitle, formLayout); - feedbackIncorrectTitleEl.setUserObject(incorrectFeedback); - feedbackIncorrectTitleEl.setEnabled(!restrictedEdit); - feedbackIncorrectTitleEl.setElementCssClass("o_sel_assessment_item_incorrect_feedback_title"); - String incorrectText = incorrectFeedback == null ? "" : incorrectFeedback.getText(); - feedbackIncorrectTextEl = uifactory.addRichTextElementForQTI21("incorrectText", "form.imd.incorrect.text", incorrectText, 8, -1, - itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); - feedbackIncorrectTextEl.setEnabled(!restrictedEdit); - feedbackIncorrectTextEl.setHelpTextKey("feedback.incorrect.help", null); - feedbackIncorrectTextEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); - feedbackIncorrectTextEl.setElementCssClass("o_sel_assessment_item_incorrect_feedback"); - RichTextConfiguration richTextConfig2 = feedbackIncorrectTextEl.getEditorConfiguration(); - richTextConfig2.setFileBrowserUploadRelPath("media");// set upload dir to the media dir - } - - - // Submit Button - if(!restrictedEdit) { - FormLayoutContainer buttonsContainer = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); - buttonsContainer.setRootForm(mainForm); - formLayout.add(buttonsContainer); - uifactory.addFormSubmitButton("submit", buttonsContainer); - } - } - - @Override - protected void formOK(UserRequest ureq) { - if(restrictedEdit) return; - - String hintTitle = hintTitleEl.getValue(); - String hintText = hintTextEl.getRawValue(); - if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(hintText))) { - ModalFeedbackBuilder hintBuilder = itemBuilder.getHint(); - if(hintBuilder == null) { - hintBuilder = itemBuilder.createHint(); - } - hintBuilder.setTitle(hintTitle); - hintBuilder.setText(hintText); - } else { - itemBuilder.removeHint(); - } - - String correctSolutionTitle = feedbackCorrectSolutionTitleEl.getValue(); - String correctSolutionText = feedbackCorrectSolutionTextEl.getRawValue(); - if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(correctSolutionText))) { - ModalFeedbackBuilder correctSolutionBuilder = itemBuilder.getCorrectSolutionFeedback(); - if(correctSolutionBuilder == null) { - correctSolutionBuilder = itemBuilder.createCorrectSolutionFeedback(); - } - correctSolutionBuilder.setTitle(correctSolutionTitle); - correctSolutionBuilder.setText(correctSolutionText); - } else { - itemBuilder.removeCorrectSolutionFeedback(); - } - - String correctTitle = feedbackCorrectTitleEl.getValue(); - String correctText = feedbackCorrectTextEl.getRawValue(); - if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(correctText))) { - ModalFeedbackBuilder correctBuilder = itemBuilder.getCorrectFeedback(); - if(correctBuilder == null) { - correctBuilder = itemBuilder.createCorrectFeedback(); - } - correctBuilder.setTitle(correctTitle); - correctBuilder.setText(correctText); - } else { - itemBuilder.removeCorrectFeedback(); - } - - String incorrectTitle = feedbackIncorrectTitleEl.getValue(); - String incorrectText = feedbackIncorrectTextEl.getRawValue(); - if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(incorrectText))) { - ModalFeedbackBuilder incorrectBuilder = itemBuilder.getIncorrectFeedback(); - if(incorrectBuilder == null) { - incorrectBuilder = itemBuilder.createIncorrectFeedback(); - } - incorrectBuilder.setTitle(incorrectTitle); - incorrectBuilder.setText(incorrectText); - } else { - itemBuilder.removeIncorrectFeedback(); - } - - fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED, itemBuilder.getAssessmentItem())); - } - - @Override - protected void doDispose() { - // - } -} diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/FeedbacksEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/FeedbacksEditorController.java new file mode 100644 index 0000000000000000000000000000000000000000..2957163e67028d1e612cd69eccdc7872e09d879c --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/FeedbacksEditorController.java @@ -0,0 +1,774 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.ui.editor; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.dropdown.DropdownItem; +import org.olat.core.gui.components.dropdown.DropdownOrientation; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +import org.olat.core.gui.components.form.flexible.elements.RichTextElement; +import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.TextElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.form.flexible.impl.elements.richText.RichTextConfiguration; +import org.olat.core.gui.components.form.flexible.impl.elements.richText.TextMode; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.StringHelper; +import org.olat.core.util.filter.FilterFactory; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; +import org.olat.ims.qti21.model.xml.ModalFeedbackBuilder; +import org.olat.ims.qti21.model.xml.ModalFeedbackBuilder.ModalFeedbackType; +import org.olat.ims.qti21.model.xml.ModalFeedbackCondition; +import org.olat.ims.qti21.model.xml.ResponseIdentifierForFeedback; +import org.olat.ims.qti21.model.xml.ResponseIdentifierForFeedback.Answer; +import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; + +/** + * + * + * Initial date: 31 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class FeedbacksEditorController extends FormBasicController implements SyncAssessmentItem { + + private FormLink addHintButton, addCorrectSolutionButton, addCorrectButton, + addIncorrectButton, addAdditionalButton, addAnsweredButton, addEmptyButton; + + private SimpleFeedbackForm hintForm, correctSolutionForm; + private SimpleFeedbackForm correctForm, incorrectForm; + private SimpleFeedbackForm answeredForm, emptyForm; + private List<RuledFeedbackForm> additionalForms = new ArrayList<>(); + + private final VFSContainer itemContainer; + private final boolean restrictedEdit; + private final FeedbacksEnabler enable; + private final AssessmentItemBuilder itemBuilder; + private final AtomicInteger counter = new AtomicInteger(); + + public FeedbacksEditorController(UserRequest ureq, WindowControl wControl, AssessmentItemBuilder itemBuilder, + File rootDirectory, VFSContainer rootContainer, File itemFile, FeedbacksEnabler enable, boolean restrictedEdit) { + super(ureq, wControl, "feedbacks"); + this.enable = enable; + this.itemBuilder = itemBuilder; + this.restrictedEdit = restrictedEdit; + String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString(); + itemContainer = (VFSContainer)rootContainer.resolve(relativePath); + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + setFormContextHelp("Test editor QTI 2.1 in detail#details_testeditor_feedback"); + formLayout.setElementCssClass("o_sel_assessment_item_feedbacks"); + + DropdownItem dropdownEl = uifactory.addDropdownMenu("add.feedback.menu", null, formLayout, getTranslator()); + dropdownEl.setOrientation(DropdownOrientation.right); + dropdownEl.setElementCssClass("o_sel_add_feedbacks"); + dropdownEl.setVisible(!restrictedEdit); + dropdownEl.setEmbbeded(true); + + addHintButton = uifactory.addFormLink("add.hint.feedback", formLayout, Link.LINK); + addHintButton.setElementCssClass("o_sel_add_hint"); + addHintButton.setVisible(enable.isEnabled(ModalFeedbackType.hint)); + dropdownEl.addElement(addHintButton); + addCorrectSolutionButton = uifactory.addFormLink("add.correctSolution.feedback", formLayout, Link.LINK); + addCorrectSolutionButton.setElementCssClass("o_sel_add_correct_solution"); + addCorrectSolutionButton.setVisible(enable.isEnabled(ModalFeedbackType.correctSolution)); + dropdownEl.addElement(addCorrectSolutionButton); + + addCorrectButton = uifactory.addFormLink("add.correct.feedback", formLayout, Link.LINK); + addCorrectButton.setElementCssClass("o_sel_add_correct"); + addCorrectButton.setVisible(enable.isEnabled(ModalFeedbackType.correct)); + dropdownEl.addElement(addCorrectButton); + addIncorrectButton = uifactory.addFormLink("add.incorrect.feedback", formLayout, Link.LINK); + addIncorrectButton.setElementCssClass("o_sel_add_incorrect"); + addIncorrectButton.setVisible(enable.isEnabled(ModalFeedbackType.incorrect)); + dropdownEl.addElement(addIncorrectButton); + + addAnsweredButton = uifactory.addFormLink("add.answered.feedback", formLayout, Link.LINK); + addAnsweredButton.setElementCssClass("o_sel_add_answered"); + addAnsweredButton.setVisible(enable.isEnabled(ModalFeedbackType.answered)); + dropdownEl.addElement(addAnsweredButton); + addEmptyButton = uifactory.addFormLink("add.empty.feedback", formLayout, Link.LINK); + addEmptyButton.setElementCssClass("o_sel_add_empty"); + addEmptyButton.setVisible(enable.isEnabled(ModalFeedbackType.empty)); + dropdownEl.addElement(addEmptyButton); + + addAdditionalButton = uifactory.addFormLink("add.additional.feedback", formLayout, Link.LINK); + dropdownEl.addElement(addAdditionalButton); + + ModalFeedbackBuilder hint = itemBuilder.getHint(); + hintForm = new SimpleFeedbackForm(hint, ModalFeedbackType.hint); + hintForm.initForm(ureq, formLayout); + hintForm.setVisible(!hintForm.isEmpty()); + + ModalFeedbackBuilder correctSolution = itemBuilder.getCorrectSolutionFeedback(); + correctSolutionForm = new SimpleFeedbackForm(correctSolution, ModalFeedbackType.correctSolution); + correctSolutionForm.initForm(ureq, formLayout); + correctSolutionForm.setVisible(!correctSolutionForm.isEmpty()); + + ModalFeedbackBuilder correct = itemBuilder.getCorrectFeedback(); + correctForm = new SimpleFeedbackForm(correct, ModalFeedbackType.correct); + correctForm.initForm(ureq, formLayout); + correctForm.setVisible(!correctForm.isEmpty()); + + ModalFeedbackBuilder incorrect = itemBuilder.getIncorrectFeedback(); + incorrectForm = new SimpleFeedbackForm(incorrect, ModalFeedbackType.incorrect); + incorrectForm.initForm(ureq, formLayout); + incorrectForm.setVisible(!incorrectForm.isEmpty()); + + ModalFeedbackBuilder answered = itemBuilder.getAnsweredFeedback(); + answeredForm = new SimpleFeedbackForm(answered, ModalFeedbackType.answered); + answeredForm.initForm(ureq, formLayout); + answeredForm.setVisible(!answeredForm.isEmpty()); + + ModalFeedbackBuilder empty = itemBuilder.getEmptyFeedback(); + emptyForm = new SimpleFeedbackForm(empty, ModalFeedbackType.empty); + emptyForm.initForm(ureq, formLayout); + emptyForm.setVisible(!emptyForm.isEmpty()); + + List<ModalFeedbackBuilder> additionals = itemBuilder.getAdditionalFeedbackBuilders(); + if(additionals != null && additionals.size() > 0) { + int count = 0; + for(ModalFeedbackBuilder additional:additionals) { + RuledFeedbackForm conditionForm = new RuledFeedbackForm(additional, ++count); + conditionForm.initForm(ureq, formLayout); + additionalForms.add(conditionForm); + } + } + if(formLayout instanceof FormLayoutContainer) { + FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; + layoutCont.contextPut("additionals", additionalForms); + } + + // Submit Button + if(!restrictedEdit) { + uifactory.addFormSubmitButton("submit", formLayout); + } + + updateAddButtons(); + } + + @Override + public void sync(UserRequest ureq, AssessmentItemBuilder builder) { + if(itemBuilder == builder && builder instanceof ResponseIdentifierForFeedback) { + for(RuledFeedbackForm additionalForm:additionalForms) { + additionalForm.sync(); + } + } + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(addHintButton == source) { + hintForm.setVisible(true); + updateAddButtons(); + } else if(addCorrectSolutionButton == source) { + correctSolutionForm.setVisible(true); + updateAddButtons(); + } else if(addCorrectButton == source) { + correctForm.setVisible(true); + updateAddButtons(); + } else if(addIncorrectButton == source) { + incorrectForm.setVisible(true); + updateAddButtons(); + } else if(addAnsweredButton == source) { + answeredForm.setVisible(true); + updateAddButtons(); + } else if(addEmptyButton == source) { + emptyForm.setVisible(true); + updateAddButtons(); + } else if(addAdditionalButton == source) { + doAddAdditionalFeedback(ureq); + } else { + if(additionalForms != null && additionalForms.size() > 0) { + for(RuledFeedbackForm conditionForm:additionalForms) { + conditionForm.formInnerEvent(source); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + private void updateAddButtons() { + addHintButton.setEnabled(!hintForm.isVisible()); + addCorrectSolutionButton.setEnabled(!correctSolutionForm.isVisible()); + addCorrectButton.setEnabled(!correctForm.isVisible()); + addIncorrectButton.setEnabled(!incorrectForm.isVisible()); + addAnsweredButton.setEnabled(!answeredForm.isVisible()); + addEmptyButton.setEnabled(!emptyForm.isVisible()); + } + + private void doAddAdditionalFeedback(UserRequest ureq) { + ModalFeedbackBuilder feedbackBuilder = new ModalFeedbackBuilder(itemBuilder.getAssessmentItem(), ModalFeedbackType.additional); + RuledFeedbackForm conditionForm = new RuledFeedbackForm(feedbackBuilder, additionalForms.size() + 1); + conditionForm.initForm(ureq, flc); + additionalForms.add(conditionForm); + } + + @Override + protected void formOK(UserRequest ureq) { + if(restrictedEdit) return; + + hintForm.commit(); + hintForm.setVisible(!hintForm.isEmpty()); + correctSolutionForm.commit(); + correctSolutionForm.setVisible(!correctSolutionForm.isEmpty()); + correctForm.commit(); + correctForm.setVisible(!correctForm.isEmpty()); + incorrectForm.commit(); + incorrectForm.setVisible(!incorrectForm.isEmpty()); + answeredForm.commit(); + answeredForm.setVisible(!answeredForm.isEmpty()); + emptyForm.commit(); + emptyForm.setVisible(!emptyForm.isEmpty()); + + List<RuledFeedbackForm> validAdditionalForms = new ArrayList<>(); + List<ModalFeedbackBuilder> additionalBuilders = new ArrayList<>(); + for(RuledFeedbackForm additionalForm:additionalForms) { + ModalFeedbackBuilder additionalBuilder = additionalForm.commit(); + if(additionalBuilder != null) { + additionalBuilders.add(additionalBuilder); + validAdditionalForms.add(additionalForm); + } + } + itemBuilder.setAdditionalFeedbackBuilders(additionalBuilders); + additionalForms.clear(); + additionalForms.addAll(validAdditionalForms); + updateAddButtons(); + + fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED, itemBuilder.getAssessmentItem())); + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + for(RuledFeedbackForm additionalForm:additionalForms) { + allOk &= additionalForm.validateFormLogic(); + } + + return allOk & super.validateFormLogic(ureq); + } + + @Override + protected void doDispose() { + // + } + + + public class SimpleFeedbackForm { + + private TextElement titleEl; + private RichTextElement textEl; + private FormLayoutContainer formLayout; + + private final ModalFeedbackType feedbackType; + private ModalFeedbackBuilder feedbackBuilder; + + public SimpleFeedbackForm(ModalFeedbackBuilder feedbackBuilder, ModalFeedbackType feedbackType) { + this.feedbackType = feedbackType; + this.feedbackBuilder = feedbackBuilder; + } + + public void initForm(UserRequest ureq, FormItemContainer parentFormLayout) { + String id = Integer.toString(counter.incrementAndGet()); + + formLayout = FormLayoutContainer.createDefaultFormLayout_2_10(feedbackType.name(), getTranslator()); + parentFormLayout.add(formLayout); + formLayout.setRootForm(mainForm); + formLayout.setFormTitle(translate("form.imd." + feedbackType.name() + ".text")); + + String title = feedbackBuilder == null ? "" : feedbackBuilder.getTitle(); + titleEl = uifactory.addTextElement("title_".concat(id), "form.imd.feedback.title", -1, title, formLayout); + titleEl.setUserObject(feedbackBuilder); + titleEl.setEnabled(!restrictedEdit); + titleEl.setElementCssClass("o_sel_assessment_item_" + feedbackType.name() + "_title"); + String text = feedbackBuilder == null ? "" : feedbackBuilder.getText(); + textEl = uifactory.addRichTextElementForQTI21("text_".concat(id), "form.imd.feedback.text", text, 8, -1, + itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); + textEl.getEditorConfiguration().setSimplestTextModeAllowed(TextMode.oneLine); + textEl.setEnabled(!restrictedEdit); + textEl.setHelpTextKey("feedback." + feedbackType.name() + ".help", null); + textEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); + textEl.setElementCssClass("o_sel_assessment_item_" + feedbackType.name() + "_feedback"); + RichTextConfiguration richTextConfig2 = textEl.getEditorConfiguration(); + richTextConfig2.setFileBrowserUploadRelPath("media");// set upload dir to the media dir + } + + public boolean isEmpty() { + String val = textEl.getValue(); + return !StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(val)); + } + + public boolean isVisible() { + return formLayout.isVisible(); + } + + public void setVisible(boolean visible) { + formLayout.setVisible(visible); + } + + public void commit() { + String title = titleEl.getValue(); + String text = textEl.getRawValue(); + if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(text))) { + feedbackBuilder = itemBuilder.getFeedbackBuilder(feedbackType); + if(feedbackBuilder == null) { + feedbackBuilder = itemBuilder.createFeedbackBuilder(feedbackType); + } + feedbackBuilder.setTitle(title); + feedbackBuilder.setText(text); + } else { + itemBuilder.removeFeedbackBuilder(feedbackType); + } + } + } + + public class RuledFeedbackForm { + + private TextElement titleEl; + private RichTextElement textEl; + private FormLayoutContainer formLayout; + private FormLayoutContainer conditionListContainer; + private List<ConditionForm> conditions = new ArrayList<>(); + + private int position; + private ModalFeedbackBuilder feedbackBuilder; + private final ModalFeedbackType feedbackType = ModalFeedbackType.additional; + + public RuledFeedbackForm(ModalFeedbackBuilder feedbackBuilder, int position) { + this.position = position; + this.feedbackBuilder = feedbackBuilder; + } + + public void initForm(UserRequest ureq, FormItemContainer parentFormLayout) { + String id = Integer.toString(counter.incrementAndGet()); + + formLayout = FormLayoutContainer.createDefaultFormLayout_2_10("feedback".concat(id), getTranslator()); + parentFormLayout.add(formLayout); + formLayout.setRootForm(mainForm); + formLayout.setFormTitle(translate("form.imd.additional.text", new String[] { Integer.toString(position) })); + + String title = feedbackBuilder == null ? "" : feedbackBuilder.getTitle(); + titleEl = uifactory.addTextElement("title_".concat(id), "form.imd.feedback.title", -1, title, formLayout); + titleEl.setUserObject(feedbackBuilder); + titleEl.setEnabled(!restrictedEdit); + titleEl.setElementCssClass("o_sel_assessment_item_" + feedbackType.name() + "_feedback_title"); + + conditionListContainer = FormLayoutContainer.createBareBoneFormLayout("cond_list_".concat(id), getTranslator()); + formLayout.add(conditionListContainer); + conditionListContainer.setRootForm(mainForm); + conditionListContainer.contextPut("conditions", conditions); + conditionListContainer.setLabel("form.imd.condition", null); + + // rules + if(feedbackBuilder.getFeedbackConditons() != null && feedbackBuilder.getFeedbackConditons().size() > 0) { + for(ModalFeedbackCondition condition:feedbackBuilder.getFeedbackConditons()) { + ConditionForm conditionForm = new ConditionForm(condition); + conditionForm.initForm(conditionListContainer); + conditions.add(conditionForm); + } + } else { + ConditionForm conditionForm = new ConditionForm(); + conditionForm.initForm(conditionListContainer); + conditions.add(conditionForm); + } + + String text = feedbackBuilder == null ? "" : feedbackBuilder.getText(); + textEl = uifactory.addRichTextElementForQTI21("text_".concat(id), "form.imd.feedback.text", text, 8, -1, + itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); + textEl.getEditorConfiguration().setSimplestTextModeAllowed(TextMode.oneLine); + textEl.setEnabled(!restrictedEdit); + textEl.setHelpTextKey("feedback." + feedbackType.name() + ".help", null); + textEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); + textEl.setElementCssClass("o_sel_assessment_item_" + feedbackType.name() + "_feedback"); + RichTextConfiguration richTextConfig2 = textEl.getEditorConfiguration(); + richTextConfig2.setFileBrowserUploadRelPath("media");// set upload dir to the media dir + + updateDeleteButtons(); + } + + public FormLayoutContainer getFormLayoutContainer() { + return formLayout; + } + + protected void sync() { + for(ConditionForm conditionForm:conditions) { + conditionForm.sync(); + } + } + + protected boolean validateFormLogic() { + boolean allOk = true; + + for(ConditionForm condition:conditions) { + allOk &= condition.validateFormLogic(); + } + + return allOk; + } + + protected void formInnerEvent(FormItem source) { + if(conditions != null && conditions.size() > 0) { + ConditionForm[] conditionArray = conditions.toArray(new ConditionForm[conditions.size()]); + for(ConditionForm condition:conditionArray) { + condition.formInnerEvent(source); + } + } + } + + public ModalFeedbackBuilder commit() { + String title = titleEl.getValue(); + String text = textEl.getRawValue(); + + List<ModalFeedbackCondition> feedbackConditions = new ArrayList<>(); + for(ConditionForm condition:conditions) { + feedbackConditions.add(condition.commit()); + } + + if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(text)) && feedbackConditions.size() > 0) { + if(feedbackBuilder == null) { + feedbackBuilder = itemBuilder.createFeedbackBuilder(feedbackType); + } + feedbackBuilder.setTitle(title); + feedbackBuilder.setText(text); + feedbackBuilder.setFeedbackConditions(feedbackConditions); + return feedbackBuilder; + } + return null; + } + + public void doAddCondition(ConditionForm current) { + ConditionForm conditionForm = new ConditionForm(); + conditionForm.initForm(conditionListContainer); + + int pos = -1; + if(current != null) { + pos = conditions.indexOf(current) + 1; + } + if(pos >= 0 && pos < conditions.size()) { + conditions.add(pos, conditionForm); + } else { + conditions.add(conditionForm); + } + conditionListContainer.setDirty(true); + updateDeleteButtons(); + } + + public void doRemoveCondition(ConditionForm toRemove) { + conditions.remove(toRemove); + conditionListContainer.remove(toRemove.getFormLayoutContainer()); + updateDeleteButtons(); + } + + private void updateDeleteButtons() { + boolean enableDelete = conditions.size() > 1; + for(ConditionForm condition:conditions) { + condition.setDeleteEnable(enableDelete); + } + } + + public class ConditionForm { + + private SingleSelection variableEl; + private SingleSelection operatorEl; + private SingleSelection dropDownValueEl; + private TextElement textValueEl; + + private FormLink addButton; + private FormLink deleteButton; + private FormLayoutContainer ruleContainer; + + private String[] variableKeys = new String[] { + ModalFeedbackCondition.Variable.score.name(), + ModalFeedbackCondition.Variable.attempts.name(), + }; + + private String[] variableWithResponseKeys = new String[] { + ModalFeedbackCondition.Variable.score.name(), + ModalFeedbackCondition.Variable.attempts.name(), + ModalFeedbackCondition.Variable.response.name(), + }; + + private String[] matchOperatorKeys = new String[] { + ModalFeedbackCondition.Operator.equals.name(), + ModalFeedbackCondition.Operator.notEquals.name(), + }; + + private String[] mathOperatorKeys = new String[] { + ModalFeedbackCondition.Operator.bigger.name(), + ModalFeedbackCondition.Operator.biggerEquals.name(), + ModalFeedbackCondition.Operator.equals.name(), + ModalFeedbackCondition.Operator.notEquals.name(), + ModalFeedbackCondition.Operator.smaller.name(), + ModalFeedbackCondition.Operator.smallerEquals.name() + }; + + private final ModalFeedbackCondition condition; + + public ConditionForm() { + this.condition = new ModalFeedbackCondition(); + } + + public ConditionForm(ModalFeedbackCondition condition) { + this.condition = condition; + } + + public void initForm(FormItemContainer feedbackFormLayout) { + String id = Integer.toString(counter.incrementAndGet()); + + String page = velocity_root + "/feedback_condition.html"; + ruleContainer = FormLayoutContainer.createCustomFormLayout("rule_".concat(id), getTranslator(), page); + feedbackFormLayout.add(ruleContainer); + ruleContainer.setRootForm(mainForm); + ruleContainer.contextPut("id", id); + ruleContainer.contextPut("rule", this); + + String[] varKeys = (itemBuilder instanceof ResponseIdentifierForFeedback) ? variableWithResponseKeys : variableKeys; + String[] variableValues = new String[varKeys.length]; + for(int i=varKeys.length; i-->0; ) { + variableValues[i] = translate("variable.".concat(varKeys[i])); + } + variableEl = uifactory.addDropdownSingleselect("var_".concat(id), null, ruleContainer, varKeys, variableValues, null); + variableEl.setDomReplacementWrapperRequired(false); + variableEl.setEnabled(!restrictedEdit); + variableEl.addActionListener(FormEvent.ONCHANGE); + boolean found = false; + if(condition.getVariable() != null) { + for(String variableKey:varKeys) { + if(variableKey.equals(condition.getVariable().name())) { + variableEl.select(variableKey, true); + found = true; + } + } + } + if(!found) { + variableEl.select(varKeys[0], true); + } + + operatorEl = uifactory.addDropdownSingleselect("ope_".concat(id), null, ruleContainer, new String[0], new String[0], null); + String[] operatorKeys = updateOperators(); + operatorEl.setDomReplacementWrapperRequired(false); + operatorEl.setEnabled(!restrictedEdit); + boolean foundOp = false; + if(condition.getVariable() != null) { + for(String operatorKey:operatorKeys) { + if(operatorKey.equals(condition.getOperator().name())) { + operatorEl.select(operatorKey, true); + foundOp = true; + } + } + } + if(!foundOp) { + operatorEl.select(operatorKeys[0], true); + } + + String val = condition.getValue(); + textValueEl = uifactory.addTextElement("txt_val_".concat(id), null, 8, val, ruleContainer); + textValueEl.setDomReplacementWrapperRequired(false); + textValueEl.setEnabled(!restrictedEdit); + + String[] answerKeys = new String[0]; + dropDownValueEl = uifactory.addDropdownSingleselect("ans_".concat(id), null, ruleContainer, answerKeys, answerKeys, null); + dropDownValueEl.setDomReplacementWrapperRequired(false); + dropDownValueEl.setEnabled(!restrictedEdit); + + updateValues(val); + + if(!restrictedEdit) { + addButton = uifactory.addFormLink("add_".concat(id), "add", null, ruleContainer, Link.BUTTON); + addButton.setIconLeftCSS("o_icon o_icon_add"); + deleteButton = uifactory.addFormLink("del_".concat(id), "delete", null, ruleContainer, Link.BUTTON); + deleteButton.setIconLeftCSS("o_icon o_icon_remove"); + } + } + + public void setDeleteEnable(boolean enable) { + if(deleteButton != null) { + deleteButton.setEnabled(enable); + } + } + + protected void sync() { + updateValues(getValue()); + } + + protected boolean validateFormLogic() { + boolean allOk = true; + + variableEl.clearError(); + textValueEl.clearError(); + dropDownValueEl.clearError(); + if(variableEl.isOneSelected()) { + String selectedKey = variableEl.getSelectedKey(); + if(ModalFeedbackCondition.Variable.score.name().equals(selectedKey)) { + try { + Double.parseDouble(textValueEl.getValue()); + } catch (NumberFormatException e) { + textValueEl.setErrorKey("error.double", null); + allOk &= false; + } + } else if(ModalFeedbackCondition.Variable.attempts.name().equals(selectedKey)) { + try { + Integer.parseInt(textValueEl.getValue()); + } catch (Exception e) { + textValueEl.setErrorKey("error.integer", null); + allOk &= false; + } + } else if(ModalFeedbackCondition.Variable.response.name().equals(selectedKey)) { + if(!dropDownValueEl.isOneSelected()) { + dropDownValueEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + } + } else { + variableEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + return allOk; + } + + protected void formInnerEvent(FormItem source) { + if(addButton == source) { + doAddCondition(this); + } else if(deleteButton == source) { + doRemoveCondition(this); + } else if(variableEl == source) { + updateOperators(); + updateValues(getValue()); + } + } + + private String[] updateOperators() { + String[] operatorKeys; + if(variableEl.getSelectedKey().equals(ModalFeedbackCondition.Variable.response.name())) { + operatorKeys = matchOperatorKeys; + } else { + operatorKeys = mathOperatorKeys; + } + + String[] operatorValues = new String[operatorKeys.length]; + for(int i=operatorKeys.length; i-->0; ) { + operatorValues[i] = translate("math.operator.".concat(operatorKeys[i])); + } + operatorEl.setKeysAndValues(operatorKeys, operatorValues, null); + return operatorKeys; + } + + private void updateValues(String val) { + boolean responseVar = variableEl.getSelectedKey().equals(ModalFeedbackCondition.Variable.response.name()); + textValueEl.setVisible(!responseVar); + dropDownValueEl.setVisible(responseVar); + + String[] answerKeys = new String[] {}; + String[] answerValues = new String[] {}; + if(itemBuilder instanceof ResponseIdentifierForFeedback) { + ResponseIdentifierForFeedback responseFeedback = (ResponseIdentifierForFeedback)itemBuilder; + List<Answer> answers = responseFeedback.getAnswers(); + answerKeys = new String[answers.size()]; + answerValues = new String[answers.size()]; + + for(int i=0; i<answers.size(); i++) { + Answer answer = answers.get(i); + answerKeys[i] = answer.getIdentifier().toString(); + answerValues[i] = answer.getLabel(); + } + dropDownValueEl.setKeysAndValues(answerKeys, answerValues, null); + + boolean foundAnswer = false; + if(val != null) { + for(String answerKey:answerKeys) { + if(answerKey.equals(val)) { + dropDownValueEl.select(answerKey, true); + foundAnswer = true; + } + } + } + if(!foundAnswer && answerKeys.length > 0) { + dropDownValueEl.select(answerKeys[0], true); + } + } + } + + public ModalFeedbackCondition commit() { + ModalFeedbackCondition.Variable var = ModalFeedbackCondition.Variable.valueOf(variableEl.getSelectedKey()); + ModalFeedbackCondition.Operator operator = ModalFeedbackCondition.Operator.valueOf(operatorEl.getSelectedKey()); + String val = getValue(); + return new ModalFeedbackCondition(var, operator, val); + } + + public String getValue() { + ModalFeedbackCondition.Variable var = ModalFeedbackCondition.Variable.valueOf(variableEl.getSelectedKey()); + String val = null; + switch(var) { + case score: + case attempts: + val = textValueEl.getValue(); + break; + case response: + val = dropDownValueEl.getSelectedKey(); + break; + + } + return val; + } + + public FormLink getAddButton() { + return addButton; + } + + public FormLink getDeleteButton() { + return deleteButton; + } + + + public SingleSelection getVariableEl() { + return variableEl; + } + + public SingleSelection getOperatorEl() { + return operatorEl; + } + + public TextElement getTextValueEl() { + return textValueEl; + } + + public FormLayoutContainer getFormLayoutContainer() { + return ruleContainer; + } + } + } +} diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/FeedbacksEnabler.java b/src/main/java/org/olat/ims/qti21/ui/editor/FeedbacksEnabler.java new file mode 100644 index 0000000000000000000000000000000000000000..fa91cf43dd72c9fb99deffd4c2e85d70301ad99f --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/FeedbacksEnabler.java @@ -0,0 +1,58 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.ui.editor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.olat.ims.qti21.model.xml.ModalFeedbackBuilder.ModalFeedbackType; + +/** + * Settings for the feedbacks editor. + * + * + * Initial date: 4 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class FeedbacksEnabler { + + private List<ModalFeedbackType> enabled = new ArrayList<>(); + + private FeedbacksEnabler(ModalFeedbackType... feedbackTypes) { + enabled = Arrays.asList(feedbackTypes); + } + + public boolean isEnabled(ModalFeedbackType type) { + return enabled.contains(type); + } + + public static FeedbacksEnabler standardFeedbacks() { + return new FeedbacksEnabler(ModalFeedbackType.hint, ModalFeedbackType.correctSolution, + ModalFeedbackType.correct, ModalFeedbackType.incorrect, ModalFeedbackType.additional); + } + + public static FeedbacksEnabler lobFeedbacks() { + return new FeedbacksEnabler(ModalFeedbackType.hint, ModalFeedbackType.correctSolution, + ModalFeedbackType.answered, ModalFeedbackType.empty, ModalFeedbackType.additional); + } + +} diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemConversionConfirmationController.java b/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemConversionConfirmationController.java new file mode 100644 index 0000000000000000000000000000000000000000..cb8f7e23ae9efcc292fb57c6f580531a50aba8d3 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemConversionConfirmationController.java @@ -0,0 +1,96 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.ui.editor; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +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.ims.qti21.model.QTI21QuestionType; +import org.olat.ims.qti21.model.xml.AlienItemAnalyzer.Report; + +/** + * + * Initial date: 30 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class UnkownItemConversionConfirmationController extends FormBasicController { + + private final Report report; + private SingleSelection alternativeEl; + + public UnkownItemConversionConfirmationController(UserRequest ureq, WindowControl wControl, Report report) { + super(ureq, wControl, "unkown_assessment_item_confirmation"); + this.report = report; + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + if(formLayout instanceof FormLayoutContainer) { + FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; + layoutCont.contextPut("warnings", report.getWarnings()); + layoutCont.contextPut("questionType", translate("new." + report.getType().name())); + } + + if(report.getAlternatives().size() > 0) { + String[] theKeys = new String[report.getAlternatives().size()]; + String[] theValues = new String[theKeys.length]; + for(int i=0; i<report.getAlternatives().size(); i++) { + QTI21QuestionType alternative = report.getAlternatives().get(i); + theKeys[i] = alternative.name(); + theValues[i] = translate("new." + alternative.name()); + } + alternativeEl = uifactory.addDropdownSingleselect("questions.alternative", formLayout, theKeys, theValues, null); + alternativeEl.setDomReplacementWrapperRequired(false); + } + + uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl()); + uifactory.addFormSubmitButton("convert", formLayout); + } + + public QTI21QuestionType getSelectedQuestionType() { + if(alternativeEl != null && alternativeEl.isOneSelected()) { + return QTI21QuestionType.valueOf(alternativeEl.getSelectedKey()); + } + return report.getType(); + } + + @Override + protected void doDispose() { + // + } + + + @Override + protected void formOK(UserRequest ureq) { + fireEvent(ureq, Event.DONE_EVENT); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } +} diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java index 5f4acc3d8b04c4322b23753e698ce4ce4f312f48..db18e4f393d92172f8028979fb3e63dc8b7afbd1 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java @@ -21,26 +21,43 @@ package org.olat.ims.qti21.ui.editor; import java.io.File; import java.net.URI; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.link.Link; 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.closablewrapper.CloseableModalController; +import org.olat.core.helpers.Settings; import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; +import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.model.InMemoryAssessmentTestSession; +import org.olat.ims.qti21.model.QTI21QuestionType; +import org.olat.ims.qti21.model.xml.AlienItemAnalyzer; +import org.olat.ims.qti21.model.xml.AlienItemAnalyzer.Report; +import org.olat.ims.qti21.ui.AssessmentTestDisplayController; import org.olat.ims.qti21.ui.ResourcesMapper; import org.olat.ims.qti21.ui.assessment.TerminatedStaticCandidateSessionContext; import org.olat.ims.qti21.ui.components.ItemBodyResultFormItem; +import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; import org.springframework.beans.factory.annotation.Autowired; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; +import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction; import uk.ac.ed.ph.jqtiplus.notification.NotificationLevel; import uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder; import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; @@ -59,7 +76,13 @@ import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; */ public class UnkownItemEditorController extends FormBasicController { + private FormLink convertLink; + + private CloseableModalController cmc; + private UnkownItemConversionConfirmationController confirmationCtrl; + private final String mapperUri; + private final File itemFileRef; private final AssessmentItem item; private final URI assessmentObjectUri; private final ResourceLocator inputResourceLocator; @@ -72,9 +95,10 @@ public class UnkownItemEditorController extends FormBasicController { public UnkownItemEditorController(UserRequest ureq, WindowControl wControl, ResolvedAssessmentItem resolvedAssessmentItem, AssessmentItem item, File itemFileRef, File fUnzippedDirRoot) { - super(ureq, wControl); - setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale())); + super(ureq, wControl, "unkown_assessment_item"); + setTranslator(Util.createPackageTranslator(AssessmentTestDisplayController.class, getLocale(), getTranslator())); this.item = item; + this.itemFileRef = itemFileRef; this.resolvedAssessmentItem = resolvedAssessmentItem; itemSessionController = createNewItemSessionStateAndController(); @@ -94,19 +118,33 @@ public class UnkownItemEditorController extends FormBasicController { protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormWarning("warning.alien.assessment.item"); - String title = StringHelper.escapeHtml(item.getTitle()); - uifactory.addStaticTextElement("title", "form.imd.title", title, formLayout); - - String responseId = "responseBody" + CodeHelper.getRAMUniqueID(); - ItemBodyResultFormItem formItem = new ItemBodyResultFormItem(responseId, resolvedAssessmentItem); - formLayout.add(responseId, formItem); - formItem.setLabel("form.imd.descr", null); - - formItem.setItemSessionState(itemSessionController.getItemSessionState()); - formItem.setCandidateSessionContext(new TerminatedStaticCandidateSessionContext(new InMemoryAssessmentTestSession())); - formItem.setResourceLocator(inputResourceLocator); - formItem.setAssessmentObjectUri(assessmentObjectUri); - formItem.setMapperUri(mapperUri); + convertLink = uifactory.addFormLink("convert.alien", formLayout, Link.BUTTON); + convertLink.setEnabled(canConvert()); + + if(formLayout instanceof FormLayoutContainer) { + FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; + + String title = StringHelper.escapeHtml(item.getTitle()); + layoutCont.contextPut("title", title); + + String responseId = "responseBody" + CodeHelper.getRAMUniqueID(); + ItemBodyResultFormItem formItem = new ItemBodyResultFormItem(responseId, resolvedAssessmentItem); + formLayout.add(responseId, formItem); + layoutCont.contextPut("responseId", responseId); + formItem.setLabel("form.imd.descr", null); + + formItem.setItemSessionState(itemSessionController.getItemSessionState()); + formItem.setCandidateSessionContext(new TerminatedStaticCandidateSessionContext(new InMemoryAssessmentTestSession())); + formItem.setResourceLocator(inputResourceLocator); + formItem.setAssessmentObjectUri(assessmentObjectUri); + formItem.setMapperUri(mapperUri); + } + } + + private boolean canConvert() { + AlienItemAnalyzer analyzer = new AlienItemAnalyzer(item); + Report report = analyzer.analyze(); + return report.getType() != QTI21QuestionType.unkown && !report.isBlocker(); } private ItemSessionController createNewItemSessionStateAndController() { @@ -132,9 +170,75 @@ public class UnkownItemEditorController extends FormBasicController { protected void doDispose() { // } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(confirmationCtrl == source) { + if(event == Event.DONE_EVENT) { + doConvertItem(ureq, confirmationCtrl.getSelectedQuestionType()); + } + cmc.deactivate(); + cleanUp(); + } else if(cmc == source) { + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeAsListenerAndDispose(confirmationCtrl); + removeAsListenerAndDispose(cmc); + confirmationCtrl = null; + cmc = null; + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(convertLink == source) { + doConfirmConversion(ureq); + } + super.formInnerEvent(ureq, source, event); + } + @Override protected void formOK(UserRequest ureq) { // } + + private void doConfirmConversion(UserRequest ureq) { + Report report = new AlienItemAnalyzer(item).analyze(); + confirmationCtrl = new UnkownItemConversionConfirmationController(ureq, getWindowControl(), report); + listenTo(confirmationCtrl); + + cmc = new CloseableModalController(getWindowControl(), translate("close"), confirmationCtrl.getInitialComponent(), true, translate("convert.alien")); + listenTo(cmc); + cmc.activate(); + } + + private void doConvertItem(UserRequest ureq, QTI21QuestionType alternativeType) { + item.setToolName(QTI21Constants.TOOLNAME); + item.setToolVersion(Settings.getVersion()); + if(alternativeType == QTI21QuestionType.matchdraganddrop) { + addClassToInteraction(QTI21Constants.CSS_MATCH_DRAG_AND_DROP); + } + qtiService.updateAssesmentObject(itemFileRef, resolvedAssessmentItem); + fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_NEED_RELOAD, item)); + } + + private void addClassToInteraction(String cssClass) { + List<Interaction> interactions = item.getItemBody().findInteractions(); + for(Interaction interaction:interactions) { + List<String> cssClasses = interaction.getClassAttr(); + if(cssClasses == null) { + cssClasses = new ArrayList<>(); + } else { + cssClasses = new ArrayList<>(cssClasses); + } + if(!cssClasses.contains(cssClass)) { + cssClasses.add(cssClass); + } + interaction.setClassAttr(cssClasses); + } + } } diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_content/feedback_condition.html b/src/main/java/org/olat/ims/qti21/ui/editor/_content/feedback_condition.html new file mode 100644 index 0000000000000000000000000000000000000000..4713052f87c833715581ae783985a74229582e30 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_content/feedback_condition.html @@ -0,0 +1,24 @@ +<div class='form-inline o_condition'> + $r.render("var_$id") + $r.render("ope_$id") + #if($r.visible("txt_val_$id")) + $r.render("txt_val_$id") + #end + #if($r.visible("ans_$id")) + $r.render("ans_$id") + #end + #if($r.available("add_$id")) + $r.render("add_$id") + #end + #if($r.available("del_$id")) + $r.render("del_$id") + #end + +#if($f.hasError("var_$id")) + <br/>$r.render("var_${id}_ERROR") +#end +#if($f.hasError("txt_val_$id")) + <br/>$r.render("txt_val_${id}_ERROR") +#end +</div> + diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_content/feedbacks.html b/src/main/java/org/olat/ims/qti21/ui/editor/_content/feedbacks.html new file mode 100644 index 0000000000000000000000000000000000000000..5cc420160928f264a9993e60f5f9509dbbd9164e --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_content/feedbacks.html @@ -0,0 +1,35 @@ +<div class="o_sel_assessment_item_feedbacks"> + <div class="o_button_group o_button_group_right"> + #if($r.available("add.feedback.menu")) + $r.render("add.feedback.menu") + #end + $r.contextHelpWithWrapper("Test editor QTI 2.1 in detail#details_testeditor_feedback") + </div> + #if($r.available("hint")) + $r.render("hint") + #end + #if($r.available("correctSolution")) + $r.render("correctSolution") + #end + #if($r.available("correct")) + $r.render("correct") + #end + #if($r.available("incorrect")) + $r.render("incorrect") + #end + #if($r.available("answered")) + $r.render("answered") + #end + #if($r.available("empty")) + $r.render("empty") + #end + #foreach($additional in $additionals) + $r.render($additional.formLayoutContainer) + #end + + #if($r.available("submit")) + <div class="col-sm-offset-2 col-sm-10"> + $r.render("submit") + </div> + #end +</div> diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_content/unkown_assessment_item.html b/src/main/java/org/olat/ims/qti21/ui/editor/_content/unkown_assessment_item.html new file mode 100644 index 0000000000000000000000000000000000000000..149dca0ae586c7aec2e895408fbabe7acce8934e --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_content/unkown_assessment_item.html @@ -0,0 +1,19 @@ +<div class="o_warning"> + $off_warn + #if($r.available("convert.alien")) + <div class="o_button_group"> + $r.render("convert.alien") + </div> + #end +</div> +<div id="o_qti_run"> + <div class="qtiworks o_assessmentitem"> + <div class="o_assessmentitem_wrapper"> + <h4 class="itemTitle">$title</h4> + <div id="itemBody" class="clearfix"> + $r.render($responseId) + </div> + <div class="o_button_group o_assessmentitem_controls"></div> + </div> + </div> +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_content/unkown_assessment_item_confirmation.html b/src/main/java/org/olat/ims/qti21/ui/editor/_content/unkown_assessment_item_confirmation.html new file mode 100644 index 0000000000000000000000000000000000000000..7a4c256471c636fc5df8c86a4cc271c058b4e2c7 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_content/unkown_assessment_item_confirmation.html @@ -0,0 +1,22 @@ +<div class="o_alternative_question_types"> + <h4 class="">$r.translate("convert.to") + #if($r.available("questions.alternative")) + $r.render("questions.alternative") + #else + $questionType + #end</h4> + #if($r.isNotEmpty($warnings)) + <div class="o_error">$r.translate("warning.conversion.list") + <ul class="list-unstyled"> + #foreach($warning in $warnings) + <li><i class="o_icon ${warning.cssClass()}"> </i> $r.translate(${warning.i18nKey()})</li> + #end + </ul> + </div> + #else + <div class="o_warning">$r.translate("warning.conversion.standard")</div> + #end + <div class="o_button_group"> + $r.render("cancel") $r.render("convert") + </div> +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_de.properties index 852f4f03d8e5642256c9100069e40a08db4d768b..648dd81a5099340f0b3f5f19f8b351ac3aef3d1f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_de.properties @@ -1,38 +1,55 @@ -#Tue Nov 15 16:40:49 CET 2016 +#Mon Sep 04 21:47:18 CEST 2017 +add=Hinzuf\u00FCgen +add.additional.feedback=Bedingte Feedback hinzuf\u00FCgen +add.answered.feedback=Feedback bei Antwort hinzuf\u00FCgen +add.correct.feedback=Feedback bei Wahl aller korrekten Antworten hinzuf\u00FCgen +add.correctSolution.feedback=Korrekte L\u00F6sung hinzuf\u00FCgen +add.empty.feedback=Feedback bei Wahl keiner Antworten hinzuf\u00FCgen +add.feedback.menu=Feedback hinzuf\u00FCgen +add.hint.feedback=L\u00F6sungshinweis +add.incorrect.feedback=Feedback bei Wahl einer falschen Antwort hinzuf\u00FCgen add.match.column=Kolonne hinzuf\u00FCgen add.match.row=Zeile hinzuf\u00FCgen answers=Antworten change.elements=Elemente \u00E4ndern +convert=Konvertieren +convert.alien=Konvertieren +convert.to=Umwandeln in: correct.answers=Korrekt cut.value=Notwendige Punktzahl f\u00FCr "Bestanden" +delete=L\u00F6schen delete.item=$org.olat.ims.qti.editor\:delete.item delete.section=$org.olat.ims.qti.editor\:delete.section delete.testPart=Wollen Sie den Test-Part mit allen Fragen wirklich l\u00F6schen? +dy=dx editor.sc.title=Single choice editor.unkown.title=Unbekanntes interaction error.cannot.create.section=Sie k\u00F6nnen hier keine Sektion erstellen. error.cannot.delete=Sie d\u00FCrfen diese Ressource nicht l\u00F6schen. error.double=$org.olat.ims.qti21.ui\:error.double error.import.question=Die Frage konnte wegen eine unerwartete Fehler nicht importiert werden +error.integer=$org.olat.ims.qti21.ui\:error.integer error.lock=Dieser Test/Fragebogen wird momentan vom Benutzer {0} editiert und ist deshalb gesperrt. error.lock.title=Test gesperrt error.mimetype=$org.olat.core.commons.modules.bc\:WrongMimeType +error.missing.fib=Die Frage mussen mindestens einen L\u00FCckentext oder eine Numerische Eingabe enthalten. +error.missing.hottext=Die Frage mussen mindestens einen Hottext enthalten. error.need.correct.answer=Sie m\u00FCssen mindestens eine Antwort als korrekt markieren. error.positive.double=Falsches Zahlenformat, nur positive Nummer sind erlaubt. Beispiele\: 15.0, 5.5, 10 error.singlechoice=Genau ein ausw\u00E4hlen -error.missing.fib=Die Frage mussen mindestens einen L\u00FCckentext oder eine Numerische Eingabe enthalten. -error.missing.hottext=Die Frage mussen mindestens einen Hottext enthalten. essay.expectedLength=Anzahl Buchstaben essay.max.strings=Max Anzahl W\u00F6rter essay.min.strings=Min Anzahl W\u00F6rter essay.rows=H\u00F6he (Anzahl Zeilen) export.qpool.successful=$org.olat.ims.qti.editor\:export.qpool.successful -feedback.correctsolution.help=Korrekte L\u00F6sung: Diese L\u00F6sung wird automatisch dann angezeigt, wenn die Antwort falsch ist. -feedback.correct.help=Feedback bei Wahl aller korrekten Antworten: Dieses Feedback erscheint nur dann, wenn alle Antworten korrekt sind. -feedback.incorrect.help=Feedback bei Wahl einer falschen Antwort: Dieses Feedback erscheint, sobald 1 Antwort falsch ist (z.B.wenn von 50 L\u00FCcken nur 1 Antwort falsch ist). -feedback.hint.help=L\u00F6sungshinweis: F\u00FCr den Testteilnehmer erscheint eine Schaltfl\u00E4che, welche er aufrufen kann, solange die Antwort noch nicht gesendet worden ist. +feedback.answered.help=Feedback bei Antwort\: Dieses Feedback erscheint sobald der Benutzer eine Antwort gibt. +feedback.correct.help=Feedback bei Wahl aller korrekten Antworten\: Dieses Feedback erscheint nur dann, wenn alle Antworten korrekt sind. +feedback.correctSolution.help=Korrekte L\u00F6sung\: Diese L\u00F6sung wird automatisch dann angezeigt, wenn die Antwort falsch ist. +feedback.empty.help=Feedback bei leere Antwort\: Dieses Feedback erscheint solange die Antwort leer ist. +feedback.hint.help=L\u00F6sungshinweis\: F\u00FCr den Testteilnehmer erscheint eine Schaltfl\u00E4che, welche er aufrufen kann, solange die Antwort noch nicht gesendet worden ist. +feedback.incorrect.help=Feedback bei Wahl einer falschen Antwort\: Dieses Feedback erscheint, sobald 1 Antwort falsch ist (z.B.wenn von 50 L\u00FCcken nur 1 Antwort falsch ist). fib.alternative=Varianten -fib.alternative.help=Verschiedene Varianten werden mit Komma getrennt. +fib.alternative.help=Verschiedene Varianten fib.caseSensitive=Gross/Klein fib.expectedLength=L\u00FCckenl\u00E4nge fib.placeholder=Platzhalter @@ -41,12 +58,12 @@ fib.tolerance.low=Untere Schranke fib.tolerance.mode=Toleranz fib.tolerance.mode.absolute=Absolut fib.tolerance.mode.absolute.example=Eine Zahl, zum Beispiel 1.5 oder 1322 -fib.tolerance.mode.absolute.help=Die Schranke stellt eine absolute Zahl dar. Beispiel: L\u00F6sung 20, Untere Schranke 2, Obere Schranke 2 → Alle L\u00F6sungen zwischen 18 und 22 sin g\u00FCltig. Die untere Schranke wird von der L\u00F6sung subtrahiert, die obere Schranke wird zur L\u00F6sung addiert. +fib.tolerance.mode.absolute.help=Die Schranke stellt eine absolute Zahl dar. Beispiel\: L\u00F6sung 20, Untere Schranke 2, Obere Schranke 2 → Alle L\u00F6sungen zwischen 18 und 22 sin g\u00FCltig. Die untere Schranke wird von der L\u00F6sung subtrahiert, die obere Schranke wird zur L\u00F6sung addiert. fib.tolerance.mode.exact=Genau fib.tolerance.mode.exact.help=Die L\u00F6sung entspricht exakt der eingegebenen L\u00F6sung unter "L\u00F6sung" fib.tolerance.mode.relative=Relativ fib.tolerance.mode.relative.example=Prozent, zum Beispiel 15 oder 99.0 -fib.tolerance.mode.relative.help=Die Schranke stellt eine relative Zahl in Prozent dar.\u2028Beispiel: L\u00F6sung 20, Untere Schranke 10, Obere Schranke 10 → Alle L\u00F6sungen zwischen 18 und 22 sind g\u00FCltig, denn die untere Schranke bedeutet minus 10% (20-2) und die obere Schranke plus 10% (20+2). +fib.tolerance.mode.relative.help=Die Schranke stellt eine relative Zahl in Prozent dar.\u2028Beispiel\: L\u00F6sung 20, Untere Schranke 10, Obere Schranke 10 → Alle L\u00F6sungen zwischen 18 und 22 sind g\u00FCltig, denn die untere Schranke bedeutet minus 10% (20-2) und die obere Schranke plus 10% (20+2). fib.tolerance.up=Obere Schranke file=Datei form.choice=Auswahl @@ -56,6 +73,8 @@ form.feedback=Feedback form.fib=L\u00FCckentext form.hotspot=Hotspot form.hottext=Hottext +form.imd.additional.text=Feedback {0} +form.imd.additional.title=Titel form.imd.alignment=Check-box Ausrichtung form.imd.alignment.left=Links form.imd.alignment.right=Rechts @@ -63,35 +82,42 @@ form.imd.answer=Antwort form.imd.answered.text=Feedback bei Antwort form.imd.answered.title=Titel form.imd.background=Hintergrund +form.imd.background.resize=Bildgr\u00F6sse f\u00FCr das Web optimieren +form.imd.background.resize.no=Nicht anpassen +form.imd.condition=Bedingung(en) form.imd.correct.kprim=Richtig form.imd.correct.spots=Korrekte Spots -form.imd.correct.solution.title=Titel -form.imd.correct.solution.text=Korrekte L\u00F6sung -form.imd.correct.solution.text.word=$\:form.imd.correct.solution.text (nur f\u00FCr Word Export) form.imd.correct.text=Feedback bei Wahl aller korrekten Antworten form.imd.correct.title=Titel +form.imd.correctSolution.text=Korrekte L\u00F6sung +form.imd.correctSolution.text.word=$\:form.imd.correctSolution.text (nur f\u00FCr Word Export) +form.imd.correctSolution.title=Titel form.imd.descr=Frage form.imd.empty.text=Feedback bei Wahl keiner Antworten form.imd.empty.title=Titel +form.imd.feedback.text=Feedback +form.imd.feedback.title=Titel form.imd.hint.text=L\u00F6sungshinweis form.imd.hint.title=Titel form.imd.incorrect.text=Feedback bei Wahl einer falschen Antwort form.imd.incorrect.title=Titel form.imd.layout=$org.olat.ims.qti.editor\:form.imd.layout +form.imd.layout.bottom=Unten form.imd.layout.horizontal=$org.olat.ims.qti.editor\:form.imd.layout.horizontal -form.imd.layout.vertical=$org.olat.ims.qti.editor\:form.imd.layout.vertical form.imd.layout.left=Links -form.imd.layout.top=Oben -form.imd.layout.right=Rechts -form.imd.layout.bottom=Unten +form.imd.layout.match.sources=Begriffe form.imd.layout.match.targets=Drop-Kategorien form.imd.layout.match.targets.short=Kategorien -form.imd.layout.match.sources=Begriffe +form.imd.layout.right=Rechts +form.imd.layout.top=Oben +form.imd.layout.vertical=$org.olat.ims.qti.editor\:form.imd.layout.vertical form.imd.limittries=$org.olat.ims.qti.editor\:form.imd.limittries -form.imd.match.single.multiple=Typ -form.imd.match.single.choice=Single choice form.imd.match.multiple.choice=Multiple choice +form.imd.match.single.choice=Single choice +form.imd.match.single.multiple=Typ form.imd.mimetype=Erwarteter Datei-Typ +form.imd.responsive=Mobiltauglich +form.imd.responsive.hint=Das Hintergrundbild passt sich an die Bildschirmgr\u00F6sse an. Achtung\: Wenn das Bild kleiner wird, werden auch die Hotspots kleiner\! form.imd.rubric=Beschreibung form.imd.shuffle=Zuf\u00E4llige Reihenfolge form.imd.title=Titel @@ -118,26 +144,36 @@ form.test.correct.title=Titel form.test.incorrect.text=Feedback, wenn notwendige Punktzahl f\u00FCr "Bestanden" nicht erreicht form.test.incorrect.title=Titel form.testPart.navigationMode=Navigation -form.testPart.navigationMode.hint=Linear: Fragen m\u00FCssen der Reihe nach gel\u00F6st werden. Nicht linear: Reihenfolge der Fragen kann selbst gew\u00E4hlt werden. +form.testPart.navigationMode.hint=Linear\: Fragen m\u00FCssen der Reihe nach gel\u00F6st werden. Nicht linear\: Reihenfolge der Fragen kann selbst gew\u00E4hlt werden. form.testPart.navigationMode.linear=Linear form.testPart.navigationMode.nonlinear=Nicht linear form.unkown=Unbekannt form.upload=Datei hochladen +hour.short=h inherit=Vererbt item.session.control.allow.comment=Kommentar erlauben item.session.control.allow.comment.hint=Ein Testteilnehmer kann pers\u00F6nliche Notizen machen. Muss unter "Optionen" ausgew\u00E4hlt sein. item.session.control.allow.review=R\u00FCckblick erlauben item.session.control.allow.review.hint=Nach Beenden des Tests, R\u00FCckblick auf den Test ist m\u00F6glich. -item.session.control.allow.skipping=Fragen \u00FCberspring erlauben +item.session.control.allow.skipping=Fragen \u00FCberspringen erlauben item.session.control.allow.skipping.hint=Ein Test kann beendet werden, bevor alle Frage beantwortet sind. item.session.control.attempts=Versuch item.session.control.attempts.hint=Diese Einschr\u00E4nkung der L\u00F6sungsversuche bezieht sich auf einen Test-Part und nicht den gesamten Test. Die Versuche f\u00FCr den gesamten Test k\u00F6nnen unter "Optionen" eingeschr\u00E4nkt werden. item.session.control.show.solution=L\u00F6sung anzeigen item.session.control.show.solution.hint=Beim R\u00FCckblick werden auch L\u00F6sungen angezeigt. -hour.short=h -minute.short=m +math.operator.bigger=> +math.operator.biggerEquals=>\= +math.operator.equals=\= +math.operator.notEquals=\!\= +math.operator.smaller=< +math.operator.smallerEquals=<\=\t\t\t\t +max.choices=Max. Anzahl von mögliche Antworten +max.choices.unlimited=Beliebig max.score=Maximal erreichbare Punktzahl +min.choices=Min. Anzahl von mögliche Antworten +min.choices.unlimited=Nicht begrenzet min.score=Minimal erreichbare Punktzahl +minute.short=m new.answer=Neue Antwort new.circle=Kreis new.drawing=Zeichnen @@ -172,10 +208,20 @@ tools.import.qpool=$org.olat.ims.qti.editor\:tools.import.qpool tools.import.table=$org.olat.ims.qti.editor\:tools.import.table tools.reload.from.files=Dateien neu laden und im Puffer ersetzen tools.reload.from.files.tooltip=Only visible to administrators. +variable.attempts=L\u00F6sungsversuche +variable.response=Antwort +variable.score=Punkte warning.alien.assessment.item=Dieser Fragetyp kann nicht mit dem OpenOLAT-Editor bearbeitet werden. warning.alien.assessment.test=Dieser Test kann nicht mit dem OpenOLAT-Editor bearbeitet werden. +warning.alien.feedbacks=Diese Frage enth\u00E4lt Feedbacks die von dem Editor nicht unterst\u00FCtzt sind. Sie werden verloren nachdem Konvertierung. warning.atleastone=Bitte w\u00E4hlen Sie mindestens ein Element. warning.atleastonesection=Diese Sektion kann nicht gel\u00F6scht werden. Ein Test oder ein Test-Part muss mindestens eine Sektion enthalten. +warning.conversion.list=Es wurde Inkompatibilit\u00E4ten gefunde\: +warning.conversion.standard=Es gibt ein Risiko dass sie Daten verlieren obwohl kein Inkompatibilit\u00E4t entdeckt wurde. +warning.custom.operator=Es wurde ein Ersteller Spezifisch Extension gefunden. Diese ist nicht von Editor unterst\u00FCtzt. warning.feedback.cutvalue=Feedback wird aktiviert sobald bei "Notwendige Punktzahl f\u00FCr 'Bestanden'" eine Punktzahl eingegeben wurde. warning.in.use=Die Ressource wird bereits f\u00FCr Auswertung verwendet. Die Bearbeitung ist begrenzt. warning.item.session.control.attempts=Diese Einschr\u00E4nkung kann Auswirkungen auf die Anzahl L\u00F6sungsversuche pro Frage haben.<br/>Bitte \u00FCberpr\u00FCfen Sie die Einstellung der Fragen. +warning.templates=Diese Frage benutzt Templates die von dem OpenOLAT Editor nicht unterst\u00FCtzt ist. +warning.text.after.interaction=Diese Frage enth\u00E4lt Text nach dem Interaktiv Element. Das ist von dem Editor nicht unterst\u00FCtzt und dieser Teil von dem Text wird verloren. +warning.unsupported.feedbacks=Diese Frage enth\u00E4tlt Feedbacks die von dem Editor nicht unterst\u00FCtzt sind. Sie werden verloren nachdem Konvertierung. diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_en.properties index 399a6fa24f6f6176f42d5e3b0ae0bd099ab9a5ee..fd79b4173be02f2aff8eb6fb5f247ceac34515ca 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_en.properties @@ -1,38 +1,55 @@ -#Tue Jun 28 15:08:20 CEST 2016 +#Mon Sep 04 21:49:39 CEST 2017 +add=Add +add.additional.feedback=Add feedback with conditions +add.answered.feedback=Add feedback by answer +add.correct.feedback=Add a feedback for all correct answers +add.correctSolution.feedback=Add correct solution +add.empty.feedback=Add feedback by empty answer +add.feedback.menu=Add feedback +add.hint.feedback=Add hint +add.incorrect.feedback=Add feedback for wrong answer add.match.column=Add column add.match.row=Add row answers=Answers change.elements=Edition +convert=Convert +convert.alien=Convert correct.answers=Correct +convert.to=Convert to: cut.value=Cut value +delete=Delete delete.item=$org.olat.ims.qti.editor\:delete.item delete.section=$org.olat.ims.qti.editor\:delete.section delete.testPart=Do you really want to delete the test part along with all its questions? +dy=dx editor.sc.title=Single choice editor.unkown.title=Unkown interaction error.cannot.create.section=A section cannot be created everywhere\! error.cannot.delete=You cannot delete this object. error.double=$org.olat.ims.qti21.ui\:error.double -error.positive.double=Only positive number are allowed. Example\: 15.0, 5.5, 10 error.import.question=An unexpected error happens during import of a question. +error.integer=$org.olat.ims.qti21.ui\:error.integer error.lock=This test/questionnaire is being edited by user {0} at the moment and therefore locked. error.lock.title=Test locked error.mimetype=$org.olat.core.commons.modules.bc\:WrongMimeType error.missing.fib=The question need at least a gap text or a numerical input. error.missing.hottext=The question need at least a hottext. error.need.correct.answer=You need a least one correct answer. +error.positive.double=Only positive number are allowed. Example\: 15.0, 5.5, 10 error.singlechoice=Choose exactly one essay.expectedLength=Number of letters essay.max.strings=Max. words essay.min.strings=Min. words essay.rows=Height (number of lines) export.qpool.successful=$org.olat.ims.qti.editor\:export.qpool.successful -feedback.correctsolution.help=Correct solution: The solution is shown automatically, if the answer is wrong. -feedback.correct.help=Feedback for all correct answers: The feedback appears only if all answer are correct. -feedback.incorrect.help=Feedback for wrong answer: This feedback appears, as soon as 1 answer is wrong. E.g. also in a gap text, which consists of 50 gaps and only 1 answer is wrong. -feedback.hint.help=Hint: For the hint a button appears, which can be opened, as long as the answer is not submitted yet. +feedback.answered.help=Feedback by answer\: this feedback is shown automatically if the user give an answer. +feedback.correct.help=Feedback for all correct answers\: The feedback appears only if all answer are correct. +feedback.correctSolution.help=Correct solution\: The solution is shown automatically, if the answer is wrong. +feedback.empty.help=Feedback by empty\: this feedback is shown if the user give an empty answer. +feedback.hint.help=Hint\: For the hint a button appears, which can be opened, as long as the answer is not submitted yet. +feedback.incorrect.help=Feedback for wrong answer\: This feedback appears, as soon as 1 answer is wrong. E.g. also in a gap text, which consists of 50 gaps and only 1 answer is wrong. fib.alternative=Alternative -fib.alternative.help=Different alternatives are separated by comma. +fib.alternative.help=Different alternatives fib.caseSensitive=Case sensitive fib.expectedLength=Gap size fib.placeholder=Placeholder @@ -41,12 +58,12 @@ fib.tolerance.low=Lower bound fib.tolerance.mode=Tolerance mode fib.tolerance.mode.absolute=Absolute fib.tolerance.mode.absolute.example=A number, example 1.5 or 1322 -fib.tolerance.mode.absolute.help=The solution is accepted until a lower and an upper bound. The bound is an absolute number. Example: Solution 20, lower bound 2, upper bound 2 → all solutions between 18 and 22 are correct. The lower bound is subtracted from the solution, the upper bound is added to the solution. +fib.tolerance.mode.absolute.help=The solution is accepted until a lower and an upper bound. The bound is an absolute number. Example\: Solution 20, lower bound 2, upper bound 2 → all solutions between 18 and 22 are correct. The lower bound is subtracted from the solution, the upper bound is added to the solution. fib.tolerance.mode.exact=Exact fib.tolerance.mode.exact.help=The solution correlates exactly with the inserted solution in "Solution" fib.tolerance.mode.relative=Relative fib.tolerance.mode.relative.example=Percentage, example 15 or 99.0 -fib.tolerance.mode.relative.help=The solution is accepted until a lower and an upper bound. The bound is a relative number in percent. Example: Solution 20, lower bound 10, upper bound 10 → all solutions between 18 and 22 are correct, as the lower bound means minus 10% (20-2) and the upper bound plus 10% (20+2). +fib.tolerance.mode.relative.help=The solution is accepted until a lower and an upper bound. The bound is a relative number in percent. Example\: Solution 20, lower bound 10, upper bound 10 → all solutions between 18 and 22 are correct, as the lower bound means minus 10% (20-2) and the upper bound plus 10% (20+2). fib.tolerance.up=Upper bound file=File form.choice=Choice @@ -56,6 +73,8 @@ form.feedback=Feedback form.fib=Gap texts form.hotspot=Hotspot form.hottext=Hottext +form.imd.additional.text=Feedback {0} +form.imd.additional.title=Title form.imd.alignment=Check-box alignment form.imd.alignment.left=Left form.imd.alignment.right=Right @@ -63,35 +82,42 @@ form.imd.answer=Answer form.imd.answered.text=Feedback by answer form.imd.answered.title=Title form.imd.background=Background +form.imd.background.resize=Optimize an image size for the Web +form.imd.background.resize.no=Don't change +form.imd.condition=Condition(s) form.imd.correct.kprim=True form.imd.correct.spots=Correct spots -form.imd.correct.solution.title=Title -form.imd.correct.solution.text=Correct solution -form.imd.correct.solution.text.word=$\:form.imd.correct.solution.text (only for Word export) form.imd.correct.text=Feedback for all correct answers form.imd.correct.title=Title +form.imd.correctSolution.text=Correct solution +form.imd.correctSolution.text.word=$\:form.imd.correctSolution.text (only for Word export) +form.imd.correctSolution.title=Title form.imd.descr=Question form.imd.empty.text=Empty feedback form.imd.empty.title=Empty title +form.imd.feedback.text=Feedback +form.imd.feedback.title=Title form.imd.hint.text=Hint form.imd.hint.title=Title form.imd.incorrect.text=Feedback for wrong answer form.imd.incorrect.title=Title form.imd.layout=$org.olat.ims.qti.editor\:form.imd.layout +form.imd.layout.bottom=Bottom form.imd.layout.horizontal=$org.olat.ims.qti.editor\:form.imd.layout.horizontal -form.imd.layout.vertical=$org.olat.ims.qti.editor\:form.imd.layout.vertical form.imd.layout.left=Left -form.imd.layout.top=Top -form.imd.layout.right=Right -form.imd.layout.bottom=Bottom +form.imd.layout.match.sources=Items form.imd.layout.match.targets=Drop-Categories form.imd.layout.match.targets.short=Categories -form.imd.layout.match.sources=Items +form.imd.layout.right=Right +form.imd.layout.top=Top +form.imd.layout.vertical=$org.olat.ims.qti.editor\:form.imd.layout.vertical form.imd.limittries=$org.olat.ims.qti.editor\:form.imd.limittries -form.imd.match.single.multiple=Type -form.imd.match.single.choice=Single choice form.imd.match.multiple.choice=Multiple choice +form.imd.match.single.choice=Single choice +form.imd.match.single.multiple=Type form.imd.mimetype=Expected mime-type +form.imd.responsive=Responsive +form.imd.responsive.hint=Adapt the size of the image to the screen. Hotspots will be minimzed too. form.imd.rubric=Description form.imd.shuffle=Shuffle answers form.imd.title=Title @@ -118,13 +144,12 @@ form.test.correct.title=Title form.test.incorrect.text=Feedback for wrong answer form.test.incorrect.title=Title form.testPart.navigationMode=Navigation mode -form.testPart.navigationMode.hint=Linear: Questions must be solved in the given order. Non linear: Order of questions can be chosen. +form.testPart.navigationMode.hint=Linear\: Questions must be solved in the given order. Non linear\: Order of questions can be chosen. form.testPart.navigationMode.linear=Linear form.testPart.navigationMode.nonlinear=Non linear form.unkown=Unkown form.upload=File upload hour.short=h -minute.short=m inherit=Inherit item.session.control.allow.comment=Allow comments item.session.control.allow.comment.hint=A test participant can take personal notes. Must be enabled under "Options". @@ -136,8 +161,19 @@ item.session.control.attempts=Attempts item.session.control.attempts.hint=This limitation of the attempts is only valid for the parts not for the whole test. The attempts for the whole test can be limited in "Options". item.session.control.show.solution=Show solution item.session.control.show.solution.hint=Solution is shown in review as well. +math.operator.bigger=> +math.operator.biggerEquals=>\= +math.operator.equals=\= +math.operator.notEquals=\!\= +math.operator.smaller=< +math.operator.smallerEquals=<\= +max.choices=Max. number of possible answers +max.choices.unlimited=Unlimited max.score=Max. score +min.choices=Min. number of possible answers +min.choices.unlimited=Not limited min.score=Min. score +minute.short=m new.answer=New answer new.circle=Circle new.drawing=Drawing @@ -172,11 +208,20 @@ tools.import.qpool=$org.olat.ims.qti.editor\:tools.import.qpool tools.import.table=$org.olat.ims.qti.editor\:tools.import.table tools.reload.from.files=Reload files and refresh cache tools.reload.from.files.tooltip=Only visible to administrators. +variable.attempts=Attempts +variable.response=Answer +variable.score=Score warning.alien.assessment.item=This question type cannot be processed with the OpenOLAT editor. warning.alien.assessment.test=This test cannot be processed with the OpenOLAT editor. +warning.alien.feedbacks=This question contains feedbacks which are not compatible with this editor. They will be lost after conversion. warning.atleastone=Please, choose at least one element. warning.atleastonesection=The section cannot be deleted. A test or a test part must contain at least one section. +warning.conversion.list=Some incompatibilities was found\: +warning.conversion.standard=There is a risk that some data got lost after conversion but no flagrant incompatibilities was found. +warning.custom.operator=This question contains creator specific extension which are currently not supported by OpenOLAT. warning.feedback.cutvalue=The feedback is based on the cut value. You need to define it first. warning.in.use=The resource is already used for assessment purpose. Editing is limited. warning.item.session.control.attempts=This limitation can have an impact on the number of attempts per questions.<br/>Please check the settings for the questions again. - +warning.templates=This question contains some templates which are not compatible with the OpenOLAT editor. +warning.text.after.interaction=This question has text after the interaction element. This is not compatible with the OpenOLAT editor and the text will be lost after conversion. +warning.unsupported.feedbacks=This question contains feedbacks which are not compatible with the OpenOLAT editor. They can be lost after conversion. diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_fr.properties index 8b10c5c87c4a94b1bd4281e7b0371aad44da8f3b..cb5c9a2e179c6b2c317ee5bb059aa3b2fab8d19f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Thu Jun 08 21:39:03 CEST 2017 +#Tue Aug 15 17:24:51 CEST 2017 add.match.column=Ajouter une colonne add.match.row=Ajouter une ligne answers=R\u00E9ponses @@ -28,11 +28,11 @@ essay.min.strings=Nombre de mots min. essay.rows=Hauteur (nombre de lignes) export.qpool.successful=$org.olat.ims.qti.editor\:export.qpool.successful feedback.correct.help=Retour d'informations si toutes les r\u00E9ponses sont correctes\: le retour d'informations n'appara\u00EEt que si toute les r\u00E9ponses sont correctes. -feedback.correctsolution.help=Solution correcte\: la solution est montr\u00E9e automatiquement si la r\u00E9ponse est fausse. +feedback.correctSolution.help=Solution correcte\: la solution est montr\u00E9e automatiquement si la r\u00E9ponse est fausse. feedback.hint.help=Conseil\: un bouton appara\u00EEt pour montr\u00E9 le conseil tant que la r\u00E9ponse n'a pas \u00E9t\u00E9 soumise. feedback.incorrect.help=Feedback pour les r\u00E9ponses incorrects\: le feedback appara\u00EEt d\u00E8s qu'une r\u00E9ponse est fausse. Par exemple dans un text \u00E0 trous qui consiste en cinquante trous et qu'une seule r\u00E9ponse est fausse. fib.alternative=Alternatives -fib.alternative.help=Les diff\u00E9rentes alternatives sont s\u00E9par\u00E9es par une virgule. +fib.alternative.help=Diff\u00E9rentes alternatives fib.caseSensitive=Sensible aux majuscules / minuscules fib.expectedLength=Taille du trou fib.placeholder=Example g\u00E9n\u00E9rique @@ -63,10 +63,12 @@ form.imd.answer=R\u00E9ponse form.imd.answered.text=Retour d'information par question form.imd.answered.title=Titre form.imd.background=Image de fond +form.imd.background.resize=Optimiser la taille de l'image pour le web +form.imd.background.resize.no=Laisser inchang\u00E9 form.imd.correct.kprim=Vrai -form.imd.correct.solution.text=Solution correcte -form.imd.correct.solution.text.word=$\:form.imd.correct.solution.text (seulement pour export Word) -form.imd.correct.solution.title=Titre +form.imd.correctSolution.text=Solution correcte +form.imd.correctSolution.text.word=$\:form.imd.correctSolution.text (seulement pour export Word) +form.imd.correctSolution.title=Titre form.imd.correct.spots=Emplacement correct form.imd.correct.text=Feedback lors du choix de toutes les r\u00E9ponses correctes form.imd.correct.title=Titre @@ -92,6 +94,8 @@ form.imd.match.multiple.choice=Multiple choice form.imd.match.single.choice=Single choice form.imd.match.single.multiple=Type form.imd.mimetype=Type de fichier +form.imd.responsive=Convient pour mobile +form.imd.responsive.hint=L'image de fond s'adaptera \u00E0 la taille de l'\u00E9cran. Attention\: si l'image deviendra plus petites, les hotspots seront \u00E9galement plus petits\! form.imd.rubric=Description form.imd.shuffle=Ordre des r\u00E9ponses al\u00E9atoires form.imd.title=Titre diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_it.properties index 49da20daff19c42ef69d01fa051708bfe4d02e56..c1c373d17c2b9bcaa5caa1a816ff39003c37a4a8 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_it.properties @@ -26,7 +26,7 @@ essay.min.strings=Parole min. essay.rows=Altezza (numero di linee) export.qpool.successful=$org.olat.ims.qti.editor\:export.qpool.successful fib.alternative=Varianti -fib.alternative.help=Differenti alternative vanno separate con virgola. +fib.alternative.help=Differenti alternative fib.caseSensitive=Maiuscole/minuscole fib.expectedLength=Dimensione lacuna fib.placeholder=Segnaposto @@ -55,9 +55,9 @@ form.imd.answered.text=Feedback su risposta form.imd.answered.title=Titolo form.imd.background=Sfondo form.imd.correct.kprim=Vero -form.imd.correct.solution.text=Soluzione corretta -form.imd.correct.solution.text.word=$\:form.imd.correct.solution.text (solo per esportazione Word) -form.imd.correct.solution.title=Titolo +form.imd.correctSolution.text=Soluzione corretta +form.imd.correctSolution.text.word=$\:form.imd.correctSolution.text (solo per esportazione Word) +form.imd.correctSolution.title=Titolo form.imd.correct.spots=Punti corretti form.imd.correct.text=Feedback per tutte risposte esatte form.imd.correct.title=Titolo diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties index b6bbbe748fed32e7a5e52b21a434c41b65a6ee39..c939c6bed71b7600efb5be3bb926b32b101e6049 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Wed Jun 21 23:32:38 CEST 2017 +#Tue Sep 05 19:12:51 CEST 2017 add.match.column=Adicionar coluna add.match.row=Adicionar linha answers=Respostas @@ -28,11 +28,11 @@ essay.min.strings=Min. palavras essay.rows=Altura (n\u00FAmero de linhas) export.qpool.successful=$org.olat.ims.qti.editor\:export.qpool.successful feedback.correct.help=Feedback para todas as respostas corretas\: o feedback aparece apenas se toda a resposta estiver correta. -feedback.correctsolution.help=Solu\u00E7\u00E3o correta\: a solu\u00E7\u00E3o \u00E9 mostrada automaticamente, se a resposta for errada. +feedback.correctSolution.help=Solu\u00E7\u00E3o correta\: a solu\u00E7\u00E3o \u00E9 mostrada automaticamente, se a resposta for errada. feedback.hint.help=Dica\: para a "dica" aparecer\u00E1 um bot\u00E3o, que pode ser aberto, desde que a resposta ainda n\u00E3o tenha sido enviada. feedback.incorrect.help=Feedback para resposta errada\: esse feedback aparece, assim que 1 resposta estiver errada. Por exemplo. Tamb\u00E9m em um texto de lacunas, que consiste em 50 lacunas e apenas 1 resposta est\u00E1 errada. fib.alternative=Alternativa -fib.alternative.help=Diferentes alternativas s\u00E3o separadas por v\u00EDrgula. +fib.alternative.help=Diferentes alternativas fib.caseSensitive=Mai\u00FAsculas e min\u00FAsculas fib.expectedLength=Tamanho do intervalo fib.placeholder=Espa\u00E7o reservado @@ -63,10 +63,12 @@ form.imd.answer=Resposta form.imd.answered.text=Feedback por resposta form.imd.answered.title=T\u00EDtulo form.imd.background=Fundo +form.imd.background.resize=Otimizar tamanho de imagem para Web +form.imd.background.resize.no=N\u00E3o mude form.imd.correct.kprim=Verdade -form.imd.correct.solution.text=Solu\u00E7\u00E3o correta -form.imd.correct.solution.text.word=$\:form.imd.correct.solution.text (apenas para exporta\u00E7\u00E3o Word) -form.imd.correct.solution.title=T\u00EDtulo +form.imd.correctSolution.text=Solu\u00E7\u00E3o correta +form.imd.correctSolution.text.word=$\:form.imd.correctSolution.text (apenas para exporta\u00E7\u00E3o Word) +form.imd.correctSolution.title=T\u00EDtulo form.imd.correct.spots=Marca\u00E7\u00E3o correta form.imd.correct.text=Coment\u00E1rios para todas as respostas corretas form.imd.correct.title=T\u00EDtulo @@ -92,6 +94,8 @@ form.imd.match.multiple.choice=M\u00FAltipla escolha form.imd.match.single.choice=Escolha \u00FAnica form.imd.match.single.multiple=Tipo form.imd.mimetype="Mime-type" esperado +form.imd.responsive=Responsivo +form.imd.responsive.hint=Adapte o tamanho da imagem \u00E0 tela. Hotspots tamb\u00E9m ser\u00E3o minimizados form.imd.rubric=Descri\u00E7\u00E3o form.imd.shuffle=Respostas aleat\u00F3rias form.imd.title=T\u00EDtulo diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_zh_CN.properties index 077ded23ec24eeb3e5e06df07cc35cace076ea58..f14e0eecef97165b803909fb0872756aa8661b35 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_zh_CN.properties +++ b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_zh_CN.properties @@ -26,7 +26,6 @@ essay.min.strings=\u6700\u5C0F\u5B57\u7B26\u6570 essay.rows=\u9AD8\u5EA6\uFF08\u884C\u6570\uFF09 export.qpool.successful=$org.olat.ims.qti.editor\:export.qpool.successful fib.alternative=\u5907\u9009 -fib.alternative.help=\u7528\u9017\u53F7\u5206\u9694\u4E0D\u540C\u7684\u5907\u9009 fib.caseSensitive=\u533A\u5206\u5927\u5C0F\u5199 fib.expectedLength=\u95F4\u9694\u5927\u5C0F fib.placeholder=\u5360\u4F4D\u7B26 @@ -54,9 +53,9 @@ form.imd.answered.text=\u53CD\u9988\u7684\u7B54\u6848 form.imd.answered.title=\u6807\u9898 form.imd.background=\u80CC\u666F form.imd.correct.kprim=True -form.imd.correct.solution.text=\u6B63\u786E\u7B54\u6848 -form.imd.correct.solution.text.word=$\:form.imd.correct.solution.text (only for Word export) -form.imd.correct.solution.title=\u8868\u5934 +form.imd.correctSolution.text=\u6B63\u786E\u7B54\u6848 +form.imd.correctSolution.text.word=$\:form.imd.correctSolution.text (only for Word export) +form.imd.correctSolution.title=\u8868\u5934 form.imd.correct.spots=Correct spots form.imd.correct.text=\u5BF9\u6240\u6709\u6B63\u786E\u7B54\u6848\u7684\u53CD\u9988 form.imd.correct.title=\u6807\u9898 diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentItemEvent.java b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentItemEvent.java index 69d2a16c6a35a3c09e2f3d1923090bb81cfe9343..eb30942035e049969f0003d5812dbac297f7212c 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentItemEvent.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/events/AssessmentItemEvent.java @@ -36,6 +36,7 @@ public class AssessmentItemEvent extends Event { private static final long serialVersionUID = -1768118856227595311L; public static final String ASSESSMENT_ITEM_CHANGED = "assessment-item-changed"; + public static final String ASSESSMENT_ITEM_NEED_RELOAD = "assessment-item-need-reload"; public static final String ASSESSMENT_ITEM_METADATA_CHANGED = "assessment-item-metadata-changed"; private AssessmentItem item; diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/ChoiceScoreController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/ChoiceScoreController.java index ac1f8b799c9e8324e2eb92b4342ce8aff449edb9..cdf02a06391ac39d9571541f0366ddcea12e6564 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/ChoiceScoreController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/ChoiceScoreController.java @@ -19,6 +19,8 @@ */ package org.olat.ims.qti21.ui.editor.interactions; +import java.io.File; +import java.net.URI; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -32,7 +34,9 @@ import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.CodeHelper; import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.filter.FilterFactory; import org.olat.ims.qti21.model.xml.AssessmentHtmlBuilder; @@ -40,6 +44,8 @@ import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; import org.olat.ims.qti21.model.xml.ScoreBuilder; import org.olat.ims.qti21.model.xml.interactions.ChoiceAssessmentItemBuilder; import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuilder.ScoreEvaluation; +import org.olat.ims.qti21.ui.ResourcesMapper; +import org.olat.ims.qti21.ui.components.FlowFormItem; import org.olat.ims.qti21.ui.editor.AssessmentTestEditorController; import org.olat.ims.qti21.ui.editor.SyncAssessmentItem; import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; @@ -65,21 +71,31 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp private TextElement minScoreEl; private TextElement maxScoreEl; private SingleSelection assessmentModeEl; + private SingleSelection maxChoicesEl, minChoicesEl; private FormLayoutContainer scoreCont; private final List<ChoiceWrapper> wrappers = new ArrayList<>(); + private int count = 0; + private final File itemFileRef; + private final String mapperUri; private final ChoiceAssessmentItemBuilder itemBuilder; private int counter = 0; private final String contextHelpUrl; public ChoiceScoreController(UserRequest ureq, WindowControl wControl, - ChoiceAssessmentItemBuilder itemBuilder, AssessmentItemRef itemRef, boolean restrictedEdit, - String contextHelpUrl) { + ChoiceAssessmentItemBuilder itemBuilder, AssessmentItemRef itemRef, File itemFileRef, + boolean restrictedEdit, String contextHelpUrl) { super(ureq, wControl, itemRef, restrictedEdit); setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale())); this.itemBuilder = itemBuilder; + this.itemFileRef = itemFileRef; this.contextHelpUrl = contextHelpUrl; + + URI assessmentObjectUri = itemFileRef.toURI(); + mapperUri = registerCacheableMapper(null, "ChoiceScoreController::" + CodeHelper.getRAMUniqueID(), + new ResourcesMapper(assessmentObjectUri)); + initForm(ureq); } @@ -98,6 +114,12 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp maxScoreEl.setElementCssClass("o_sel_assessment_item_max_score"); maxScoreEl.setEnabled(!restrictedEdit); + String[] choiceKeys = new String[0]; + String[] choiceValues = new String[0]; + maxChoicesEl = uifactory.addDropdownSingleselect("max.choices", formLayout, choiceKeys, choiceValues, null); + minChoicesEl = uifactory.addDropdownSingleselect("min.choices", formLayout, choiceKeys, choiceValues, null); + updateMinMaxChoices(); + String[] modeValues = new String[]{ translate("form.score.assessment.all.correct"), translate("form.score.assessment.per.answer") @@ -131,6 +153,52 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp uifactory.addFormSubmitButton("submit", buttonsContainer); } + private void updateMinMaxChoices() { + int maxPossibleChoices = itemBuilder.getMaxPossibleCorrectAnswers(); + String[] maxChoiceKeys = new String[maxPossibleChoices]; + String[] maxChoicesValues = new String[maxPossibleChoices]; + for(int i=0; i<maxPossibleChoices; i++) { + maxChoiceKeys[i] = maxChoicesValues[i] = Integer.toString(i); + } + maxChoicesValues[0] = translate("max.choices.unlimited"); + maxChoicesEl.setKeysAndValues(maxChoiceKeys, maxChoicesValues, null); + maxChoicesEl.setVisible(itemBuilder.getMaxPossibleCorrectAnswers() > 1); + + boolean found = false; + String maxChoices = Integer.toString(itemBuilder.getMaxChoices()); + for(String choiceKey:maxChoiceKeys) { + if(choiceKey.equals(maxChoices)) { + maxChoicesEl.select(choiceKey, true); + found = true; + } + } + + if(!found) { + maxChoicesEl.select(maxChoiceKeys[0], true); + } + + String[] minChoiceKeys = new String[maxPossibleChoices]; + String[] minChoicesValues = new String[maxPossibleChoices]; + for(int i=0; i<maxPossibleChoices; i++) { + minChoiceKeys[i] = minChoicesValues[i] = Integer.toString(i); + } + minChoicesValues[0] = translate("min.choices.unlimited"); + minChoicesEl.setKeysAndValues(minChoiceKeys, minChoicesValues, null); + minChoicesEl.setVisible(itemBuilder.getMaxPossibleCorrectAnswers() > 1); + boolean minFound = false; + String minChoices = Integer.toString(itemBuilder.getMinChoices()); + for(String choiceKey:minChoiceKeys) { + if(choiceKey.equals(minChoices)) { + minChoicesEl.select(choiceKey, true); + minFound = true; + } + } + + if(!minFound) { + minChoicesEl.select(maxChoiceKeys[0], true); + } + } + @Override public void sync(UserRequest ureq, AssessmentItemBuilder assessmentItemBuilder) { if(itemBuilder == assessmentItemBuilder) { @@ -149,6 +217,8 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp wrapperIt.remove(); } } + + updateMinMaxChoices(); } } @@ -206,6 +276,14 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp Double maxScore = Double.parseDouble(maxScoreValue); itemBuilder.setMaxScore(maxScore); itemBuilder.setMinScore(new Double(0d)); + if(maxChoicesEl != null && maxChoicesEl.isOneSelected()) { + int maxChoices = Integer.parseInt(maxChoicesEl.getSelectedKey()); + itemBuilder.setMaxChoices(maxChoices); + } + if(minChoicesEl != null && minChoicesEl.isOneSelected()) { + int minChoices = Integer.parseInt(minChoicesEl.getSelectedKey()); + itemBuilder.setMinChoices(minChoices); + } if(assessmentModeEl.isOneSelected() && assessmentModeEl.isSelected(1)) { itemBuilder.setScoreEvaluationMode(ScoreEvaluation.perAnswer); @@ -233,6 +311,7 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp private String summary; private Choice choice; private final TextElement pointsEl; + private FlowFormItem summaryEl; public ChoiceWrapper(Choice choice, TextElement pointsEl) { setChoice(choice); @@ -248,6 +327,10 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp return summary; } + public FlowFormItem getSummaryEl() { + return summaryEl; + } + public TextElement getPointsEl() { return pointsEl; } @@ -259,15 +342,29 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp public void setChoice(Choice choice) { this.choice = choice; if(choice instanceof SimpleChoice) { - String answer = new AssessmentHtmlBuilder().flowStaticString(((SimpleChoice)choice).getFlowStatics()); + SimpleChoice simpleChoice = (SimpleChoice)choice; + String answer = new AssessmentHtmlBuilder().flowStaticString(simpleChoice.getFlowStatics()); answer = FilterFactory.getHtmlTagAndDescapingFilter().filter(answer); answer = answer.trim(); summary = Formatter.truncate(answer, 128); + if(!StringHelper.containsNonWhitespace(summary)) { + summaryEl = new FlowFormItem("summary" + count++, itemFileRef); + summaryEl.setFlowStatics(simpleChoice.getFlowStatics()); + summaryEl.setMapperUri(mapperUri); + scoreCont.add(summaryEl); + } } else if(choice instanceof Hottext) { - String answer = new AssessmentHtmlBuilder().inlineStaticString(((Hottext)choice).getInlineStatics()); + Hottext hottext = (Hottext)choice; + String answer = new AssessmentHtmlBuilder().inlineStaticString(hottext.getInlineStatics()); answer = FilterFactory.getHtmlTagAndDescapingFilter().filter(answer); answer = answer.trim(); summary = Formatter.truncate(answer, 128); + if(!StringHelper.containsNonWhitespace(summary)) { + summaryEl = new FlowFormItem("summary" + count++, itemFileRef); + summaryEl.setInlineStatics(hottext.getInlineStatics()); + summaryEl.setMapperUri(mapperUri); + scoreCont.add(summaryEl); + } } else { summary = ""; } diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBEditorController.java index bfc79d67e54289f854a8d8117bb15ba39615eb60..6e7eef7aaa1baf5e1f2401fe9501c488c0d29bd6 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBEditorController.java @@ -22,7 +22,6 @@ package org.olat.ims.qti21.ui.editor.interactions; import java.io.ByteArrayInputStream; import java.io.File; -import org.apache.commons.lang.StringEscapeUtils; import org.cyberneko.html.parsers.SAXParser; import org.json.JSONException; import org.json.JSONObject; @@ -341,7 +340,7 @@ public class FIBEditorController extends FormBasicController { if("true".equals(solutionEmpty)) { ((TextEntry)entry).setSolution(""); } else { - solution = StringEscapeUtils.unescapeHtml(solution); + solution = itemBuilder.unescapeDataQtiSolution(solution); ((TextEntry)entry).setSolution(solution); } } else if(entry instanceof NumericalEntry) { @@ -369,7 +368,7 @@ public class FIBEditorController extends FormBasicController { if("data-qti-solution".equals(name)) { solution = attributes.getValue(i); if(solution != null) { - solution = StringEscapeUtils.unescapeHtml(solution); + solution = itemBuilder.unescapeDataQtiSolution(solution); } } else if("data-qti-solution-empty".equals(name)) { solutionEmpty = attributes.getValue(i); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBTextEntrySettingsController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBTextEntrySettingsController.java index e6082f0235c71d041337e90920921e5e9f6aaf96..09552b59fb117e9aa062c3f47010531ee90ae1f5 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBTextEntrySettingsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBTextEntrySettingsController.java @@ -19,18 +19,26 @@ */ package org.olat.ims.qti21.ui.editor.interactions; +import java.util.ArrayList; +import java.util.List; + import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.link.Link; 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.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.TextEntry; +import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.TextEntryAlternative; import org.olat.ims.qti21.ui.editor.AssessmentTestEditorController; import uk.ac.ed.ph.jqtiplus.types.Identifier; @@ -47,10 +55,13 @@ public class FIBTextEntrySettingsController extends FormBasicController { private TextElement solutionEl; private TextElement placeholderEl; - private TextElement alternativeEl; private TextElement expectedLengthEl; + private FormLink addFirstAlternative; private MultipleSelectionElement caseSensitiveEl; + private FormLayoutContainer alternativesCont; + private final List<AlternativeRow> alternativeRows = new ArrayList<>(); + private int count = 0; private final boolean restrictedEdit; private final TextEntry interaction; @@ -74,11 +85,26 @@ public class FIBTextEntrySettingsController extends FormBasicController { String placeholder = interaction.getPlaceholder(); placeholderEl = uifactory.addTextElement("fib.placeholder", "fib.placeholder", 256, placeholder, formLayout); placeholderEl.setEnabled(!restrictedEdit); - String alternatives = interaction.alternativesToString(); - alternativeEl = uifactory.addTextElement("fib.alternative", "fib.alternative", 256, alternatives, formLayout); - alternativeEl.setHelpText(translate("fib.alternative.help")); - alternativeEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_fragetypen_fib"); - alternativeEl.setEnabled(!restrictedEdit); + + String alternativesPage = velocity_root + "/fib_alternatives.html"; + alternativesCont = FormLayoutContainer.createCustomFormLayout("alternatives.list", getTranslator(), alternativesPage); + alternativesCont.setRootForm(mainForm); + formLayout.add(alternativesCont); + alternativesCont.setLabel("fib.alternative", null); + alternativesCont.setHelpText(translate("fib.alternative.help")); + alternativesCont.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_fragetypen_fib"); + alternativesCont.contextPut("alternatives", alternativeRows); + + addFirstAlternative = uifactory.addFormLink("add.first.alternative", "add", "", null, alternativesCont, Link.LINK | Link.NONTRANSLATED); + addFirstAlternative.setIconLeftCSS("o_icon o_icon-lg o_icon_add"); + addFirstAlternative.setVisible(!restrictedEdit); + + List<TextEntryAlternative> alternatives = interaction.getAlternatives(); + if(alternatives != null && alternatives.size() > 0) { + for(TextEntryAlternative alternative:alternatives) { + appendAlternative(alternative, null, false); + } + } Integer expectedLength = interaction.getExpectedLength(); String expectedLengthStr = expectedLength == null ? null : expectedLength.toString(); @@ -100,7 +126,7 @@ public class FIBTextEntrySettingsController extends FormBasicController { } uifactory.addFormCancelButton("cancel", buttonsContainer, ureq, getWindowControl()); } - + public String getSolution() { return interaction.getSolution(); } @@ -108,6 +134,49 @@ public class FIBTextEntrySettingsController extends FormBasicController { public Identifier getResponseIdentifier() { return interaction.getResponseIdentifier(); } + + private void appendAlternative(TextEntryAlternative alternative, AlternativeRow previousRow, boolean focus) { + String text = alternative.getAlternative(); + TextElement alternativeEl = uifactory.addTextElement("fib.alternative." + count++, "fib.alternative", 256, text, alternativesCont); + alternativeEl.setDomReplacementWrapperRequired(false); + alternativeEl.setEnabled(!restrictedEdit); + + if(focus) { + solutionEl.setFocus(false); + for(AlternativeRow row:alternativeRows) { + row.getAlternativeEl().setFocus(false); + } + alternativeEl.setFocus(true); + } + + FormLink addButton = null; + if(!restrictedEdit) { + addButton = uifactory.addFormLink("add.alternative." + count++, "add", "", null, alternativesCont, Link.NONTRANSLATED); + addButton.setIconLeftCSS("o_icon o_icon-lg o_icon_add"); + addButton.setVisible(!restrictedEdit); + alternativesCont.add(addButton); + } + + FormLink removeButton = null; + if(!restrictedEdit) { + removeButton = uifactory.addFormLink("remove.alternative." + count++, "rm", "", null, alternativesCont, Link.NONTRANSLATED); + removeButton.setIconLeftCSS("o_icon o_icon-lg o_icon_delete"); + removeButton.setVisible(!restrictedEdit); + alternativesCont.add(removeButton); + } + + AlternativeRow row = new AlternativeRow(alternative, alternativeEl, addButton, removeButton); + if(previousRow == null) { + alternativeRows.add(row); + } else { + int index = alternativeRows.indexOf(previousRow) + 1; + if(index >= 0 && index < alternativeRows.size()) { + alternativeRows.add(index, row); + } else { + alternativeRows.add(row); + } + } + } @Override protected void doDispose() { @@ -135,12 +204,55 @@ public class FIBTextEntrySettingsController extends FormBasicController { return allOk & super.validateFormLogic(ureq); } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source == addFirstAlternative) { + appendAlternative(new TextEntryAlternative(), null, true); + } else if(source instanceof FormLink) { + for(AlternativeRow alternativeRow:alternativeRows) { + if(alternativeRow.getRemoveButton() == source) { + alternativeRows.remove(alternativeRow); + flc.setDirty(true); + break; + } else if(alternativeRow.getAddButton() == source) { + appendAlternative(new TextEntryAlternative(), alternativeRow, true); + break; + } + } + } + super.formInnerEvent(ureq, source, event); + } @Override protected void formOK(UserRequest ureq) { interaction.setSolution(solutionEl.getValue()); interaction.setPlaceholder(placeholderEl.getValue()); - interaction.stringToAlternatives(alternativeEl.getValue()); + List<TextEntryAlternative> alternatives = new ArrayList<>(alternativeRows.size()); + for(AlternativeRow row:alternativeRows) { + TextEntryAlternative alternative = row.getAlternative(); + String val = row.getAlternativeEl().getValue(); + int indexSeparator = val.indexOf(';'); + // Don't split single ;, or ä + if(indexSeparator >= 0 && val.length() > 1 && indexSeparator != val.length() - 1) { + String[] valArr = val.split("[;]"); + for(int i=0;i<valArr.length; i++) { + if(i==0) { + alternative.setAlternative(valArr[i]); + alternatives.add(alternative); + } else { + TextEntryAlternative newAlternative = new TextEntryAlternative(); + newAlternative.setAlternative(valArr[i]); + newAlternative.setScore(alternative.getScore()); + alternatives.add(newAlternative); + } + } + } else { + alternative.setAlternative(val); + alternatives.add(alternative); + } + } + interaction.setAlternatives(alternatives); interaction.setCaseSensitive(caseSensitiveEl.isAtLeastSelected(1)); if(StringHelper.containsNonWhitespace(expectedLengthEl.getValue())) { interaction.setExpectedLength(new Integer(expectedLengthEl.getValue())); @@ -154,4 +266,36 @@ public class FIBTextEntrySettingsController extends FormBasicController { protected void formCancelled(UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); } + + public class AlternativeRow { + + private final TextElement alternativeEl; + private final FormLink addButton, removeButton; + + private final TextEntryAlternative alternative; + + public AlternativeRow(TextEntryAlternative alternative, TextElement alternativeEl, + FormLink addButton, FormLink removeButton) { + this.addButton = addButton; + this.removeButton = removeButton; + this.alternative = alternative; + this.alternativeEl = alternativeEl; + } + + public TextElement getAlternativeEl() { + return alternativeEl; + } + + public TextEntryAlternative getAlternative() { + return alternative; + } + + public FormLink getAddButton() { + return addButton; + } + + public FormLink getRemoveButton() { + return removeButton; + } + } } diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/HotspotEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/HotspotEditorController.java index a23e11da1f277f51f6e9f6cedb469e3f19db3969..ee268dc31202821ddf0aa9676a59db72d30ed9a7 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/HotspotEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/HotspotEditorController.java @@ -41,6 +41,7 @@ import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; +import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; @@ -51,6 +52,7 @@ import org.olat.core.gui.components.link.Link; 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.FileUtils; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.ValidationStatus; @@ -76,6 +78,8 @@ import uk.ac.ed.ph.jqtiplus.types.Identifier; */ public class HotspotEditorController extends FormBasicController { + private static final String[] onKeys = new String[] { "on" }; + private static final Set<String> mimeTypes = new HashSet<>(); static { mimeTypes.add("image/gif"); @@ -87,7 +91,9 @@ public class HotspotEditorController extends FormBasicController { private TextElement titleEl; private RichTextElement textEl; private FileElement backgroundEl; + private SingleSelection resizeEl; private FormLayoutContainer hotspotsCont; + private MultipleSelectionElement responsiveEl; private FormLink newCircleButton, newRectButton; private MultipleSelectionElement correctHotspotsEl; @@ -137,6 +143,12 @@ public class HotspotEditorController extends FormBasicController { formLayout, ureq.getUserSession(), getWindowControl()); textEl.addActionListener(FormEvent.ONCLICK); + responsiveEl = uifactory.addCheckboxesHorizontal("form.imd.responsive", formLayout, onKeys, new String[] {""}); + responsiveEl.setHelpText(translate("form.imd.responsive.hint")); + if(itemBuilder.isResponsive()) { + responsiveEl.select(onKeys[0], true); + } + initialBackgroundImage = getCurrentBackground(); backgroundEl = uifactory.addFileElement(getWindowControl(), "form.imd.background", "form.imd.background", formLayout); backgroundEl.setEnabled(!restrictedEdit); @@ -147,6 +159,15 @@ public class HotspotEditorController extends FormBasicController { backgroundEl.setDeleteEnabled(true); backgroundEl.limitToMimeType(mimeTypes, "error.mimetype", new String[]{ mimeTypes.toString() }); + String[] resizeKeys = new String[] { "no" }; + String[] resizeValues = new String[] { translate("form.imd.background.resize.no") }; + resizeEl = uifactory.addRadiosHorizontal("form.imd.background.resize", formLayout, resizeKeys, resizeValues); + resizeEl.setVisible(false); + if(initialBackgroundImage != null) { + Size size = imageService.getSize(new LocalFileImpl(initialBackgroundImage), null); + optimizeResizeEl(size, false); + } + //responses String page = velocity_root + "/hotspots.html"; hotspotsCont = FormLayoutContainer.createCustomFormLayout("answers", getTranslator(), page); @@ -210,6 +231,14 @@ public class HotspotEditorController extends FormBasicController { backgroundEl.validate(status); allOk &= status.isEmpty(); } + + correctHotspotsEl.clearError(); + if(!restrictedEdit) { + if(correctHotspotsEl.getSelectedKeys().size() == 0) { + correctHotspotsEl.setErrorKey("error.need.correct.answer", null); + allOk &= false; + } + } return allOk & super.validateFormLogic(ureq); } @@ -259,6 +288,8 @@ public class HotspotEditorController extends FormBasicController { if(status.isEmpty()) { flc.setDirty(true); backgroundImage = backgroundEl.moveUploadFileTo(itemFile.getParentFile()); + Size size = imageService.getSize(new LocalFileImpl(backgroundImage), null); + optimizeResizeEl(size, true); } } Size backgroundSize = updateBackground(); @@ -344,26 +375,33 @@ public class HotspotEditorController extends FormBasicController { } if(objectImg != null) { - String filename = objectImg.getName(); + String relativePath = itemFile.getParentFile().toPath().relativize(objectImg.toPath()).toString(); size = imageService.getSize(new LocalFileImpl(objectImg), null); - hotspotsCont.contextPut("filename", filename); - if(size != null) { - if(size.getHeight() > 0) { - hotspotsCont.contextPut("height", Integer.toString(size.getHeight())); - } else { - hotspotsCont.contextRemove("height"); - } - if(size.getWidth() > 0) { - hotspotsCont.contextPut("width", Integer.toString(size.getWidth())); - } else { - hotspotsCont.contextRemove("width"); - } - } + hotspotsCont.contextPut("filename", relativePath); + setBackgroundSize(size); } else { hotspotsCont.contextRemove("filename"); } return size; } + + private void setBackgroundSize(Size size) { + if(size == null) { + hotspotsCont.contextRemove("height"); + hotspotsCont.contextRemove("width"); + } else { + if(size.getHeight() > 0) { + hotspotsCont.contextPut("height", Integer.toString(size.getHeight())); + } else { + hotspotsCont.contextRemove("height"); + } + if(size.getWidth() > 0) { + hotspotsCont.contextPut("width", Integer.toString(size.getWidth())); + } else { + hotspotsCont.contextRemove("width"); + } + } + } @Override protected void formOK(UserRequest ureq) { @@ -371,6 +409,7 @@ public class HotspotEditorController extends FormBasicController { //set the question with the text entries String questionText = textEl.getRawValue(); itemBuilder.setQuestion(questionText); + itemBuilder.setResponsive(responsiveEl.isAtLeastSelected(1)); File objectImg = null; if(backgroundImage != null) { @@ -379,23 +418,81 @@ public class HotspotEditorController extends FormBasicController { objectImg = initialBackgroundImage; } + boolean updateHotspot = true; + if(objectImg != null) { String filename = objectImg.getName(); String mimeType = WebappHelper.getMimeType(filename); - Size size = imageService.getSize(new LocalFileImpl(objectImg), null); + Size currentSize = imageService.getSize(new LocalFileImpl(objectImg), null); + Size size = currentSize; + if(resizeEl.isVisible() && !resizeEl.isSelected(0)) { + int maxSize = Integer.parseInt(resizeEl.getSelectedKey()); + if(maxSize < currentSize.getHeight() || maxSize < currentSize.getWidth()) { + String extension = FileUtils.getFileSuffix(filename); + size = imageService.scaleImage(objectImg, extension, objectImg, maxSize, maxSize, false); + setBackgroundSize(size); + scaleHotspot(currentSize, size); + optimizeResizeEl(size, false); + updateHotspot = false; + } + } + int height = -1; int width = -1; if(size != null) { height = size.getHeight(); width = size.getWidth(); } - itemBuilder.setBackground(filename, mimeType, height, width); + + String relPath = itemFile.getParentFile().toPath().relativize(objectImg.toPath()).toString(); + itemBuilder.setBackground(relPath, mimeType, height, width); + } + + if(updateHotspot) { + updateHotspots(ureq); } - updateHotspots(ureq); fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED, itemBuilder.getAssessmentItem(), QTI21QuestionType.hotspot)); } + private void optimizeResizeEl(Size size, boolean selectSize) { + List<String> keys = new ArrayList<>(); + List<String> values = new ArrayList<>(); + + String selectedSize = null; + for(BackgroundSize availableSize:BackgroundSize.values()) { + int proposedSize = availableSize.size(); + if(proposedSize <= size.getHeight() || proposedSize <= size.getWidth()) { + String s = Integer.toString(availableSize.size()); + keys.add(s); + values.add(s + " x " + s); + if((proposedSize == size.getHeight() && proposedSize >= size.getWidth()) + || (proposedSize == size.getWidth() && proposedSize >= size.getHeight())) { + selectedSize = s; + } + } + } + if(selectedSize == null) { + keys.add(0, "no"); + values.add(0, translate("form.imd.background.resize.no")); + } + resizeEl.setKeysAndValues(keys.toArray(new String[keys.size()]), values.toArray(new String[values.size()]), null); + + if(keys.size() == 1) { + resizeEl.select(keys.get(0), true); + resizeEl.setVisible(false); + } else { + if(selectedSize != null) { + resizeEl.select(selectedSize, true); + } else if(selectSize && keys.size() > 1 && keys.get(1).equals(Integer.toString(BackgroundSize.s1024.size))) { + resizeEl.select(Integer.toString(BackgroundSize.s1024.size), true); + } else { + resizeEl.select(keys.get(0), true); + } + resizeEl.setVisible(true); + } + } + private void updateHotspots(UserRequest ureq) { Map<String,HotspotWrapper> wrapperMap = new HashMap<>(); for(HotspotWrapper wrapper:choiceWrappers) { @@ -421,6 +518,69 @@ public class HotspotEditorController extends FormBasicController { } } + private void scaleHotspot(Size oldSize, Size newSize) { + if(oldSize == null || newSize == null || choiceWrappers.isEmpty()) return; + int oldWidth = oldSize.getWidth(); + int newWidth = newSize.getWidth(); + int oldHeight = oldSize.getHeight(); + int newHeight = newSize.getHeight(); + if(oldWidth <= 0 || oldHeight <= 0 || newWidth <= 0 || newHeight <= 0) return; + + double widthFactor = ((double)oldWidth / newWidth); + double heightFactor = ((double)oldHeight / newHeight); + + for(HotspotWrapper wrapper:choiceWrappers) { + HotspotChoice choice = wrapper.getChoice(); + if(choice != null) { + if(Shape.CIRCLE.equals(choice.getShape())) { + scaleCircle(choice.getCoords(), widthFactor, heightFactor); + } else if(Shape.RECT.equals(choice.getShape())) { + scaleRect(choice.getCoords(), widthFactor, heightFactor); + } + } + } + } + + private void scaleCircle(List<Integer> coords, double widthFactor, double heightFactor) { + if(coords.size() != 3) return; + + int centerX = coords.get(0); + int centerY = coords.get(1); + int radius = coords.get(2); + + if(centerX > 0) { + coords.set(0, (int)Math.round(centerX / widthFactor)); + } + if(centerY > 0) { + coords.set(1, (int)Math.round(centerY / heightFactor)); + } + if(radius > 0) { + coords.set(2, (int)Math.round(radius / widthFactor)); + } + } + + private void scaleRect(List<Integer> coords, double widthFactor, double heightFactor) { + if(coords.size() != 4) return; + + int leftX = coords.get(0); + int topY = coords.get(1); + int rightX = coords.get(2); + int bottomY = coords.get(3); + + if(leftX > 0) { + coords.set(0, (int)Math.round(leftX / widthFactor)); + } + if(topY > 0) { + coords.set(1, (int)Math.round(topY / heightFactor)); + } + if(rightX > 0) { + coords.set(2, (int)Math.round(rightX / widthFactor)); + } + if(bottomY > 0) { + coords.set(3, (int)Math.round(bottomY / heightFactor)); + } + } + /** * If the image is too small, translate the hotspots to match * approximatively the new image. @@ -442,7 +602,7 @@ public class HotspotEditorController extends FormBasicController { translateRect(choice.getCoords(), width, height); } } - } + } } private void translateCircle(List<Integer> coords, int width, int height) { @@ -505,4 +665,20 @@ public class HotspotEditorController extends FormBasicController { coords.set(3, (bottomY - translateY)); } } + + public enum BackgroundSize { + s1024(1024), + s800(800), + s480(480); + + private final int size; + + private BackgroundSize(int size) { + this.size = size; + } + + public int size() { + return size; + } + } } diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java index d075f236618d93f3245f662c0d9d667dcf0e59bf..5b0a038a222b6cc064067d0f88943e36c582f922 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java @@ -33,6 +33,7 @@ import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.form.flexible.impl.elements.richText.TextMode; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; @@ -154,6 +155,7 @@ public class KPrimEditorController extends FormBasicController { String choiceId = "answer" + count++; RichTextElement choiceEl = uifactory.addRichTextElementForQTI21(choiceId, "form.imd.answer", choiceContent, 8, -1, itemContainer, answersCont, ureq.getUserSession(), getWindowControl()); + choiceEl.getEditorConfiguration().setSimplestTextModeAllowed(TextMode.oneLine); choiceEl.setUserObject(choice); answersCont.add("choiceId", choiceEl); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/LobFeedbackEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/LobFeedbackEditorController.java deleted file mode 100644 index 27800c8e87ebaa2a71cbddf86db4e9d449b25092..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/LobFeedbackEditorController.java +++ /dev/null @@ -1,224 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.ims.qti21.ui.editor.interactions; - -import java.io.File; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.form.flexible.FormItemContainer; -import org.olat.core.gui.components.form.flexible.elements.RichTextElement; -import org.olat.core.gui.components.form.flexible.elements.TextElement; -import org.olat.core.gui.components.form.flexible.impl.FormBasicController; -import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; -import org.olat.core.gui.components.form.flexible.impl.elements.richText.RichTextConfiguration; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.util.StringHelper; -import org.olat.core.util.Util; -import org.olat.core.util.filter.FilterFactory; -import org.olat.core.util.vfs.VFSContainer; -import org.olat.ims.qti21.model.xml.ModalFeedbackBuilder; -import org.olat.ims.qti21.model.xml.interactions.LobAssessmentItemBuilder; -import org.olat.ims.qti21.ui.editor.FeedbackEditorController; -import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; - -/** - * - * Initial date: 09.08.2016<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class LobFeedbackEditorController extends FormBasicController { - - private TextElement hintTitleEl; - private RichTextElement hintTextEl; - private TextElement feedbackCorrectSolutionTitleEl; - private RichTextElement feedbackCorrectSolutionTextEl; - private TextElement feedbackTitleEl, feedbackEmptyTitleEl; - private RichTextElement feedbackTextEl, feedbackEmptyTextEl; - - private final File itemFile; - private final File rootDirectory; - private final VFSContainer rootContainer; - private final boolean restrictedEdit; - private final LobAssessmentItemBuilder itemBuilder; - - public LobFeedbackEditorController(UserRequest ureq, WindowControl wControl, LobAssessmentItemBuilder itemBuilder, - File rootDirectory, VFSContainer rootContainer, File itemFile, boolean restrictedEdit) { - super(ureq, wControl, LAYOUT_DEFAULT_2_10); - setTranslator(Util.createPackageTranslator(FeedbackEditorController.class, getLocale(), getTranslator())); - this.itemBuilder = itemBuilder; - this.restrictedEdit = restrictedEdit; - this.itemFile = itemFile; - this.rootDirectory = rootDirectory; - this.rootContainer = rootContainer; - initForm(ureq); - } - - @Override - protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - setFormContextHelp("Test editor QTI 2.1 in detail#details_testeditor_feedback"); - formLayout.setElementCssClass("o_sel_assessment_item_feedbacks"); - - String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString(); - VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath); - - { - ModalFeedbackBuilder hint = itemBuilder.getHint(); - String hintTitle = hint == null ? "" : hint.getTitle(); - hintTitleEl = uifactory.addTextElement("hintTitle", "form.imd.hint.title", -1, hintTitle, formLayout); - hintTitleEl.setElementCssClass("o_sel_assessment_item_hint_title"); - hintTitleEl.setUserObject(hint); - hintTitleEl.setEnabled(!restrictedEdit); - String hintText = hint == null ? "" : hint.getText(); - hintTextEl = uifactory.addRichTextElementForQTI21("hintText", "form.imd.hint.text", hintText, 8, -1, - itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); - hintTextEl.setElementCssClass("o_sel_assessment_item_hint"); - hintTextEl.setEnabled(!restrictedEdit); - hintTextEl.setHelpTextKey("feedback.hint.help", null); - hintTextEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); - RichTextConfiguration hintConfig = hintTextEl.getEditorConfiguration(); - hintConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir - } - - {//correct solution feedback for Word - ModalFeedbackBuilder correctSolutionFeedback = itemBuilder.getCorrectSolutionFeedback(); - String correctSolutionTitle = correctSolutionFeedback == null ? "" : correctSolutionFeedback.getTitle(); - feedbackCorrectSolutionTitleEl = uifactory.addTextElement("correctSolutionTitle", "form.imd.correct.solution.title", -1, correctSolutionTitle, formLayout); - feedbackCorrectSolutionTitleEl.setUserObject(correctSolutionFeedback); - feedbackCorrectSolutionTitleEl.setEnabled(!restrictedEdit); - feedbackCorrectSolutionTitleEl.setElementCssClass("o_sel_assessment_item_correct_solution_title"); - String correctSolutionText = correctSolutionFeedback == null ? "" : correctSolutionFeedback.getText(); - feedbackCorrectSolutionTextEl = uifactory.addRichTextElementForQTI21("correctSolutionText", "form.imd.correct.solution.text.word", correctSolutionText, 8, -1, - itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); - feedbackCorrectSolutionTextEl.setEnabled(!restrictedEdit); - feedbackCorrectSolutionTextEl.setHelpTextKey("feedback.correctsolution.help", null); - feedbackCorrectSolutionTextEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_feedback"); - feedbackCorrectSolutionTextEl.setElementCssClass("o_sel_assessment_item_correct_solution"); - RichTextConfiguration richTextConfig2 = feedbackCorrectSolutionTextEl.getEditorConfiguration(); - richTextConfig2.setFileBrowserUploadRelPath("media");// set upload dir to the media dir - } - - {//feedback if response - ModalFeedbackBuilder answeredFeedback = itemBuilder.getAnsweredFeedback(); - String correctTitle = answeredFeedback == null ? "" : answeredFeedback.getTitle(); - feedbackTitleEl = uifactory.addTextElement("answeredTitle", "form.imd.answered.title", -1, correctTitle, formLayout); - feedbackTitleEl.setUserObject(answeredFeedback); - feedbackTitleEl.setEnabled(!restrictedEdit); - feedbackTitleEl.setElementCssClass("o_sel_assessment_item_answered_feedback_title"); - String correctText = answeredFeedback == null ? "" : answeredFeedback.getText(); - feedbackTextEl = uifactory.addRichTextElementForQTI21("answeredText", "form.imd.answered.text", correctText, 8, -1, - itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); - feedbackTextEl.setEnabled(!restrictedEdit); - feedbackTextEl.setElementCssClass("o_sel_assessment_item_answered_feedback"); - RichTextConfiguration richTextConfig = feedbackTextEl.getEditorConfiguration(); - richTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir - } - - {// feedback if the answer is empty - ModalFeedbackBuilder emptyFeedback = itemBuilder.getEmptyFeedback(); - String emptyTitle = emptyFeedback == null ? "" : emptyFeedback.getTitle(); - feedbackEmptyTitleEl = uifactory.addTextElement("emptyTitle", "form.imd.empty.title", -1, emptyTitle, formLayout); - feedbackEmptyTitleEl.setUserObject(emptyFeedback); - feedbackEmptyTitleEl.setEnabled(!restrictedEdit); - feedbackEmptyTitleEl.setElementCssClass("o_sel_assessment_item_empty_feedback_title"); - String emptyText = emptyFeedback == null ? "" : emptyFeedback.getText(); - feedbackEmptyTextEl = uifactory.addRichTextElementForQTI21("emptyText", "form.imd.empty.text", emptyText, 8, -1, - itemContainer, formLayout, ureq.getUserSession(), getWindowControl()); - feedbackEmptyTextEl.setEnabled(!restrictedEdit); - feedbackEmptyTextEl.setElementCssClass("o_sel_assessment_item_empty_feedback"); - RichTextConfiguration emptyTextConfig = feedbackEmptyTextEl.getEditorConfiguration(); - emptyTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir - } - - // Submit Button - if(!restrictedEdit) { - FormLayoutContainer buttonsContainer = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); - buttonsContainer.setRootForm(mainForm); - formLayout.add(buttonsContainer); - uifactory.addFormSubmitButton("submit", buttonsContainer); - } - } - - @Override - protected void formOK(UserRequest ureq) { - if(restrictedEdit) return; - - String hintTitle = hintTitleEl.getValue(); - String hintText = hintTextEl.getRawValue(); - if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(hintText))) { - ModalFeedbackBuilder hintBuilder = itemBuilder.getHint(); - if(hintBuilder == null) { - hintBuilder = itemBuilder.createHint(); - } - hintBuilder.setTitle(hintTitle); - hintBuilder.setText(hintText); - } else { - itemBuilder.removeHint(); - } - - String correctSolutionTitle = feedbackCorrectSolutionTitleEl.getValue(); - String correctSolutionText = feedbackCorrectSolutionTextEl.getRawValue(); - if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(correctSolutionText))) { - ModalFeedbackBuilder correctSolutionBuilder = itemBuilder.getCorrectSolutionFeedback(); - if(correctSolutionBuilder == null) { - correctSolutionBuilder = itemBuilder.createCorrectSolutionFeedback(); - } - correctSolutionBuilder.setTitle(correctSolutionTitle); - correctSolutionBuilder.setText(correctSolutionText); - } else { - itemBuilder.removeCorrectSolutionFeedback(); - } - - String correctTitle = feedbackTitleEl.getValue(); - String correctText = feedbackTextEl.getRawValue(); - if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(correctText))) { - ModalFeedbackBuilder correctBuilder = itemBuilder.getAnsweredFeedback(); - if(correctBuilder == null) { - correctBuilder = itemBuilder.createAnsweredFeedback(); - } - correctBuilder.setTitle(correctTitle); - correctBuilder.setText(correctText); - } else { - itemBuilder.removeAnsweredFeedback(); - } - - String emptyTitle = feedbackEmptyTitleEl.getValue(); - String emptyText = feedbackEmptyTextEl.getRawValue(); - if(StringHelper.containsNonWhitespace(FilterFactory.getHtmlTagsFilter().filter(emptyText))) { - ModalFeedbackBuilder emptyBuilder = itemBuilder.getEmptyFeedback(); - if(emptyBuilder == null) { - emptyBuilder = itemBuilder.createEmptyFeedback(); - } - emptyBuilder.setTitle(emptyTitle); - emptyBuilder.setText(emptyText); - } else { - itemBuilder.removeEmptyFeedback(); - } - - fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED, itemBuilder.getAssessmentItem())); - } - - - @Override - protected void doDispose() { - // - } -} diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchEditorController.java index 71221c85dc4da95d5a8bb6cf7ab68f0ad351ecf4..bae0eae92dfdda1364eeaa8c77c5ef552ff42de5 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchEditorController.java @@ -243,7 +243,7 @@ public class MatchEditorController extends FormBasicController { } commitTemporaryAssociations(ureq); - + /* if(singleMultiEl.isOneSelected() && singleMultiEl.isSelected(0)) { Map<String,String> sourseTargetMap = new HashMap<>(); String[] directedPairsIds = ureq.getHttpReq().getParameterValues("qtiworks_response_" + itemBuilder.getResponseIdentifier()); @@ -278,6 +278,7 @@ public class MatchEditorController extends FormBasicController { } } } + */ if(layoutEl != null) { layoutEl.clearError(); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchScoreController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchScoreController.java index 41645f6dc62ca1216313fdc53e09f3cab056ed0d..6c451a1c2720f45a4e867176cb1c75b3f12c111f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchScoreController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchScoreController.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -19,6 +20,8 @@ */ package org.olat.ims.qti21.ui.editor.interactions; +import java.io.File; +import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -34,6 +37,8 @@ import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.CodeHelper; +import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.course.assessment.AssessmentHelper; import org.olat.ims.qti21.model.xml.AssessmentHtmlBuilder; @@ -41,6 +46,8 @@ import org.olat.ims.qti21.model.xml.AssessmentItemBuilder; import org.olat.ims.qti21.model.xml.ScoreBuilder; import org.olat.ims.qti21.model.xml.interactions.MatchAssessmentItemBuilder; import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuilder.ScoreEvaluation; +import org.olat.ims.qti21.ui.ResourcesMapper; +import org.olat.ims.qti21.ui.components.FlowFormItem; import org.olat.ims.qti21.ui.editor.AssessmentTestEditorController; import org.olat.ims.qti21.ui.editor.SyncAssessmentItem; import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent; @@ -70,15 +77,24 @@ public class MatchScoreController extends AssessmentItemRefEditorController impl private MatchAssessmentItemBuilder itemBuilder; + private int count = 0; + private final String mapperUri; + private final File itemFileRef; private List<MatchWrapper> sourceWrappers = new ArrayList<>(); private List<MatchWrapper> targetWrappers = new ArrayList<>(); private Map<DirectedPairValue, MatchScoreWrapper> scoreWrappers = new HashMap<>(); public MatchScoreController(UserRequest ureq, WindowControl wControl, MatchAssessmentItemBuilder itemBuilder, - AssessmentItemRef itemRef, boolean restrictedEdit) { + AssessmentItemRef itemRef, File itemFileRef, boolean restrictedEdit) { super(ureq, wControl, itemRef, restrictedEdit); setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale())); this.itemBuilder = itemBuilder; + this.itemFileRef = itemFileRef; + + URI assessmentObjectUri = itemFileRef.toURI(); + mapperUri = registerCacheableMapper(null, "MatchScoreController::" + CodeHelper.getRAMUniqueID(), + new ResourcesMapper(assessmentObjectUri)); + initForm(ureq); } @@ -175,10 +191,10 @@ public class MatchScoreController extends AssessmentItemRefEditorController impl DirectedPairValue dKey = new DirectedPairValue(sourceIdentifier, targetIdentifier); if(!scoreWrappers.containsKey(dKey)) { String key = sourceIdentifier.toString() + "-" + targetIdentifier.toString(); - TextElement textEl = uifactory.addTextElement(key, null, 4, "", scoreCont); + TextElement textEl = uifactory.addTextElement(key, null, 8, "", scoreCont); MatchScoreWrapper scoreWrapper = new MatchScoreWrapper(sourceIdentifier, targetIdentifier, textEl); textEl.setDomReplacementWrapperRequired(false); - textEl.setDisplaySize(4); + textEl.setDisplaySize(5); textEl.setUserObject(scoreWrapper); textEl.setEnabled(!restrictedEdit); @@ -200,9 +216,23 @@ public class MatchScoreController extends AssessmentItemRefEditorController impl allOk &= validateDouble(maxScoreEl); if(assessmentModeEl.isOneSelected() && assessmentModeEl.isSelected(1)) { - /*for(HotspotChoiceWrapper wrapper:wrappers) { - allOk &= validateDouble(wrapper.getPointsEl()); - }*/ + for(Map.Entry<DirectedPairValue, MatchScoreWrapper> entry:scoreWrappers.entrySet()) { + MatchScoreWrapper scoreWrapper = entry.getValue(); + TextElement scoreEl = scoreWrapper.getScoreEl(); + String val = scoreEl.getValue(); + scoreEl.clearError(); + if(StringHelper.containsNonWhitespace(val)) { + try { + Double.parseDouble(val); + } catch (NumberFormatException e) { + scoreEl.setErrorKey("error.double", null); + allOk &= false; + } + } else { + scoreEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + } } return allOk & super.validateFormLogic(ureq); @@ -250,22 +280,32 @@ public class MatchScoreController extends AssessmentItemRefEditorController impl } private MatchWrapper createMatchWrapper(SimpleAssociableChoice choice) { - return new MatchWrapper(choice.getIdentifier(), choice); + FlowFormItem summaryEl = new FlowFormItem("summary_" + count++, itemFileRef); + summaryEl.setFlowStatics(choice.getFlowStatics()); + summaryEl.setMapperUri(mapperUri); + scoreCont.add(summaryEl); + return new MatchWrapper(choice.getIdentifier(), choice, summaryEl); } public static class MatchWrapper { private final Identifier choiceIdentifier; private SimpleAssociableChoice choice; + private final FlowFormItem summaryEl; - public MatchWrapper(Identifier choiceIdentifier, SimpleAssociableChoice choice) { + public MatchWrapper(Identifier choiceIdentifier, SimpleAssociableChoice choice, FlowFormItem summaryEl) { this.choiceIdentifier = choiceIdentifier; this.choice = choice; + this.summaryEl = summaryEl; } public String getSummary() { return new AssessmentHtmlBuilder().flowStaticString(choice.getFlowStatics()); } + + public FlowFormItem getSummaryEl() { + return summaryEl; + } public Identifier getChoiceIdentifier() { return choiceIdentifier; diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java index b75d66233975705df11c738d69467451e3e25f80..de160e8130a0e1cd491f7086da91b5c57d5754cc 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java @@ -33,6 +33,7 @@ import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.form.flexible.impl.elements.richText.TextMode; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; @@ -170,6 +171,7 @@ public class MultipleChoiceEditorController extends FormBasicController { String choiceId = "answer" + count++; RichTextElement choiceEl = uifactory.addRichTextElementForQTI21(choiceId, "form.imd.answer", choiceContent, 8, -1, itemContainer, answersCont, ureq.getUserSession(), getWindowControl()); + choiceEl.getEditorConfiguration().setSimplestTextModeAllowed(TextMode.oneLine); choiceEl.setUserObject(choice); answersCont.add("choiceId", choiceEl); @@ -239,8 +241,10 @@ public class MultipleChoiceEditorController extends FormBasicController { //correct response String[] correctAnswers = ureq.getHttpReq().getParameterValues("correct"); List<Identifier> correctAnswerList = new ArrayList<>(); - for(String correctAnswer:correctAnswers) { - correctAnswerList.add(Identifier.parseString(correctAnswer)); + if(correctAnswers != null) { + for(String correctAnswer:correctAnswers) { + correctAnswerList.add(Identifier.parseString(correctAnswer)); + } } itemBuilder.setCorrectAnswers(correctAnswerList); @@ -294,13 +298,13 @@ public class MultipleChoiceEditorController extends FormBasicController { private void updateCorrectAnswers(UserRequest ureq) { String[] correctAnswers = ureq.getHttpReq().getParameterValues("correct"); + List<Identifier> correctAnswerList = new ArrayList<>(); if(correctAnswers != null) { - List<Identifier> correctAnswerList = new ArrayList<>(); for(String correctAnswer:correctAnswers) { correctAnswerList.add(Identifier.parseString(correctAnswer)); } - itemBuilder.setCorrectAnswers(correctAnswerList); - } + } + itemBuilder.setCorrectAnswers(correctAnswerList); } private void doAddSimpleChoice(UserRequest ureq) { diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java index 0679b526a19c62b73eecbb8c796029a3b4472ba6..c07f9d6df097d530f60dad2298546b0cc7039379 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java @@ -33,6 +33,7 @@ import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.form.flexible.impl.elements.richText.TextMode; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; @@ -166,6 +167,7 @@ public class SingleChoiceEditorController extends FormBasicController { String choiceId = "answer" + count++; RichTextElement choiceEl = uifactory.addRichTextElementForQTI21(choiceId, "form.imd.answer", choiceContent, 8, -1, itemContainer, answersCont, ureq.getUserSession(), getWindowControl()); + choiceEl.getEditorConfiguration().setSimplestTextModeAllowed(TextMode.oneLine); choiceEl.setUserObject(choice); answersCont.add("choiceId", choiceEl); diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/choices_score.html b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/choices_score.html index ecf086035635891291be759cba4bc05db0a7ec1c..8adeebdc2356d23260ce685f528f93872e4a7579 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/choices_score.html +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/choices_score.html @@ -8,7 +8,11 @@ #foreach($choice in $choices) <tr> <td>#if(${choice.isCorrect()}) <i class="o_icon o_icon-lg o_icon_check_on"> </i> #end</td> - <td>$choice.summary</td> + <td>#if($r.isNotNull($choice.summaryEl)) + $r.render($choice.summaryEl) + #else + $choice.summary + #end</td> <td>$r.render($choice.getPointsEl().getComponent().getComponentName()) #if($f.hasError($choice.getPointsEl().getComponent().getComponentName())) <div>$r.render("${choice.getPointsEl().getComponent().getComponentName()}_ERROR")</div> diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/fib_alternatives.html b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/fib_alternatives.html new file mode 100644 index 0000000000000000000000000000000000000000..41b463ea73d11be7aebe8776e21883f1bc023173 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/fib_alternatives.html @@ -0,0 +1,11 @@ +#if($r.isNotEmpty($alternatives)) + #foreach($alternative in $alternatives) + <div class="form-inline o_qti_gaptext_add_alternative"> + $r.render(${alternative.getAlternativeEl()}) + #if($r.isNotNull(${alternative.getAddButton()})) $r.render(${alternative.getAddButton()}) #end + #if($r.isNotNull(${alternative.getRemoveButton()})) $r.render(${alternative.getRemoveButton()}) #end + </div> + #end +#elseif($r.available("add.first.alternative")) + <div class="form-inline o_qti_gaptext_add_first_alternative">$r.render("add.first.alternative")</div> +#end \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/hotspots.html b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/hotspots.html index 2e431d823fb52d06f8f4c5739c98d5d2046e6e95..5de136cbac70c4313276d72e6dcd292008b2ba17 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/hotspots.html +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/hotspots.html @@ -1,7 +1,7 @@ #if($r.visible("new.circle")) <div class="btn-group small o_block_bottom">$r.render("new.circle") $r.render("new.rectangle")</div> #end -<div id="o_qti_hotspots_edit" style="position:relative; #if($width && !${width.isEmpty()}) width:${width}px; #end #if($height && !${height.isEmpty()}) height:${height}px; #end #if($filename && !${filename.isEmpty()}) background-image: url('$mapperUri/$filename'); #end"> +<div id="o_qti_hotspots_edit" style="position:relative; #if($width && !${width.isEmpty()}) width:${width}px; #end #if($height && !${height.isEmpty()}) height:${height}px; #end #if($filename && !${filename.isEmpty()}) background-image: url('$mapperUri/${filename}?t=${r.getUniqueId()}'); #end"> #foreach($hotspot in $hotspots) <input type="hidden" id="${hotspot.identifier}_shape" name="${hotspot.identifier}_shape" value="${hotspot.shape}" /> <input type="hidden" id="${hotspot.identifier}_coords" name="${hotspot.identifier}_coords" value="${hotspot.coords}" /> diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/match_score.html b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/match_score.html index 03cbbdb6b0d328e09e845e4878cfcf6b69ed792c..56689877bf6d96efe3a93fae9931356fe4db25be 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/match_score.html +++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/match_score.html @@ -3,14 +3,14 @@ <tr> <th></th> #foreach($targetChoice in $targetChoices) - <th>${targetChoice.getSummary()} + <th>${r.render($targetChoice.getSummaryEl())} #end </tr> </thead> <tbody> #foreach($sourceChoice in $sourceChoices) <tr> - <th>${sourceChoice.getSummary()}</th> + <th>${r.render($sourceChoice.getSummaryEl())}</th> #set($sourceIndex = ${foreach.index}) #foreach($targetChoice in $targetChoices) <td class="o_sel_match_${sourceIndex}_${foreach.index}"> @@ -19,6 +19,9 @@ #if(${scoreWrapper.isCorrect()}) <i class=" o_icon o_icon-lg o_icon_accept"> </i> #end + #if($f.hasError("${sourceChoice.getChoiceIdentifier().toString()}-${targetChoice.getChoiceIdentifier().toString()}")) + <div>$r.render("${sourceChoice.getChoiceIdentifier().toString()}-${targetChoice.getChoiceIdentifier().toString()}_ERROR")</div> + #end </td> #end </tr> diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java index 28f75e4dd8cf8a6b539a6b1df9ac6ed63ebed49a..db0a7c4e67e7df7508a9c5c5513e583b81f5af78 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java @@ -36,6 +36,7 @@ import org.olat.core.gui.control.controller.BasicController; import org.olat.core.util.StringHelper; import org.olat.ims.qti.statistics.QTIType; import org.olat.ims.qti.statistics.model.StatisticsItem; +import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.QTI21StatisticsManager; import org.olat.ims.qti21.model.QTI21QuestionType; import org.olat.ims.qti21.model.QTI21StatisticSearchParams; @@ -60,6 +61,7 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.MatchInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.TextEntryInteraction; import uk.ac.ed.ph.jqtiplus.node.test.AssessmentItemRef; +import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; /** * @@ -78,15 +80,17 @@ public class QTI21AssessmentItemStatisticsController extends BasicController { private final QTI21StatisticSearchParams searchParams; private final QTI21StatisticResourceResult resourceResult; + private final QTI21ItemBodyController itemBodyCtrl; + @Autowired private QTI21StatisticsManager qtiStatisticsManager; public QTI21AssessmentItemStatisticsController(UserRequest ureq, WindowControl wControl, - AssessmentItemRef itemRef, AssessmentItem item, String sectionTitle, QTI21StatisticResourceResult resourceResult, + AssessmentItemRef itemRef, ResolvedAssessmentItem resolvedAssessmentItem, String sectionTitle, QTI21StatisticResourceResult resourceResult, boolean withFilter, boolean printMode) { super(ureq, wControl); - this.item = item; + item = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode(); this.itemRef = itemRef; this.resourceResult = resourceResult; searchParams = resourceResult.getSearchParams(); @@ -114,6 +118,10 @@ public class QTI21AssessmentItemStatisticsController extends BasicController { mainVC.put("filter", filterCtrl.getInitialComponent()); } + itemBodyCtrl = new QTI21ItemBodyController(ureq, getWindowControl(), itemRef, resolvedAssessmentItem, resourceResult); + listenTo(itemBodyCtrl); + mainVC.put("question", itemBodyCtrl.getInitialComponent()); + putInitialPanel(mainVC); updateData(ureq); } @@ -166,7 +174,8 @@ public class QTI21AssessmentItemStatisticsController extends BasicController { itemRef, item, (ChoiceInteraction)interaction, itemStats, resourceResult); } else if(interaction instanceof MatchInteraction) { String responseIdentifier = interaction.getResponseIdentifier().toString(); - if(responseIdentifier.startsWith("KPRIM_")) { + if(responseIdentifier.startsWith("KPRIM_") + || QTI21QuestionType.hasClass(interaction, QTI21Constants.CSS_MATCH_KPRIM)) { interactionCtrl = new KPrimStatisticsController(ureq, getWindowControl(), itemRef, item, (MatchInteraction)interaction, resourceResult); } else { diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21ItemBodyController.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21ItemBodyController.java new file mode 100644 index 0000000000000000000000000000000000000000..21c70ef6a03cd738a01a535cc24733386c4db3c9 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21ItemBodyController.java @@ -0,0 +1,131 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.ui.statistics; + +import java.io.File; +import java.net.URI; +import java.util.Date; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.CodeHelper; +import org.olat.core.util.Util; +import org.olat.fileresource.types.ImsQTI21Resource; +import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; +import org.olat.ims.qti21.QTI21Service; +import org.olat.ims.qti21.model.InMemoryAssessmentTestSession; +import org.olat.ims.qti21.ui.AssessmentTestDisplayController; +import org.olat.ims.qti21.ui.ResourcesMapper; +import org.olat.ims.qti21.ui.assessment.TerminatedStaticCandidateSessionContext; +import org.olat.ims.qti21.ui.components.ItemBodyResultFormItem; +import org.springframework.beans.factory.annotation.Autowired; + +import uk.ac.ed.ph.jqtiplus.node.test.AssessmentItemRef; +import uk.ac.ed.ph.jqtiplus.notification.NotificationLevel; +import uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder; +import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; +import uk.ac.ed.ph.jqtiplus.running.ItemProcessingInitializer; +import uk.ac.ed.ph.jqtiplus.running.ItemSessionController; +import uk.ac.ed.ph.jqtiplus.running.ItemSessionControllerSettings; +import uk.ac.ed.ph.jqtiplus.state.ItemProcessingMap; +import uk.ac.ed.ph.jqtiplus.state.ItemSessionState; +import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; + +/** + * The controller is used as wrapper for the item body + * form item. + * + * Initial date: 19 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QTI21ItemBodyController extends FormBasicController { + + private final String mapperUri; + private final URI assessmentObjectUri; + private final ResourceLocator inputResourceLocator; + private final ItemSessionController itemSessionController; + private final ResolvedAssessmentItem resolvedAssessmentItem; + + @Autowired + private QTI21Service qtiService; + + public QTI21ItemBodyController(UserRequest ureq, WindowControl wControl, + AssessmentItemRef itemRef, ResolvedAssessmentItem resolvedAssessmentItem, QTI21StatisticResourceResult resourceResult) { + super(ureq, wControl, LAYOUT_BAREBONE); + setTranslator(Util.createPackageTranslator(AssessmentTestDisplayController.class, getLocale(), getTranslator())); + + this.resolvedAssessmentItem = resolvedAssessmentItem; + itemSessionController = createNewItemSessionStateAndController(); + + File itemFileRef = resourceResult.getAssessmentItemFile(itemRef); + File fUnzippedDirRoot = resourceResult.getUnzippedDirectory(); + ResourceLocator fileResourceLocator = new PathResourceLocator(fUnzippedDirRoot.toPath()); + inputResourceLocator = ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator); + assessmentObjectUri = itemFileRef.toURI(); + mapperUri = registerCacheableMapper(null, "QTI21StatisticsElement::" + CodeHelper.getRAMUniqueID(), + new ResourcesMapper(assessmentObjectUri)); + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + ItemBodyResultFormItem questionItem = new ItemBodyResultFormItem("question", resolvedAssessmentItem); + questionItem.setItemSessionState(itemSessionController.getItemSessionState()); + questionItem.setCandidateSessionContext(new TerminatedStaticCandidateSessionContext(new InMemoryAssessmentTestSession())); + questionItem.setResourceLocator(inputResourceLocator); + questionItem.setAssessmentObjectUri(assessmentObjectUri); + questionItem.setMapperUri(mapperUri); + formLayout.add(questionItem); + } + + private ItemSessionController createNewItemSessionStateAndController() { + /* Resolve the underlying JQTI+ object */ + final ItemProcessingMap itemProcessingMap = new ItemProcessingInitializer(resolvedAssessmentItem, true).initialize(); + + /* Create fresh state for session */ + final ItemSessionState itemSessionState = new ItemSessionState(); + final ItemSessionControllerSettings itemSessionControllerSettings = new ItemSessionControllerSettings(); + itemSessionControllerSettings.setTemplateProcessingLimit(25); + itemSessionControllerSettings.setMaxAttempts(10); + + /* Create controller and wire up notification recorder */ + final ItemSessionController sessionController = new ItemSessionController(qtiService.jqtiExtensionManager(), + itemSessionControllerSettings, itemProcessingMap, itemSessionState); + sessionController.addNotificationListener(new NotificationRecorder(NotificationLevel.ERROR)); + + sessionController.initialize(new Date()); + return sessionController; + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + // + } +} diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java index a66d7a8bdea1faecc1c2f1af9c8ace60dd9154ac..b433469c1f0c4185be8f29f540fc960d85909719 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java @@ -146,6 +146,10 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { return new File(itemUri); } + public File getUnzippedDirectory() { + return FileResourceManager.getInstance().unzipFileResource(testEntry.getOlatResource()); + } + public boolean canViewAnonymousUsers() { return secCallback.canViewAnonymousUsers(); } @@ -348,8 +352,7 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { private Controller createAssessmentItemController(UserRequest ureq, WindowControl wControl, AssessmentItemRef assessmentItemRef, String sectionTitle, boolean printMode) { ResolvedAssessmentItem resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(assessmentItemRef); - AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode(); - Controller ctrl = new QTI21AssessmentItemStatisticsController(ureq, wControl, assessmentItemRef, assessmentItem, sectionTitle, this, withFilter, printMode); + Controller ctrl = new QTI21AssessmentItemStatisticsController(ureq, wControl, assessmentItemRef, resolvedAssessmentItem, sectionTitle, this, withFilter, printMode); String iconCssClass = "o_mi_qtisc"; if(courseNode != null) { ctrl = TitledWrapperHelper.getWrapper(ureq, wControl, ctrl, courseNode, iconCssClass); diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/print.html b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/print.html index ca3a74b41cf63de9d547d92267343d419bf4e1f8..d30bd838cf063b12196c565b7a512da78f7b7044 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/print.html +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/print.html @@ -9,6 +9,7 @@ #end <script type='text/javascript'> /* <![CDATA[ */ - window.print(); + ## Execute deferred. Gives browser the time to finish the page rendering first before executing the print dialog. + jQuery(function() {window.print();}); /* ]]> */ </script> \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html index 6997a37d561ae50d3da884b4f4b9b99b541a5bbf..2160d3f7192f7eb4502f43de2237a4ce7fe7c592 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html @@ -4,15 +4,15 @@ </div> #end +#if($sectionTitle) +<h5>$r.translate("section"): $r.escapeHtml($sectionTitle)</h5> +#end +<h3><i class="o_icon $itemCss""> </i> $r.escapeHtml($title)</h3> +#if($r.available("question")) + <h4>$r.translate("chart.item")</h4> + <div id="itemBody" class="clearfix">$r.render("question")</div> +#end <div class="o_qti_statistics"> - #if($sectionTitle) - <h5>$r.translate("section"): $r.escapeHtml($sectionTitle)</h5> - #end - <h3><i class="o_icon $itemCss""> </i> $r.escapeHtml($title)</h3> - #if($r.isNotEmpty($question)) - <h4>$r.translate("chart.item")</h4> - <div class="o_qti_statistics_question clearfix">$r.escapeHtml($question)</div> - #end <h4>$r.translate("fig.title")</h4> <table class="o_qti_statistics_figures"><tbody> #if($numOfParticipants) diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_en.properties index 4ea1a0b3fda978c641d4b8b49c3d86d5813f7a95..3a3f1721bea63d2f3aa8c67d276641371b8856c1 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_en.properties @@ -1,8 +1,11 @@ -#Fri May 06 15:54:01 CEST 2016 +#Mon Jul 17 21:13:47 CEST 2017 answer.correct=$org.olat.ims.qti.statistics.ui\:answer.correct answer.false=$org.olat.ims.qti.statistics.ui\:answer.false answer.noanswer=$org.olat.ims.qti.statistics.ui\:answer.noanswer answer.points=$org.olat.ims.qti.statistics.ui\:answer.points +associateInteraction=Associate +chart.answer.averageScoreQuestions.y=$org.olat.ims.qti.statistics.ui\:chart.answer.averageScoreQuestions.y +chart.averagescore.peritem=$org.olat.ims.qti.statistics.ui\:chart.averagescore.peritem chart.cutscore=$org.olat.ims.qti.statistics.ui\:chart.cutscore chart.duration.histogramm=$org.olat.ims.qti.statistics.ui\:chart.duration.histogramm chart.duration.histogramm.legend=$org.olat.ims.qti.statistics.ui\:chart.duration.histogramm.legend @@ -12,8 +15,11 @@ chart.percent.participants=$org.olat.ims.qti.statistics.ui\:chart.percent.partic chart.percent.participants.num=$org.olat.ims.qti.statistics.ui\:chart.percent.participants.num chart.points=$org.olat.ims.qti.statistics.ui\:chart.points chart.responses=$org.olat.ims.qti.statistics.ui\:chart.responses +chart.rightanswers.peritem=$org.olat.ims.qti.statistics.ui\:chart.rightanswers.peritem chart.score.histogramm=$org.olat.ims.qti.statistics.ui\:chart.score.histogramm download.raw.data=$org.olat.ims.qti.statistics.ui\:download.raw.data +drawingInteraction=$org.olat.ims.qti21.ui.editor\:new.drawing +extendedTextInteraction=$org.olat.ims.qti21.ui.editor\:new.essay fib.wrong.answer=$org.olat.ims.qti.statistics.ui\:fib.wrong.answer fig.averagedur=$org.olat.ims.qti.statistics.ui\:fig.averagedur fig.averagescore=$org.olat.ims.qti.statistics.ui\:fig.averagescore @@ -33,21 +39,19 @@ fig.surveyId=$org.olat.ims.qti.statistics.ui\:fig.surveyId fig.testId=$org.olat.ims.qti.statistics.ui\:fig.testId fig.title=$org.olat.ims.qti.statistics.ui\:fig.title fig.wronganswers=$org.olat.ims.qti.statistics.ui\:fig.wronganswers -menu.title=$org.olat.ims.qti.statistics.ui\:menu.title -section=$org.olat.ims.qti.statistics.ui\:section -stats.unsupported.interaction={0} is not supported. -associateInteraction=Associate gapMatchInteraction=Gap match -inlineChoiceInteraction=Inline choice -sliderInteraction=Slider -selectPointInteraction=Select point -graphicOrderInteraction=Graphic order graphicAssociateInteraction=Graphic associate graphicGapMatchInteraction=Graphic gap match -positionObjectInteraction=Position object -mediaInteraction=Media +graphicOrderInteraction=Graphic order hotspotInteraction=$org.olat.ims.qti21.ui.editor\:new.hotspot -drawingInteraction=$org.olat.ims.qti21.ui.editor\:new.drawing +hottextInteraction=Hottext +inlineChoiceInteraction=Inline choice +mediaInteraction=Media +menu.title=$org.olat.ims.qti.statistics.ui\:menu.title +positionObjectInteraction=Position object +section=$org.olat.ims.qti.statistics.ui\:section +selectPointInteraction=Select point +sliderInteraction=Slider +stats.unsupported.interaction={0} is not supported. uploadInteraction=$org.olat.ims.qti21.ui.editor\:new.upload -extendedTextInteraction=$org.olat.ims.qti21.ui.editor\:new.essay -hottextInteraction=Hottext \ No newline at end of file +user.not.answer=$org.olat.ims.qti.statistics.ui\:user.not.answer diff --git a/src/main/java/org/olat/ldap/LDAPEvent.java b/src/main/java/org/olat/ldap/LDAPEvent.java index bb0ba1795611787dfe84e8edf600d71f7ada49fa..77d2f130b545789df715e74a2892daeba6efb71c 100644 --- a/src/main/java/org/olat/ldap/LDAPEvent.java +++ b/src/main/java/org/olat/ldap/LDAPEvent.java @@ -39,7 +39,6 @@ public class LDAPEvent extends MultiUserEvent { public static final String SYNCHING = "synching"; public static final String DO_SYNCHING = "do_synching"; - public static final String DO_FULL_SYNCHING = "do_full_synching"; public static final String SYNCHING_ENDED = "synching_ended"; private boolean success; diff --git a/src/main/java/org/olat/ldap/LDAPLoginManager.java b/src/main/java/org/olat/ldap/LDAPLoginManager.java index 7ffac3daf83c1a548b4e78faa09957553eefbd60..2faaa37e0c540dffb1c15d003fa007cbd5e24445 100644 --- a/src/main/java/org/olat/ldap/LDAPLoginManager.java +++ b/src/main/java/org/olat/ldap/LDAPLoginManager.java @@ -27,6 +27,7 @@ import java.util.Map; import javax.naming.directory.Attributes; import javax.naming.ldap.LdapContext; +import org.olat.basesecurity.IdentityRef; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.util.resource.OresHelper; @@ -43,6 +44,9 @@ public interface LDAPLoginManager { public boolean changePassword(Identity identity, String pwd, LDAPError errors); + + public Identity createAndPersistUser(String uid); + public Identity createAndPersistUser(Attributes userAttributes); public Map<String,String> prepareUserPropertyForSync(Attributes attributes, Identity identity); @@ -51,11 +55,13 @@ public interface LDAPLoginManager { public Identity findIdentityByLdapAuthentication(Attributes attrs, LDAPError errors); - public void syncUser(Map<String,String> olatPropertyMap, Identity identity); + public Identity syncUser(Map<String,String> olatPropertyMap, IdentityRef identity); + + public void syncUserGroups(Identity identity); public void deletIdentities(List<Identity> identityList); - public boolean doBatchSync(LDAPError errors, boolean full); + public boolean doBatchSync(LDAPError errors); public Date getLastSyncDate(); @@ -64,6 +70,14 @@ public interface LDAPLoginManager { public void freeSyncLock(); public void doSyncSingleUser(Identity ident); + + /** + * A filter is build from the login attribute value and the resulting + * attributes are sync to the specified identity. + * + * @param ident The identity to synchronize + */ + public void doSyncSingleUserWithLoginAttribute(Identity ident); public void removeFallBackAuthentications(); diff --git a/src/main/java/org/olat/ldap/LDAPLoginModule.java b/src/main/java/org/olat/ldap/LDAPLoginModule.java index e3e351c848611a27d45ce718e5e510d73138c056..839b802b92f8e3af7a979f6ee198bb91e8f251a4 100644 --- a/src/main/java/org/olat/ldap/LDAPLoginModule.java +++ b/src/main/java/org/olat/ldap/LDAPLoginModule.java @@ -20,11 +20,14 @@ package org.olat.ldap; +import static org.quartz.CronScheduleBuilder.cronSchedule; +import static org.quartz.JobBuilder.newJob; +import static org.quartz.TriggerBuilder.newTrigger; + import java.io.FileInputStream; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.X509Certificate; -import java.text.ParseException; import java.util.Date; import java.util.Enumeration; @@ -35,10 +38,9 @@ import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; -import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.Scheduler; -import org.quartz.SchedulerException; +import org.quartz.Trigger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -267,21 +269,23 @@ public class LDAPLoginModule extends AbstractSpringModule { private void initCronSyncJob() { try { // Create job with cron trigger configuration - JobDetail jobDetail = new JobDetail("LDAP_Cron_Syncer_Job", Scheduler.DEFAULT_GROUP, LDAPUserSynchronizerJob.class); - CronTrigger trigger = new CronTrigger(); - trigger.setName("LDAP_Cron_Syncer_Trigger"); - trigger.setCronExpression(ldapSyncCronSyncExpression); + JobDetail jobDetail = newJob(LDAPUserSynchronizerJob.class) + .withIdentity("LDAP_Cron_Syncer_Job", Scheduler.DEFAULT_GROUP) + .build(); + Trigger trigger = newTrigger() + .withIdentity("LDAP_Cron_Syncer_Trigger") + .withSchedule(cronSchedule(ldapSyncCronSyncExpression)) + .build(); + // Schedule job now scheduler.scheduleJob(jobDetail, trigger); log.info("LDAP cron syncer is enabled with expression::" + ldapSyncCronSyncExpression); - } catch (ParseException e) { + } catch (Exception e) { setLdapSyncCronSync(false); log.error("LDAP configuration in attribute 'ldapSyncCronSyncExpression' is not valid (" + ldapSyncCronSyncExpression + "). See http://quartz.sourceforge.net/javadoc/org/quartz/CronTrigger.html to learn more about the cron syntax. Disabling LDAP cron syncing", e); - } catch (SchedulerException e) { - log.error("Error while scheduling LDAP cron sync job. Disabling LDAP cron syncing", e); } } diff --git a/src/main/java/org/olat/ldap/LDAPUserSynchronizerJob.java b/src/main/java/org/olat/ldap/LDAPUserSynchronizerJob.java index 065171d864aaa0ced0ad8e1c5a040446c8d6d858..978075c96b602fc6b52d930b4756366d53ede6ec 100644 --- a/src/main/java/org/olat/ldap/LDAPUserSynchronizerJob.java +++ b/src/main/java/org/olat/ldap/LDAPUserSynchronizerJob.java @@ -19,9 +19,6 @@ */ package org.olat.ldap; -import java.util.Calendar; -import java.util.Date; - import org.olat.core.CoreSpringFactory; import org.olat.core.commons.services.scheduler.JobWithDB; import org.quartz.JobExecutionContext; @@ -37,28 +34,17 @@ import org.quartz.JobExecutionException; * @author gnaegi */ public class LDAPUserSynchronizerJob extends JobWithDB { - - private static Date lastFullSync; /** * @see org.olat.core.commons.services.scheduler.JobWithDB#executeWithDB(org.quartz.JobExecutionContext) */ - public void executeWithDB(JobExecutionContext arg0) throws JobExecutionException { + public void executeWithDB(JobExecutionContext arg0) + throws JobExecutionException { try { log.info("Starting LDAP user synchronize job"); LDAPError errors = new LDAPError(); LDAPLoginManager ldapLoginManager = CoreSpringFactory.getImpl(LDAPLoginManager.class); - boolean full; - - Calendar fullLimit = Calendar.getInstance(); - fullLimit.add(Calendar.HOUR_OF_DAY, -12); - if(lastFullSync == null || lastFullSync.before(fullLimit.getTime())) { - full = true; - lastFullSync = new Date(); - } else { - full = false; - } - boolean allOk = ldapLoginManager.doBatchSync(errors, full); + boolean allOk = ldapLoginManager.doBatchSync(errors); if(allOk) { log.info("LDAP user synchronize job finished successfully"); } else { @@ -67,7 +53,6 @@ public class LDAPUserSynchronizerJob extends JobWithDB { } catch (Exception e) { // ups, something went completely wrong! We log this but continue next time log.error("Erron while synchronizeing LDAP users", e); - } - // db closed by JobWithDB class + } } } diff --git a/src/main/java/org/olat/ldap/manager/LDAPDAO.java b/src/main/java/org/olat/ldap/manager/LDAPDAO.java index 07429db9d2512fd2233b1f7db55ee1485ae76c0b..9c1e9390a073ebd22039bc0ef63e6e9ab88c75e2 100644 --- a/src/main/java/org/olat/ldap/manager/LDAPDAO.java +++ b/src/main/java/org/olat/ldap/manager/LDAPDAO.java @@ -30,6 +30,7 @@ import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.SizeLimitExceededException; import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; @@ -38,8 +39,6 @@ import javax.naming.ldap.LdapContext; import javax.naming.ldap.PagedResultsControl; import javax.naming.ldap.PagedResultsResponseControl; -import net.fortuna.ical4j.util.TimeZones; - import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; @@ -51,6 +50,8 @@ import org.olat.ldap.model.LDAPUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import net.fortuna.ical4j.util.TimeZones; + /** * * Initial date: 24.11.2014<br> @@ -90,6 +91,30 @@ public class LDAPDAO { return ldapGroups; } + public List<LDAPGroup> searchGroups(LdapContext ctx, List<String> groupDNs, String filter) { + final List<LDAPGroup> ldapGroups = new ArrayList<>(); + String[] groupAttributes = new String[]{ "cn" }; + for(String groupDN:groupDNs) { + LDAPVisitor visitor = new LDAPVisitor() { + @Override + public void visit(SearchResult searchResult) throws NamingException { + Attributes resAttributes = searchResult.getAttributes(); + Attribute cnAttr = resAttributes.get("cn"); + + Object cn = cnAttr.get(); + if(cn instanceof String) { + LDAPGroup group = new LDAPGroup(); + group.setCommonName((String)cn); + ldapGroups.add(group); + } + } + + }; + search(visitor, groupDN, filter, groupAttributes, ctx); + } + return ldapGroups; + } + public void search(LDAPVisitor visitor, String ldapBase, String filter, String[] returningAttrs, LdapContext ctx) { SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); @@ -217,7 +242,7 @@ public class LDAPDAO { return userDN; } - private String buildSearchUserFilter(String attribute, String uid) { + protected String buildSearchUserFilter(String attribute, String uid) { String ldapUserFilter = syncConfiguration.getLdapUserFilter(); StringBuilder filter = new StringBuilder(); if (ldapUserFilter != null) { diff --git a/src/main/java/org/olat/ldap/manager/LDAPLoginManagerImpl.java b/src/main/java/org/olat/ldap/manager/LDAPLoginManagerImpl.java index d4d4c7cfbad6e1bf476e143a9321ba433637a2c9..555fda1b2e513d2e809b6899bd99cac92fe44d0d 100644 --- a/src/main/java/org/olat/ldap/manager/LDAPLoginManagerImpl.java +++ b/src/main/java/org/olat/ldap/manager/LDAPLoginManagerImpl.java @@ -40,6 +40,7 @@ import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; +import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.Control; import javax.naming.ldap.InitialLdapContext; @@ -52,7 +53,9 @@ import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityModule; import org.olat.basesecurity.Constants; import org.olat.basesecurity.GroupRoles; +import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.SecurityGroup; +import org.olat.basesecurity.model.IdentityRefImpl; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.services.taskexecutor.TaskExecutorManager; @@ -147,9 +150,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe batchSyncIsRunning = false; lastSyncDate = ((LDAPEvent)event).getTimestamp(); } else if(LDAPEvent.DO_SYNCHING.equals(event.getCommand())) { - doHandleBatchSync(false); - } else if(LDAPEvent.DO_FULL_SYNCHING.equals(event.getCommand())) { - doHandleBatchSync(true); + doHandleBatchSync(); } } else if(event instanceof FrameworkStartedEvent) { try { @@ -173,7 +174,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe // Start LDAP cron sync job if (ldapLoginModule.isLdapSyncCronSync()) { LDAPError errors = new LDAPError(); - if (doBatchSync(errors, true)) { + if (doBatchSync(errors)) { log.info("LDAP start sync: users synced"); } else { log.warn("LDAP start sync error: " + errors.get()); @@ -184,14 +185,15 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe } } - private void doHandleBatchSync(final boolean full) { + private void doHandleBatchSync() { //fxdiff: also run on nodes != 1 as nodeid = tomcat-id in fx-environment // if(WebappHelper.getNodeId() != 1) return; Runnable batchSyncTask = new Runnable() { + @Override public void run() { LDAPError errors = new LDAPError(); - doBatchSync(errors, full); + doBatchSync(errors); } }; taskExecutorManager.execute(batchSyncTask); @@ -443,11 +445,13 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe * @param identity Identity to sync */ @Override - public void syncUser(Map<String, String> olatPropertyMap, Identity identity) { - if (identity == null) { + public Identity syncUser(Map<String, String> olatPropertyMap, IdentityRef identityRef) { + if (identityRef == null) { log.warn("Identiy is null - should not happen", null); - return; + return null; } + + Identity identity = securityManager.loadIdentityByKey(identityRef.getKey()); User user = identity.getUser(); // remove user identifyer - can not be changed later olatPropertyMap.remove(LDAPConstants.LDAP_USER_IDENTIFYER); @@ -480,6 +484,26 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe } } userManager.updateUser(user); + return identity; + } + + @Override + public Identity createAndPersistUser(String uid) { + String ldapUserIDAttribute = syncConfiguration.getOlatPropertyToLdapAttribute(LDAPConstants.LDAP_USER_IDENTIFYER); + String filter = ldapDao.buildSearchUserFilter(ldapUserIDAttribute, uid); + LdapContext ctx = bindSystem(); + String userDN = ldapDao.searchUserDNByUid(uid, ctx); + log.info("create and persist user identifier by userDN: " + userDN + " with filter: " + filter); + LDAPUserVisitor visitor = new LDAPUserVisitor(syncConfiguration); + ldapDao.search(visitor, userDN, filter, syncConfiguration.getUserAttributes(), ctx); + + Identity newIdentity = null; + List<LDAPUser> ldapUser = visitor.getLdapUserList(); + if(ldapUser != null && ldapUser.size() > 0) { + Attributes userAttributes = ldapUser.get(0).getAttributes(); + newIdentity = createAndPersistUser(userAttributes); + } + return newIdentity; } /** @@ -640,6 +664,89 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe } } + /** + * The method search in LDAP the user, search the groups + * of which it is member of, and sync the groups. + * + * @param identity The identity to sync + */ + @Override + public void syncUserGroups(Identity identity) { + LdapContext ctx = bindSystem(); + if (ctx == null) { + log.error("could not bind to ldap", null); + } + + String ldapUserIDAttribute = syncConfiguration.getOlatPropertyToLdapAttribute(LDAPConstants.LDAP_USER_IDENTIFYER); + String filter = ldapDao.buildSearchUserFilter(ldapUserIDAttribute, identity.getName()); + + boolean withCoacheOfGroups = StringHelper.containsNonWhitespace(syncConfiguration.getCoachedGroupAttribute()); + List<String> ldapBases = syncConfiguration.getLdapBases(); + String[] searchAttr; + if(withCoacheOfGroups) { + searchAttr = new String[]{ "dn", syncConfiguration.getCoachedGroupAttribute() }; + } else { + searchAttr = new String[]{ "dn" }; + } + + SearchControls ctls = new SearchControls(); + ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); + ctls.setReturningAttributes(searchAttr); + + String userDN = null; + List<String> groupList = null; + for (String ldapBase : ldapBases) { + try { + NamingEnumeration<SearchResult> enm = ctx.search(ldapBase, filter, ctls); + while (enm.hasMore()) { + SearchResult result = enm.next(); + userDN = result.getNameInNamespace(); + + if(withCoacheOfGroups) { + Attributes resAttributes = result.getAttributes(); + Attribute coachOfGroupsAttr = resAttributes.get(syncConfiguration.getCoachedGroupAttribute()); + if(coachOfGroupsAttr != null && coachOfGroupsAttr.get() instanceof String) { + String groupString = (String)coachOfGroupsAttr.get(); + if(!"-".equals(groupString)) { + String[] groupArr = groupString.split(syncConfiguration.getCoachedGroupAttributeSeparator()); + groupList = new ArrayList<>(groupArr.length); + for(String group:groupArr) { + groupList.add(group); + } + } + } + } + } + if (userDN != null) { + break; + } + } catch (NamingException e) { + log.error("NamingException when trying to bind user with username::" + identity.getName() + " on ldapBase::" + ldapBase, e); + } + } + + // get the potential groups + if(userDN != null) { + List<String> groupDNs = syncConfiguration.getLdapGroupBases(); + String groupFilter = "(&(objectClass=groupOfNames)(member=" + userDN + "))"; + List<LDAPGroup> groups = ldapDao.searchGroups(ctx, groupDNs, groupFilter); + for(LDAPGroup group:groups) { + BusinessGroup managedGroup = getManagerBusinessGroup(group.getCommonName()); + if(managedGroup != null) { + List<String> roles = businessGroupRelationDao.getRoles(identity, managedGroup); + if(roles.isEmpty()) { + boolean coach = groupList != null && groupList.contains(group.getCommonName()); + if(coach) { + businessGroupRelationDao.addRole(identity, managedGroup, GroupRoles.coach.name()); + } else { + businessGroupRelationDao.addRole(identity, managedGroup, GroupRoles.participant.name()); + } + } + } + } + } + } + /** * Searches for Identity in OLAT. * @@ -661,7 +768,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe String uid = getAttributeValue(attrs.get(syncConfiguration .getOlatPropertyToLdapAttribute(LDAPConstants.LDAP_USER_IDENTIFYER))); String token = getAttributeValue(attrs.get(syncConfiguration.getLdapUserLoginAttribute())); - + Identity identity = securityManager.findIdentityByNameCaseInsensitive(uid); if (identity == null) { return null; @@ -671,7 +778,9 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe log.error("Error getting user from OLAT security group '" + LDAPConstants.SECURITY_GROUP_LDAP + "' : group does not exist", null); return null; } - if (securityManager.isIdentityInSecurityGroup(identity, ldapGroup)) { + + boolean inSecurityGroup = securityManager.isIdentityInSecurityGroup(identity, ldapGroup); + if (inSecurityGroup) { Authentication ldapAuth = securityManager.findAuthentication(identity, LDAPAuthenticationController.PROVIDER_LDAP); if(ldapAuth == null) { //BUG Fixe: update the user and test if it has a ldap provider @@ -764,7 +873,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe * */ @Override - public boolean doBatchSync(LDAPError errors, boolean full) { + public boolean doBatchSync(LDAPError errors) { //fxdiff: also run on nodes != 1 as nodeid = tomcat-id in fx-environment // if(WebappHelper.getNodeId() != 1) { // log.warn("Sync happens only on node 1", null); @@ -792,14 +901,13 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe coordinator.getEventBus().fireEventToListenersOf(new LDAPEvent(LDAPEvent.SYNCHING), ldapSyncLockOres); - if(full) { - lastSyncDate = null; - } + lastSyncDate = null; LdapContext ctx = null; boolean success = false; try { acquireSyncLock(); + long startTime = System.currentTimeMillis(); ctx = bindSystem(); if (ctx == null) { errors.insert("LDAP connection ERROR"); @@ -812,7 +920,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe //check server capabilities // Get time before sync to have a save sync time when sync is successful - String sinceSentence = (lastSyncDate == null ? " (full sync)" : " since last sync from " + lastSyncDate); + String sinceSentence = (lastSyncDate == null ? "" : " since last sync from " + lastSyncDate); doBatchSyncDeletedUsers(ctx, sinceSentence); // bind again to use an initial unmodified context. lookup of server-properties might fail otherwise! ctx.close(); @@ -831,6 +939,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe ctx.close(); success = true; + log.audit("LDAP batch sync done: " + success + " in " + ((System.currentTimeMillis() - startTime) / 1000) + "s"); return success; } catch (Exception e) { @@ -949,9 +1058,10 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe } private void syncRole(LDAPUser ldapUser, String role) { - Identity identity = ldapUser.getCachedIdentity(); - List<String> roleList = securityManager.getRolesAsString(identity); + IdentityRef identityRef = ldapUser.getCachedIdentity(); + List<String> roleList = securityManager.getRolesAsString(identityRef); if(!roleList.contains(role)) { + Identity identity = securityManager.loadIdentityByKey(identityRef.getKey()); Roles roles = securityManager.getRoles(identity); switch(role) { case Constants.GROUP_AUTHORS: @@ -1029,6 +1139,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe + users.toString() + "]"); } } + dbInstance.commitAndCloseSession(); } private List<LDAPUser> doBatchSyncNewAndModifiedUsers(LdapContext ctx, String sinceSentence, Map<String,LDAPUser> dnToIdentityKeyMap, LDAPError errors) { @@ -1038,7 +1149,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe // Check for new and modified users List<LDAPUser> newLdapUserList = new ArrayList<LDAPUser>(); - Map<Identity, Map<String, String>> changedMapIdentityMap = new HashMap<Identity, Map<String, String>>(); + Map<IdentityRef, Map<String, String>> changedMapIdentityMap = new HashMap<>(); for (LDAPUser ldapUser: ldapUserList) { String user = null; try { @@ -1053,7 +1164,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe } if(StringHelper.containsNonWhitespace(ldapUser.getDn())) { dnToIdentityKeyMap.put(ldapUser.getDn(), ldapUser); - ldapUser.setCachedIdentity(identity); + ldapUser.setCachedIdentity(new IdentityRefImpl(identity.getKey())); } } else if (errors.isEmpty()) { String[] reqAttrs = syncConfiguration.checkRequestAttributes(userAttrs); @@ -1066,26 +1177,42 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe } else { log.warn(errors.get(), null); } - - if(++count % 20 == 0) { - dbInstance.intermediateCommit(); - } } catch (Exception e) { // catch here to go on with other users on exeptions! log.error("some error occured in looping over set of changed user-attributes, actual user " + user + ". Will still continue with others.", e); + errors.insert("Cannot sync user: " + user); + } finally { + dbInstance.commit(); + if(count % 10 == 0) { + dbInstance.closeSession(); + } } + if(count % 1000 == 0) { + log.info("Retrieve " + count + "/" + ldapUserList.size() + " users in LDAP server"); + } + count++; } // sync existing users if (changedMapIdentityMap == null || changedMapIdentityMap.isEmpty()) { log.info("LDAP batch sync: no users to sync" + sinceSentence); } else { - for (Identity ident : changedMapIdentityMap.keySet()) { + int syncCount = 0; + for (IdentityRef ident : changedMapIdentityMap.keySet()) { // sync user is exception save, no try/catch needed - syncUser(changedMapIdentityMap.get(ident), ident); - //REVIEW Identity are not saved??? - if(++count % 20 == 0) { - dbInstance.intermediateCommit(); + try { + syncCount++; + syncUser(changedMapIdentityMap.get(ident), ident); + } catch (Exception e) { + errors.insert("Cannot sync user: " + ident); + } finally { + dbInstance.commit(); + if(syncCount % 20 == 0) { + dbInstance.closeSession(); + } + } + if(syncCount % 1000 == 0) { + log.info("Update " + syncCount + "/" + changedMapIdentityMap.size() + " LDAP users"); } } log.info("LDAP batch sync: " + changedMapIdentityMap.size() + " users synced" + sinceSentence); @@ -1095,27 +1222,34 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe if (newLdapUserList.isEmpty()) { log.info("LDAP batch sync: no users to create" + sinceSentence); } else { + int newCount = 0; for (LDAPUser ldapUser: newLdapUserList) { Attributes userAttrs = ldapUser.getAttributes(); try { + newCount++; Identity identity = createAndPersistUser(userAttrs); - if(++count % 20 == 0) { - dbInstance.intermediateCommit(); - } - if(StringHelper.containsNonWhitespace(ldapUser.getDn())) { dnToIdentityKeyMap.put(ldapUser.getDn(), ldapUser); - ldapUser.setCachedIdentity(identity); + ldapUser.setCachedIdentity(new IdentityRefImpl(identity.getKey())); } } catch (Exception e) { // catch here to go on with other users on exeptions! log.error("some error occured while creating new users, actual userAttribs " + userAttrs + ". Will still continue with others.", e); + } finally { + dbInstance.commit(); + if(newCount % 20 == 0) { + dbInstance.closeSession(); + } + } + + if(newCount % 1000 == 0) { + log.info("Create " + count + "/" + newLdapUserList.size() + " LDAP users"); } } log.info("LDAP batch sync: " + newLdapUserList.size() + " users created" + sinceSentence); } - - dbInstance.intermediateCommit(); + + dbInstance.commitAndCloseSession(); return ldapUserList; } @@ -1155,7 +1289,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe List<String> groupIds = ldapUser.getGroupIds(); List<String> coachedGroupIds = ldapUser.getCoachedGroupIds(); if((groupIds != null && groupIds.size() > 0) || (coachedGroupIds != null && coachedGroupIds.size() > 0)) { - Identity identity = ldapUser.getCachedIdentity(); + IdentityRef identity = ldapUser.getCachedIdentity(); if(identity == null) { log.error("Identity with dn=" + ldapUser.getDn() + " not found"); } else { @@ -1205,16 +1339,25 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe } } + int count = 0; for(LDAPUser participant:participants) { - Identity memberIdentity = participant.getCachedIdentity(); + IdentityRef memberIdentity = participant.getCachedIdentity(); syncMembership(businessGroup, memberIdentity, false); currentMembers.remove(memberIdentity); + + if(count % 20 == 0) { + dbInstance.commitAndCloseSession(); + } } for(LDAPUser coach:coaches) { - Identity memberIdentity = coach.getCachedIdentity(); + IdentityRef memberIdentity = coach.getCachedIdentity(); syncMembership(businessGroup, memberIdentity, true); currentMembers.remove(memberIdentity); + + if(count % 20 == 0) { + dbInstance.commitAndCloseSession(); + } } for(Identity currentMember:currentMembers) { @@ -1222,13 +1365,18 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe for(String role:roles) { businessGroupRelationDao.removeRole(currentMember, businessGroup, role); } + + if(count % 20 == 0) { + dbInstance.commitAndCloseSession(); + } } } - private void syncMembership(BusinessGroup businessGroup, Identity identity, boolean coach) { - if(identity != null) { - List<String> roles = businessGroupRelationDao.getRoles(identity, businessGroup); + private void syncMembership(BusinessGroup businessGroup, IdentityRef identityRef, boolean coach) { + if(identityRef != null) { + List<String> roles = businessGroupRelationDao.getRoles(identityRef, businessGroup); if(roles.isEmpty()) { + Identity identity = securityManager.loadIdentityByKey(identityRef.getKey()); if(coach) { businessGroupRelationDao.addRole(identity, businessGroup, GroupRoles.coach.name()); } else { @@ -1240,6 +1388,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe //participant and only participant, do nothing } else { boolean already = false; + Identity identity = securityManager.loadIdentityByKey(identityRef.getKey()); String mainRole = coach ? GroupRoles.coach.name() : GroupRoles.participant.name(); for(String role:roles) { if(mainRole.equals(role)) { @@ -1279,7 +1428,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe private LDAPUser getLDAPUser(LdapContext ctx, String member, Map<String,LDAPUser> dnToIdentityKeyMap, LDAPError errors) { LDAPUser ldapUser = dnToIdentityKeyMap.get(member); - Identity identity = ldapUser == null ? null : ldapUser.getCachedIdentity(); + IdentityRef identity = ldapUser == null ? null : ldapUser.getCachedIdentity(); if(identity == null) { String userFilter = syncConfiguration.getLdapUserFilter(); @@ -1325,6 +1474,35 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe syncUser(olatProToSync, ident); } } + + @Override + public void doSyncSingleUserWithLoginAttribute(Identity ident) { + LdapContext ctx = bindSystem(); + if (ctx == null) { + log.error("could not bind to ldap", null); + } + + String ldapUserIDAttribute = syncConfiguration.getLdapUserLoginAttribute(); + String filter = ldapDao.buildSearchUserFilter(ldapUserIDAttribute, ident.getName()); + + List<Attributes> ldapUserAttrs = new ArrayList<>(); + ldapDao.searchInLdap(new LDAPVisitor() { + @Override + public void visit(SearchResult result) { + ldapUserAttrs.add(result.getAttributes()); + } + }, filter, syncConfiguration.getUserAttributes(), ctx); + + if(ldapUserAttrs.size() == 1) { + Attributes attrs = ldapUserAttrs.get(0); + Map<String, String> olatProToSync = prepareUserPropertyForSync(attrs, ident); + if (olatProToSync != null) { + syncUser(olatProToSync, ident); + } + } else { + log.error("Cannot sync the user because it was not found on LDAP server: " + ident); + } + } /** * @see org.olat.ldap.LDAPLoginManager#getLastSyncDate() diff --git a/src/main/java/org/olat/ldap/model/LDAPUser.java b/src/main/java/org/olat/ldap/model/LDAPUser.java index ff2483607703d28f1cfe2fad37ad9ccebd964dfd..44b3bc1d8c5a321438ae62888149647659973d21 100644 --- a/src/main/java/org/olat/ldap/model/LDAPUser.java +++ b/src/main/java/org/olat/ldap/model/LDAPUser.java @@ -23,7 +23,7 @@ import java.util.List; import javax.naming.directory.Attributes; -import org.olat.core.id.Identity; +import org.olat.basesecurity.IdentityRef; /** * @@ -43,7 +43,7 @@ public class LDAPUser { private List<String> groupIds; private List<String> coachedGroupIds; private Attributes attributes; - private Identity cachedIdentity; + private IdentityRef cachedIdentity; public String getDn() { return dn; @@ -125,11 +125,11 @@ public class LDAPUser { this.coachedGroupIds = coachedGroupIds; } - public Identity getCachedIdentity() { + public IdentityRef getCachedIdentity() { return cachedIdentity; } - public void setCachedIdentity(Identity cachedIdentity) { + public void setCachedIdentity(IdentityRef cachedIdentity) { this.cachedIdentity = cachedIdentity; } diff --git a/src/main/java/org/olat/ldap/ui/LDAPAdminController.java b/src/main/java/org/olat/ldap/ui/LDAPAdminController.java index f7cd3f3986dcb6943d1845f4e288ba58205bac5e..a336a196d8f804dd6a61a9445181a817ca4edf67 100644 --- a/src/main/java/org/olat/ldap/ui/LDAPAdminController.java +++ b/src/main/java/org/olat/ldap/ui/LDAPAdminController.java @@ -75,7 +75,7 @@ public class LDAPAdminController extends BasicController implements GenericEvent private Integer amountUsersToDelete; private List<Identity> identitiesToDelete; private LDAPLoginManager ldapLoginManager; - private Link fullSyncStartLink; + private UserSearchController userSearchCtrl; private CloseableCalloutWindowController calloutCtr; private Link syncOneUserLink; @@ -93,7 +93,6 @@ public class LDAPAdminController extends BasicController implements GenericEvent updateLastSyncDateInVC(); // Create start LDAP sync link syncStartLink = LinkFactory.createButton("sync.button.start", ldapAdminVC, this); - fullSyncStartLink = LinkFactory.createButton("full.sync.button.start", ldapAdminVC, this); // sync one user only // syncOneUserLink = LinkFactory.createButton("one.user.sync.button.start", ldapAdminVC, this); @@ -144,29 +143,17 @@ public class LDAPAdminController extends BasicController implements GenericEvent // Start sync job // Disable start link during sync syncStartLink.setEnabled(false); - fullSyncStartLink.setEnabled(false); LDAPEvent ldapEvent = new LDAPEvent(LDAPEvent.DO_SYNCHING); CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(ldapEvent, LDAPLoginManager.ldapSyncLockOres); showInfo("admin.synchronize.started"); - } - else if (source == fullSyncStartLink){ - // Start sync job - // Disable start link during sync - syncStartLink.setEnabled(false); - fullSyncStartLink.setEnabled(false); - LDAPEvent ldapEvent = new LDAPEvent(LDAPEvent.DO_FULL_SYNCHING); - CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(ldapEvent, LDAPLoginManager.ldapSyncLockOres); - showInfo("admin.synchronize.started"); - } - else if (source == syncOneUserLink){ + } else if (source == syncOneUserLink){ userSearchCtrl = new UserSearchController(ureq, getWindowControl(), false); listenTo(userSearchCtrl); calloutCtr = new CloseableCalloutWindowController(ureq, getWindowControl(), userSearchCtrl.getInitialComponent(), syncOneUserLink, null, true, null); calloutCtr.addDisposableChildController(userSearchCtrl); calloutCtr.activate(); listenTo(calloutCtr); - } - else if (source == deletStartLink) { + } else if (source == deletStartLink) { // cancel if some one else is making sync or delete job if (!ldapLoginManager.acquireSyncLock()) { showError("delete.error.lock"); @@ -284,7 +271,6 @@ public class LDAPAdminController extends BasicController implements GenericEvent } // re-enable start link syncStartLink.setEnabled(true); - fullSyncStartLink.setEnabled(true); // update last sync date updateLastSyncDateInVC(); } diff --git a/src/main/java/org/olat/ldap/ui/LDAPGroupsLoginInterceptor.java b/src/main/java/org/olat/ldap/ui/LDAPGroupsLoginInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..f4c5aebba62739e0aecec7949b5e9f01758a9045 --- /dev/null +++ b/src/main/java/org/olat/ldap/ui/LDAPGroupsLoginInterceptor.java @@ -0,0 +1,77 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ldap.ui; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.ldap.LDAPLoginManager; +import org.olat.ldap.LDAPLoginModule; +import org.olat.login.SupportsAfterLoginInterceptor; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 18 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LDAPGroupsLoginInterceptor extends FormBasicController implements SupportsAfterLoginInterceptor { + + @Autowired + private LDAPLoginModule ldapModule; + @Autowired + private LDAPLoginManager ldapManager; + + public LDAPGroupsLoginInterceptor(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + initForm(ureq); + } + + @Override + public boolean isUserInteractionRequired(UserRequest ureq) { + if(ldapModule.isLDAPEnabled()) { + try { + ldapManager.syncUserGroups(getIdentity()); + } catch (Exception e) { + logError("Cannot sync LDAP groups", e); + } + } + return false; + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + // + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + @Override + protected void doDispose() { + // + } +} diff --git a/src/main/java/org/olat/ldap/ui/_content/ldapadmin.html b/src/main/java/org/olat/ldap/ui/_content/ldapadmin.html index c3e61bb5ce38c69fe66b6d095e6e40de178a53f4..38698ccb7b9543b6f71d5e5763a3a5b0a7ae77eb 100644 --- a/src/main/java/org/olat/ldap/ui/_content/ldapadmin.html +++ b/src/main/java/org/olat/ldap/ui/_content/ldapadmin.html @@ -1,52 +1,36 @@ <h2>$r.translate("admin.title")</h2> - <fieldset> <legend>$r.translate("admin.deleteUser.title")</legend> - <p> - $r.translate("admin.deleteUser.intro") - </p> - <p> - $r.render("delete.button.start") - </p> + <div class="o_info">$r.translate("admin.deleteUser.intro")</div> + <div class="o_button_group">$r.render("delete.button.start")</div> </fieldset> - <fieldset> <legend>$r.translate("admin.synchronize.title")</legend> - <p> - $r.translate("admin.synchronize.intro") - </p> - <p> + <p>$r.translate("admin.synchronize.intro")</p> + <div class="o_info"> $r.translate("admin.synchronize.last"): #if ($lastSyncDate) $lastSyncDate #else <i>$r.translate("admin.synchronize.last.unknown")</i> - #end - </p> - <p> + #end</div> + <div class="o_button_group"> $r.render("sync.button.start") - </p> - <p> - $r.render("full.sync.button.start") - </p> - #if ($r.available("one.user.sync.button.start")) - <p> - $r.render("one.user.sync.button.start") - </p> - #end + #if ($r.available("one.user.sync.button.start")) + $r.render("one.user.sync.button.start") + #end + </div> </fieldset> - #if($r.available("remove.fallback.auth")) <fieldset> <legend>$r.translate("ldap.maintenance")</legend> - $r.translate("remove.fallback.auth.info") - <p> + <div class="o_info">$r.translate("remove.fallback.auth.info")</div> + <div class="o_button_group"> $r.render("remove.fallback.auth") - </p> + </div> </fieldset> #end - <fieldset> <legend>$r.translate("admin.logview.title")</legend> $r.render("logViewController") -</fieldset> +</fieldset> \ No newline at end of file diff --git a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_de.properties index 652217c098e51bfd6e3b7305916bfaa028721efd..c9b7dbff5de671347c71069b2893315847b9a066 100644 --- a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_de.properties @@ -37,8 +37,7 @@ login.error=<b>LDAP Benutzername oder Passwort ungültig.</b><p>Möglich login.form=OLAT Anmeldung \u00FCber LDAP login.intro=Bitte melden Sie sich mit Ihrem pers\u00F6nlichen LDAP-Benutzernamen und Passwort an. login.notauthenticated=<b>Keine Berechtigung für OLAT</b><p>Sie sind nicht zur Verwendung von OLAT berechtigt.</p><p>Diese Berechtigung können Sie über die Benutzerverwaltung erhalten.</p> -sync.button.start=Starte inkrementelle Synchronisation -full.sync.button.start=Starte volle Synchronisation +sync.button.start=Starte Synchronisation uncheckall=Auswahl l\u00F6schen one.user.sync.button.start=Einen Benutzer synchronisieren remove.fallback.auth=Authentifizierungen aus Cache l\u00f6schen diff --git a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_en.properties index 3da702b021b3969b2f48cf0f9b920090b8782e9f..cfb92a358a2c628e8a153184890053536d918412 100644 --- a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_en.properties @@ -29,7 +29,6 @@ delete.step0.description=Select users delete.step1.content.nothingToDelete=No users selected. Please go back to select some users or click on "Finish" to abort deletion. delete.step1.description=Confirm error.password.change.not.allow=You are registrated in OpenOLAT with a LDAP account. To change your password, please contact your system administrator. -full.sync.button.start=Start full sync ldap.maintenance=Maintenance lf.error.loginempty=Please insert your LDAP user name. lf.error.passempty=Please insert your LDAP password. @@ -42,5 +41,5 @@ login.notauthenticated=<b>Not authenticated for OLAT</b><p>You are not allowed t one.user.sync.button.start=Synchronize user account remove.fallback.auth=Delete cached fallback-authentications remove.fallback.auth.info=By removing the fallback-authentications a login is not possible anymore should the connection to the LDAP-server fail. The cache works again after a successful login. -sync.button.start=Start incremental sync +sync.button.start=Start sync uncheckall=Deselect all diff --git a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_fr.properties index a1a41b825bdab24efa941148d9e71d141f647090..b4eb854d50ce475d192659da66aca81c4f941cdc 100644 --- a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_fr.properties @@ -29,7 +29,6 @@ delete.step0.description=Choisir utilisateur delete.step1.content.nothingToDelete=Aucun utilisateur n'a \u00E9t\u00E9 s\u00E9lectionn\u00E9, faites un pas en arri\u00E8re pour en s\u00E9lectionner, ou cliquez sur "Terminer" pour ne pas en effacer. delete.step1.description=Confirmer error.password.change.not.allow=Vous \u00EAtes enregistr\u00E9 avec un compte LDAP dans OpenOLAT. Pour changer votre mot de passe, contactez s'il vous pla\u00EEt votre administrateur syst\u00E8me. -full.sync.button.start=D\u00E9marrer une synchronisation compl\u00E8te ldap.maintenance=Maintenance lf.error.loginempty=Veuillez indiquer votre nom d'utilisateur LDAP. lf.error.passempty=Indiquez votre mot de passe LDAP. @@ -42,5 +41,5 @@ login.notauthenticated=<b>Pas d'autorisation pour OpenOLAT</ b><p>Vous n'\u00EAt one.user.sync.button.start=Synchroniser un utilisateur remove.fallback.auth=Supprimer les authentifications du cache remove.fallback.auth.info=Si les authentifications de r\u00E9serves sauvegard\u00E9es sur le serveur OpenOLAT sont supprim\u00E9es, un login ne sera possible que via LDAP. Si la connexion au serveur LDAP n'est pas disponible, l'utilisateur ne pourra plus se connecter \u00E0 OpenOLAT\! -sync.button.start=D\u00E9part +sync.button.start=D\u00E9marrer une synchronisation uncheckall=Effacer s\u00E9lection diff --git a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_it.properties index 1a861d512765ebee2ca3e5bb5588b7d6240436fe..c58d79ae7aa93a5b46aff88be51103b6aa80a6fc 100644 --- a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_it.properties @@ -29,7 +29,6 @@ delete.step0.description=Selezione utenti delete.step1.content.nothingToDelete=Nessun utente \u00E8 stato selezionato, faccia un passo indietro per farlo o clicchi su "Concludere" per non eliminarne. delete.step1.description=Conferma error.password.change.not.allow=Sei registrato in OpenOLAT con un account LDAP. Per modificare la password, contattare l'amministratore di sistema. -full.sync.button.start=Avviare full sync ldap.maintenance=Manutenzione lf.error.loginempty=Indichi il Suo nome d'utente LDAP, p.f. lf.error.passempty=Indichi la Sua password LDPA, p.f. @@ -42,5 +41,5 @@ login.notauthenticated=<b>Non autenticato per OLAT</b><p>Il login in OLAT non \u one.user.sync.button.start=Sincronizzare account utente remove.fallback.auth=Eliminare le fallback-authentication in cache remove.fallback.auth.info=Rimuovendo le fallback-authentication in cache, il login non sar\u00E0 pi\u00F9 possibile nel caso la connessione al server LDAP fallisca. La cache funzioner\u00E0 di nuovo dopo un login avvenuto con successo. -sync.button.start=Avviare +sync.button.start=Avviare sync uncheckall=Cancellare selezione diff --git a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_pl.properties index 718ab858640b4089027532a349802ba74c7fff22..0d764c064eb0ebf1a970e97662fef15ee31f1c28 100644 --- a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_pl.properties @@ -24,7 +24,6 @@ delete.step0.content=Wybierz u\u017Cytkownik\u00F3w do usuni\u0119cia delete.step0.description=Wybierz u\u017Cytkownika do usuni\u0119cia delete.step1.content.nothingToDelete=Nie wybrano u\u017Cytkownik\u00F3w do usuni\u0119cia delete.step1.description=Potwierd\u017A -full.sync.button.start=Rozpocznij pe\u0142n\u0105 synchronizacj\u0119 ldap.maintenance=Konserwacka lf.error.loginempty=Wprowad\u017A swoj\u0105 nazw\u0119 u\u017Cytkownika LDAP. lf.error.passempty=Wprowad\u017A swoje has\u0142o LDAP @@ -34,5 +33,5 @@ login.error=<b>Nieprawid\u0142owa nazwa u\u017Cytkownika LDAP lub has\u0142o.</b login.form=Logowanie do OLAT za pomoc\u0105 serwera LDAP login.intro=Zaloguj si\u0119 ze swoj\u0105 nazw\u0105 u\u017Cytkownika LDAP i has\u0142em one.user.sync.button.start=Synchronizuj konta u\u017Cytkownik\u00F3w -sync.button.start=Start +sync.button.start=Rozpocznij synchronizacj\u0119 uncheckall=Odznacz wszystkie diff --git a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_pt_BR.properties index b63db442fde6f8182793e064963fde1c0f17dddc..ce7fb1c9280c03d4c0b22a93b53d8415950e446a 100644 --- a/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/ldap/ui/_i18n/LocalStrings_pt_BR.properties @@ -29,7 +29,6 @@ delete.step0.description=Selecione o usu\u00E1rio a deletar delete.step1.content.nothingToDelete=Nenhum usu\u00E1rio selecionado para remo\u00E7\u00E3o delete.step1.description=Confirma error.password.change.not.allow=Voc\u00EA est\u00E1 logado com um acesso LDAP no OpenOLAT. Para alterar sua senha, entre em contato com o administrador do sistema. -full.sync.button.start=Iniciar sincroniza\u00E7\u00E3o completa ldap.maintenance=Manuten\u00E7\u00E3o lf.error.loginempty=Favor insira seu usu\u00E1rio LDAP lf.error.passempty=Favor insira o seu password LDAP @@ -42,5 +41,5 @@ login.notauthenticated=<b>N\u00E3o autenticado para o OLAT</b><p>Voc\u00EA n\u00 one.user.sync.button.start=Sincronizar conta de usu\u00E1rio remove.fallback.auth=Excluir cache fallback de autentica\u00E7\u00F5es remove.fallback.auth.info=Ao retirar as autentica\u00E7\u00F5es fallback, um login n\u00E3o \u00E9 mais poss\u00EDvel se a conex\u00E3o com o servidor LDAP falhar. O cache funciona novamente ap\u00F3s um login bem-sucedido. -sync.button.start=Inicia +sync.button.start=Iniciar sincroniza\u00E7\u00E3o uncheckall=Deseleciona tudo diff --git a/src/main/java/org/olat/login/LoginAdminController.java b/src/main/java/org/olat/login/LoginAdminController.java index 2c4443927bab8d5fa22ce710c2b90e4fa96e7196..661fb3ac7dae2514a8edc49818aabd133aa756ec 100644 --- a/src/main/java/org/olat/login/LoginAdminController.java +++ b/src/main/java/org/olat/login/LoginAdminController.java @@ -27,6 +27,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; +import org.olat.search.SearchModule; import org.springframework.beans.factory.annotation.Autowired; /** @@ -37,13 +38,15 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class LoginAdminController extends FormBasicController { - private MultipleSelectionElement guestLoginEl, guestLinkEl, invitationLoginEl; + private MultipleSelectionElement guestLoginEl, guestLinkEl, invitationLoginEl, fullTextSearchEl; private static final String[] keys = new String[]{ "on" }; private final String[] values; @Autowired private LoginModule loginModule; + @Autowired + private SearchModule searchModule; public LoginAdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); @@ -68,6 +71,10 @@ public class LoginAdminController extends FormBasicController { invitationLoginEl = uifactory.addCheckboxesHorizontal("invitation.login", "invitation.login", formLayout, keys, values); invitationLoginEl.select(keys[0], loginModule.isInvitationEnabled()); invitationLoginEl.addActionListener(FormEvent.ONCHANGE); + + fullTextSearchEl = uifactory.addCheckboxesHorizontal("guest.search", "guest.search", formLayout, keys, values); + fullTextSearchEl.select(keys[0], searchModule.isGuestEnabled()); + fullTextSearchEl.addActionListener(FormEvent.ONCHANGE); } @Override @@ -86,6 +93,9 @@ public class LoginAdminController extends FormBasicController { } else if(invitationLoginEl == source) { boolean enabled = invitationLoginEl.isAtLeastSelected(1); loginModule.setInvitationEnabled(enabled); + } else if(fullTextSearchEl == source) { + boolean enabled = fullTextSearchEl.isAtLeastSelected(1); + searchModule.setGuestEnabled(enabled); } super.formInnerEvent(ureq, source, event); } diff --git a/src/main/java/org/olat/login/LoginAuthprovidersController.java b/src/main/java/org/olat/login/LoginAuthprovidersController.java index 08a57b79b85339c19cca6e4d609ca4b7e74b14d1..83dccae10dd9104657a45612163a8ab6ef31155d 100644 --- a/src/main/java/org/olat/login/LoginAuthprovidersController.java +++ b/src/main/java/org/olat/login/LoginAuthprovidersController.java @@ -84,6 +84,8 @@ public class LoginAuthprovidersController extends MainLayoutBasicController impl private Link anoLink; private StackedPanel dmzPanel; + @Autowired + private I18nModule i18nModule; @Autowired private LoginModule loginModule; @@ -283,14 +285,14 @@ public class LoginAuthprovidersController extends MainLayoutBasicController impl aboutVC.contextPut("version", Settings.getFullVersionInfo()); // Add translator and languages info I18nManager i18nMgr = I18nManager.getInstance(); - Collection<String> enabledKeysSet = I18nModule.getEnabledLanguageKeys(); + Collection<String> enabledKeysSet = i18nModule.getEnabledLanguageKeys(); Map<String, String> langNames = new HashMap<String, String>(); Map<String, String> langTranslators = new HashMap<String, String>(); String[] enabledKeys = ArrayHelper.toArray(enabledKeysSet); String[] names = new String[enabledKeys.length]; for (int i = 0; i < enabledKeys.length; i++) { String key = enabledKeys[i]; - String langName = i18nMgr.getLanguageInEnglish(key, I18nModule.isOverlayEnabled()); + String langName = i18nMgr.getLanguageInEnglish(key, i18nModule.isOverlayEnabled()); langNames.put(key, langName); names[i] = langName; String author = i18nMgr.getLanguageAuthor(key); diff --git a/src/main/java/org/olat/login/_content/about.html b/src/main/java/org/olat/login/_content/about.html index ea1663114d278b0383c5d954b2a58fab4bdff4b7..dd435de9e3e2169c04b1e8cd8be28dd5ce4cacf9 100644 --- a/src/main/java/org/olat/login/_content/about.html +++ b/src/main/java/org/olat/login/_content/about.html @@ -6,9 +6,9 @@ #if($r.translate("about.custom.title") != "") <div id="o_about_custom"> - <h2> + <h1> $r.translate("about.custom.title") - </h2> + </h1> <p> $r.translate("about.custom") </p> @@ -19,16 +19,24 @@ <h2> LMS OpenOLAT </h2> - <a href="http://www.openolat.org" target="_blank" class="o_link_extern">http://www.openolat.org</a> - <p class="text-muted"> - $r.translate("about.version") $r.getVersion() + <p> + <a href="http://www.openolat.org" target="_blank" class="o_link_extern">http://www.openolat.org</a> + <br /> + <span class="text-muted"> + $r.translate("about.version") $r.getVersion() + </span> </p> - <a href="https://www.frentix.com/testbericht-openolat-sehr-gut/" target="_blank" title="The OpenOLAT LMS got a high score in the e-learning journal ranking"> - <img border="0" src="$r.staticLink("images/openolat/openolat-test-sehr-gut_large.png")" alt="The OpenOLAT LMS got a high score in the e-learning journal ranking" style="float: right; padding-left: 2em; padding-bottom: 2em; max-width: 40%;" /> - </a> <p> $r.translate("about.history") </p> + <p> + <a href="https://www.frentix.com/testbericht-openolat-sehr-gut/" target="_blank" title="The OpenOLAT LMS got a high score in the e-learning journal ranking"> + <img border="0" src="$r.staticLink("images/openolat/openolat-test-sehr-gut_large.png")" alt="The OpenOLAT LMS got a high score in the e-learning journal ranking" style="display: inline-block; padding-left: 2em; padding-bottom: 2em; max-width: 40%; max-height: 200px;" /> + </a> + <a href="http://www.comenius-award.de" target="_blank" title="The OpenOLAT LMS wins a comenius edu media award"> + <img border="0" src="$r.staticLink("images/openolat/openolat_comeniusedumed_2017.png")" alt="The OpenOLAT LMS wins a comenius edu media award" style="display: inline-block; padding-left: 2em; padding-bottom: 2em; max-width: 40%; max-height: 200px;" /> + </a> + </p> <p> $r.translate("about.elearningjournal.test.2015") </p> @@ -40,20 +48,24 @@ <br /> <a href="http://www.elearning-journal.de" target="_blank" class="text-muted o_link_extern">eLearning Journal | Themenheft Praxistest: weiterbilden 2.0</a> </p> + + <h2> + Social + </h2> <p> $r.translate("about.social") </p> <p> - <a href="http://www.twitter.com/OpenOLAT" target="_blank"><i class="o_icon o_icon_twitter o_icon-2x"> </i></a> - <a href="http://facebook.com/OpenOLAT" target="_blank"><i class="o_icon o_icon_facebook o_icon-2x"> </i></a> - <a href="https://plus.google.com/communities/117966447506177997483" target="_blank"><i class="o_icon o_icon_google o_icon-2x"> </i></a> + <a href="http://www.twitter.com/OpenOLAT" target="_blank"><i class="o_icon o_icon_twitter o_icon-3x"> </i></a> + <a href="http://facebook.com/OpenOLAT" target="_blank"><i class="o_icon o_icon_facebook o_icon-3x"> </i></a> + <a href="https://plus.google.com/communities/117966447506177997483" target="_blank"><i class="o_icon o_icon_google o_icon-3x"> </i></a> </p> </div> <div id="o_about_financing"> - <h3 style="clear:both;"> + <h2 style="clear:both;"> $r.translate("about.financing") - </h3> + </h2> <p> $r.translate("about.financing.intro") <p> @@ -68,9 +80,9 @@ </div> <div class="o_about_partner"> - <h3 > + <h2 > $r.translate("about.partner") - </h3> + </h2> <p> $r.translate("about.partner.intro") <p> @@ -90,6 +102,10 @@ <td>Gold</td> <td><a href="http://www.vcrp.de" target="_blank" class="o_extern">Virtueller Campus Rheinland-Pfalz, VCRP</a></td> </tr> + <tr> + <td>Silver</td> + <td><a href="http://www.hs-furtwangen.de" target="_blank" class="o_extern">Hochschule Furtwangen, HFU</a></td> + </tr> <tr> <td>Bronze</td> <td><a href="http://www.bzgbs.ch" target="_blank" class="o_extern">BZG Bildungszentrum Gesundheit Basel-Stadt</a></td> @@ -117,11 +133,15 @@ </tr> <tr> <td>Bronze</td> - <td><a href="http://www.hs-furtwangen.de" target="_blank" class="o_extern">Hochschule Furtwangen, HFU</a></td> + <td><a href="http://www.uni-hamburg.de" target="_blank" class="o_extern">Universität Hamburg, UHH</a></td> </tr> <tr> <td>Bronze</td> - <td><a href="http://www.uni-hamburg.de" target="_blank" class="o_extern">Universität Hamburg, UHH</a></td> + <td><a href="http://www.ibw.ch" target="_blank" class="o_extern">Höhere Fachschule Südostschweiz, ibW</a></td> + </tr> + <tr> + <td>Bronze</td> + <td><a href="http://www.zag.zh.ch" target="_blank" class="o_extern">Zentrum für Ausbildung im Gesundheitswesen Kanton Zürich, ZAG</a></td> </tr> </tbody> </table> @@ -132,13 +152,13 @@ $r.translate("about.linktext") </p> <p class="text-right"> - <br />Zürich, 15.08.2013 + <br />Zürich, 13.09.2017 </p> <div class="o_about_copyright"> - <h3> + <h2> $r.translate("about.copyright") - </h3> + </h2> <pre class="small"> $licenses </pre> diff --git a/src/main/java/org/olat/login/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/login/_i18n/LocalStrings_de.properties index 181a6d611e552fafaa831d79ad12109d991663fa..1a4f1f79f6af69d57d32c474072c2ade8aac9605 100644 --- a/src/main/java/org/olat/login/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/login/_i18n/LocalStrings_de.properties @@ -88,6 +88,7 @@ default.shib.intro=Sie werden zur Authentifizierung weitergeleitet. enabled=ein guest.login=Gastlogin auf Login Seite guest.login.links=Links f\u00FCr Gast +guest.search=Volltextsuche f\u00FCr Gast invitation.login=Einladung erlauben lf.error.loginempty=Bitte geben Sie einen Benutzernamen ein. lf.error.passempty=Bitte geben Sie ein Passwort ein. diff --git a/src/main/java/org/olat/login/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/login/_i18n/LocalStrings_en.properties index 09f76ff3fce92ed82c1145a27481ba69ca616149..bfe7a2aedcfc928a8cb323da996ce2710565ffa2 100644 --- a/src/main/java/org/olat/login/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/login/_i18n/LocalStrings_en.properties @@ -88,6 +88,7 @@ default.shib.intro=You will be redirected to authentication. enabled=enabled guest.login=Guest login on login page guest.login.links=Links for guests +guest.search=Full-text search for guest invitation.login=Allow invitation lf.error.loginempty=Please enter your user name. lf.error.passempty=Please insert a password. diff --git a/src/main/java/org/olat/login/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/login/_i18n/LocalStrings_fr.properties index de036081c4815fa911d56139f28a41459f1b6ab9..38cdabc634c102ca754601eb9395fa1371aef2bb 100644 --- a/src/main/java/org/olat/login/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/login/_i18n/LocalStrings_fr.properties @@ -1,7 +1,7 @@ -#Sun Nov 08 12:54:50 CET 2015 +#Tue Aug 15 17:29:04 CEST 2017 +about.copyright=Copyright et participations about.custom= about.custom.title= -about.copyright=Copyright et participations about.date=Z\u00FCrich, le 8 f\u00E9vrier 2011 about.elearningjournal.test.2015=Le eLearning-Journal a class\u00E9 OpenOLAT avec le titre "tr\u00E8s bien" apr\u00E8s un test et une comparaison approfondie des LMS disponibles sur le march\u00E9. Avec cet excellent r\u00E9sultat, OpenOLAT est consid\u00E9r\u00E9 comme une solution de r\u00E9f\u00E9rence. Une sp\u00E9cialit\u00E9 d'OpenOLAT qui a \u00E9t\u00E9 soulign\u00E9e, est le grand nombre de fonctionnalit\u00E9s et d'outils disponibles. about.financing=Financer le d\u00E9veloppement @@ -76,6 +76,7 @@ default.shib.intro=Vous \u00EAtes redirig\u00E9 vers la connexion enabled=on guest.login=Connexion invit\u00E9 sur la page de login guest.login.links=Liens pour invit\u00E9s +guest.search=Recherche plein texte pour les invit\u00E9s invitation.login=Autoriser les invitations lf.error.loginempty=Veuillez entrer un nom d'utilisateur lf.error.passempty=Veuillez entrer un mot de passe diff --git a/src/main/java/org/olat/login/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/login/_i18n/LocalStrings_pt_BR.properties index 2facbd98b3fae1af6e310ac228ee8e38aee0eb8d..94ce962ed933608005b247b38388ee4c4c3fb186 100644 --- a/src/main/java/org/olat/login/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/login/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Thu Mar 16 22:33:37 CET 2017 +#Tue Sep 05 23:26:40 CEST 2017 about.copyright=Copyright e contribui\u00E7\u00F5es about.date=Zurique, 8 de Fevereiro de 2011 about.elearningjournal.test.2015=O eLearning-Journal classificou o LMS OpenOLAT com o resultado "muito bom" em uma compara\u00E7\u00E3o extensa e em testes de LMS dispon\u00EDveis no mercado. Com este grande resultado, o OpenOLAT \u00E9 avaliado como a melhor solu\u00E7\u00E3o. Como grande destaque, o OpenOLAT foi nomeado devido ao grande n\u00FAmero de recursos e ferramentas dispon\u00EDveis. @@ -74,6 +74,7 @@ default.shib.intro=Voc\u00EA ser\u00E1 redirecionado para autentica\u00E7\u00E3o enabled=lig. guest.login=Login de convidado na p\u00E1gina de login guest.login.links=Links para convidados +guest.search=Busca completa para convidado invitation.login=Permitir convite lf.error.loginempty=Favor inserir seu usu\u00E1rio OpenOLAT. lf.error.passempty=Favor inserir sua senha OpenOLAT. diff --git a/src/main/java/org/olat/login/auth/OLATAuthManager.java b/src/main/java/org/olat/login/auth/OLATAuthManager.java index db0509ecbcf85d970d67aaded0f75b1046ef22da..bb6028877c8d63c3b982b20c079064f8ea03a062 100644 --- a/src/main/java/org/olat/login/auth/OLATAuthManager.java +++ b/src/main/java/org/olat/login/auth/OLATAuthManager.java @@ -269,7 +269,7 @@ public class OLATAuthManager extends BasicManager implements AuthenticationSPI { } if(identity != null && StringHelper.containsNonWhitespace(username) && webDAVAuthManager != null) { - webDAVAuthManager.changeDigestPassword(doer, identity, username, newPwd); + webDAVAuthManager.changeDigestPassword(doer, identity, newPwd); } return true; } @@ -294,7 +294,7 @@ public class OLATAuthManager extends BasicManager implements AuthenticationSPI { } if(identity != null && StringHelper.containsNonWhitespace(username) && webDAVAuthManager != null) { - webDAVAuthManager.changeDigestPassword(doer, identity, username, newPwd); + webDAVAuthManager.changeDigestPassword(doer, identity, newPwd); } return true; } diff --git a/src/main/java/org/olat/login/oauth/OAuthDispatcher.java b/src/main/java/org/olat/login/oauth/OAuthDispatcher.java index beb09fceab790331160c0cea70a18fab6d9212b2..9ed4997dce0d1c40ab3e0a7f132a230b4f5fd482 100644 --- a/src/main/java/org/olat/login/oauth/OAuthDispatcher.java +++ b/src/main/java/org/olat/login/oauth/OAuthDispatcher.java @@ -149,6 +149,19 @@ public class OAuthDispatcher implements Dispatcher { OAuthRegistration registration = new OAuthRegistration(provider.getProviderName(), infos); login(infos, registration); + + if(provider instanceof OAuthUserCreator) { + Identity newIdentity; + OAuthUserCreator userCreator = (OAuthUserCreator)provider; + if(registration.getIdentity() == null) { + newIdentity = userCreator.createUser(infos); + } else { + newIdentity = userCreator.updateUser(infos, registration.getIdentity()); + } + if(newIdentity != null) { + registration.setIdentity(newIdentity); + } + } if(registration.getIdentity() == null) { if(CoreSpringFactory.getImpl(OAuthLoginModule.class).isAllowUserCreation()) { diff --git a/src/main/java/org/olat/login/oauth/OAuthUserCreator.java b/src/main/java/org/olat/login/oauth/OAuthUserCreator.java new file mode 100644 index 0000000000000000000000000000000000000000..67bd052dfd708eee62bfca02747d9eecb703302a --- /dev/null +++ b/src/main/java/org/olat/login/oauth/OAuthUserCreator.java @@ -0,0 +1,40 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.login.oauth; + +import org.olat.core.id.Identity; +import org.olat.login.oauth.model.OAuthUser; + +/** + * + * Implement this interface if your service provider can + * automatically create the user without user interaction. + * + * Initial date: 18 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface OAuthUserCreator extends OAuthSPI { + + public Identity createUser(OAuthUser user); + + public Identity updateUser(OAuthUser user, Identity identity); + +} diff --git a/src/main/java/org/olat/login/oauth/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/login/oauth/ui/_i18n/LocalStrings_fr.properties index 28dca0e64c8433b17a026f8b6cbd3964469fb670..b30fbeb6780d88c445490fe9a6d352539b9b4120 100644 --- a/src/main/java/org/olat/login/oauth/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/login/oauth/ui/_i18n/LocalStrings_fr.properties @@ -57,7 +57,7 @@ openidconnectif.enabled=Open ID Connect openidconnectif.issuer=Issuer openidconnectif.issuer.example=https\://frentix.com openidconnectif.name=Nom du provider -openidconnectif.name.error=Limitez-vous s'il-vous-pla\u00EEt aux caract\u00E8res suivants\: a-z A-Z 0-9 . - _. Le nom doit avoir au minimum trois caract\u00E8res et au maximum 8. +openidconnectif.name.error=Limitez-vous s'il vous pla\u00EEt aux caract\u00E8res suivants\: a-z A-Z 0-9 . - _. Le nom doit avoir au minimum trois caract\u00E8res et au maximum 8. openidconnectif.wait.message=Vous allez \u00EAtre redirig\u00E9 vers OpenOLAT dans quelques instants. penidconnectif.displayname=Appelation twitter.admin.title=Configuration Twitter diff --git a/src/main/java/org/olat/modules/IModuleConfiguration.java b/src/main/java/org/olat/modules/IModuleConfiguration.java deleted file mode 100644 index 494d12ec3d36a8a0ef7a618f2154c1d495d8250a..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/modules/IModuleConfiguration.java +++ /dev/null @@ -1,139 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.modules; - -import org.olat.modules.ModuleProperty.ModulePropertyValue; - -/** - * A simple interface for dealing with sets of key/value pairs supporting the following - * <ul> - * <li>subsets based on a common key prefix (eg: sendToUsers, sendToOwners --> prefix: sendTo) - * <li>strongly typed properties (the definition of "keyName" is associated with a java type) - * </ul> - * - * <p>Initial date: May 6, 2016 - * @author lmihalkovic, http://www.frentix.com - */ -public interface IModuleConfiguration { - - /** - * Factory method for creating a {@link IModuleConfiguration} instance with a given - * property name prefix, backed by a given instance of {@link ModuleConfiguration}. - * This method allows a custom prefix/name separator to be specified. Passing {@code null} - * as a separator is equivalent to passing an empty string {@code ""}. - * - * @param fragmentName - * @param sep - * @param config - * @return - */ - public static IModuleConfiguration fragment(String fragmentName, String sep, ModuleConfiguration config) { - return new ModuleconfigurationFragment(fragmentName, sep, config); - } - - /** - * Factory method for creating a {@link IModuleConfiguration} instance with a given - * property name prefix, backed by a given instance of {@link ModuleConfiguration}. - * By default the property name will follow the pattern: prefix_XXXXX, where XXXXX - * is the name passed as a parameter to the methods in this interface - * - * - * @param fragmentName - * @param config - * @return - */ - public static IModuleConfiguration fragment(String fragmentName, ModuleConfiguration config) { - return new ModuleconfigurationFragment(fragmentName, "_", config); - } - - // ------------------------------------------------------------------------ - - public default boolean has(String configKey) { - return get(configKey) != null; - } - - public default boolean hasAnyOf(String...configKeys) { - for(String key : configKeys) { - if (get(key) != null) return true; - } - return false; - } - - public default boolean allTrue(String... configKeys) { - boolean rc = false; - for(String key : configKeys) { - rc = rc & getBooleanSafe(key); - if (!rc) break; - } - return rc; - } - - public default boolean anyTrue(String... configKeys) { - boolean rc = false; - for(String key : configKeys) { - rc = getBooleanSafe(key); - if (rc) break; - } - return rc; - } - - - public boolean getBooleanSafe(String configKey); - public void setBooleanEntry(String configKey, boolean value); - - public void set(String configKey, Object value); - public Object get(String configKey); - @SuppressWarnings("unchecked") - default public <T> T getAs(String configKey) { - Object val = get(configKey); - return val != null ? (T)val : null; - } - - - // ------------------------------------------------------------------------ - // Strongly typed API - - public <X> ModulePropertyValue<X> get(ModuleProperty<X> key); - public default <X> X val(ModuleProperty<X> key) { - return get(key).val(); - } - public <X> void set(ModulePropertyValue<X> value); - public <X> void set(ModuleProperty<X> key, X value); - - public default boolean has(ModuleProperty<?> key) { - ModulePropertyValue<?> val = get(key); - return val.isSet(); - } - - public boolean hasAnyOf(ModuleProperty<?>...keys); - - public boolean anyTrue(ModuleProperty<Boolean> key); - public boolean anyTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2); - public boolean anyTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3); - public boolean anyTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3, ModuleProperty<Boolean> key4); - public boolean anyTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3, ModuleProperty<Boolean> key4, ModuleProperty<Boolean> key5); - - public boolean allTrue(ModuleProperty<Boolean> key); - public boolean allTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2); - public boolean allTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3); - public boolean allTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3, ModuleProperty<Boolean> key4); - public boolean allTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3, ModuleProperty<Boolean> key4, ModuleProperty<Boolean> key5); - -} diff --git a/src/main/java/org/olat/modules/ModuleConfiguration.java b/src/main/java/org/olat/modules/ModuleConfiguration.java index b434bcec3521ef6d39baea5fc3c8b6e78cc870e2..b39f383316bb53d3379ba470129df8df0942db05 100644 --- a/src/main/java/org/olat/modules/ModuleConfiguration.java +++ b/src/main/java/org/olat/modules/ModuleConfiguration.java @@ -238,7 +238,7 @@ public class ModuleConfiguration implements Serializable { } } - public <U> List<U> getList(String config_key, Class<U> cl) { + public <U> List<U> getList(String config_key, @SuppressWarnings("unused") Class<U> cl) { @SuppressWarnings("unchecked") List<U> list = (List<U>)get(config_key); if(list == null) { @@ -254,6 +254,33 @@ public class ModuleConfiguration implements Serializable { set(config_key, list); } } + + public boolean has(String configKey) { + return get(configKey) != null; + } + + public boolean anyTrue(String... keys) { + if(keys != null && keys.length > 0) { + for(int i=keys.length; i-->0; ) { + if(getBooleanSafe(keys[i])) { + return true; + } + } + } + return false; + } + + public boolean hasAnyOf(String... keys) { + if(keys != null && keys.length > 0) { + for(int i=keys.length; i-->0; ) { + if(get(keys[i]) != null) { + return true; + } + } + } + return false; + } + /** * Get the version of this module configuration. The version specifies which diff --git a/src/main/java/org/olat/modules/ModuleProperty.java b/src/main/java/org/olat/modules/ModuleProperty.java deleted file mode 100644 index 6c66c2968fdb03a9a5523ab70cc5b4cbc994b961..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/modules/ModuleProperty.java +++ /dev/null @@ -1,158 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.modules; - -import java.lang.reflect.Array; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; - -/** - * A simple implementation of a strongly typed named property - * - * <p>Initial date: May 6, 2016 - * @author lmihalkovic, http://www.frentix.com - */ -public abstract class ModuleProperty<T> { - - /** - * A strongly typed property value - * - * Initial date: May 6, 2016<br> - * @author lmihalkovic, http://www.frentix.com - * - */ - public static final class ModulePropertyValue<X> { - private X value; - private final ModuleProperty<X> def; - protected ModulePropertyValue(X value, ModuleProperty<X> def) { - this.value = value; - this.def = def; - } - public X val() { - if(!isSet()) return getDefault(); - return value; - } - public void val(X val) { - this.value = val; - } - public X getDefault() { - return def.getDefault(); - } - public boolean isSet() { - return this.value != null; - } - public String name() { - return def.name; - } - } - - private final String name; - private final T defaultValue; - private final Type type; - - public ModuleProperty(String name) { - this(name, null); - } - - public ModuleProperty(String name, T defaultValue) { - this.name = name; - this.defaultValue = defaultValue; - this.type = getType(); - } - - public ModulePropertyValue<T> val(T value) { - return new ModulePropertyValue<T>(value, this); - } - - public String name() { - return this.name; - } - - public boolean hasDefault() { - return defaultValue != null; - } - - T getDefault() { - return this.defaultValue; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[") - .append(name()) - .append(":") - .append(type); - if (defaultValue!= null) { - sb.append(" {").append(defaultValue).append("}"); - } - sb.append("]"); - return sb.toString(); - } - - // ------------------------------ - // Internal - - private Type getType() { - Type superclass = getClass().getGenericSuperclass(); - if (superclass instanceof Class) { - throw new RuntimeException("Missing type parameter."); - } - return ((ParameterizedType) superclass).getActualTypeArguments()[0]; - } - - @SuppressWarnings("unchecked") - Class<T> rawType() { - // this is ok or leads to a CCE later if the types do not match - return (Class<T>) getRawType(type); - } - - private static Class<?> getRawType(Type type) { - if (type instanceof Class<?>) { - // type is a class - return (Class<?>) type; - } else if (type instanceof ParameterizedType) { - ParameterizedType parameterizedType = (ParameterizedType) type; - Type rawType = parameterizedType.getRawType(); - checkArgument(rawType instanceof Class); - return (Class<?>) rawType; - } else if (type instanceof GenericArrayType) { - Type componentType = ((GenericArrayType) type).getGenericComponentType(); - return Array.newInstance(getRawType(componentType), 0).getClass(); - } else if (type instanceof TypeVariable) { - return Object.class; - } else if (type instanceof WildcardType) { - return getRawType(((WildcardType) type).getUpperBounds()[0]); - } else { - String className = type == null ? "null" : type.getClass().getName(); - throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " + "GenericArrayType, but <" - + type + "> is of type " + className); - } - } - - private static void checkArgument(boolean condition) { - if (!condition) { - throw new IllegalArgumentException(); - } - } -} diff --git a/src/main/java/org/olat/modules/ModuleconfigurationFragment.java b/src/main/java/org/olat/modules/ModuleconfigurationFragment.java deleted file mode 100644 index 3aeebf598d59abedadaadf71444136bdb70c1442..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/modules/ModuleconfigurationFragment.java +++ /dev/null @@ -1,190 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.modules; - -import java.util.Date; -import java.util.List; - -import org.olat.modules.ModuleProperty.ModulePropertyValue; - -/** - * A sub-section of a standard module configuration. This is particularly - * useful in case a block of key/value pairs would be repeated, with a - * different prefix. - * - * <p>Initial date: May 6, 2016 - * @author lmihalkovic, http://www.frentix.com - */ -public class ModuleconfigurationFragment implements IModuleConfiguration { - - private final ModuleConfiguration config; - private final String fragmentName; - private final String sep; - - protected ModuleconfigurationFragment(String fragmentName, String separator, ModuleConfiguration config) { - this.config = config; - this.fragmentName = fragmentName; - this.sep = separator == null ? "" : separator; - } - - protected final String key(String configKey) { - return fragmentName + sep + configKey; - } - - @Override - public boolean getBooleanSafe(String configKey) { - return config.getBooleanSafe(key(configKey)); - } - - @Override - public void setBooleanEntry(String configKey, boolean value) { - config.setBooleanEntry(key(configKey), value); - } - - @Override - public void set(String configKey, Object value) { - config.set(key(configKey), value); - } - - @Override - public Object get(String configKey) { - return config.get(key(configKey)); - } - - public <U> List<U> getList(String configKey, Class<U> cl) { - return config.getList(key(configKey), cl); - } - - @Override - public boolean anyTrue(ModuleProperty<Boolean> key) { - return _anyTrue(key); - } - @Override - public boolean anyTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2) { - return _anyTrue(key1, key2); - } - @Override - public boolean anyTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3) { - return _anyTrue(key1, key2, key3); - } - @Override - public boolean anyTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3, ModuleProperty<Boolean> key4) { - return _anyTrue(key1, key2, key3, key4); - } - @Override - public boolean anyTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3, ModuleProperty<Boolean> key4, ModuleProperty<Boolean> key5) { - return _anyTrue(key1, key2, key3, key4, key5); - } - @SafeVarargs - protected final boolean _anyTrue(ModuleProperty<Boolean>... keys) { - boolean rc = false; - for(ModuleProperty<Boolean> key : keys) { - rc = getBooleanSafe(key.name()); - if (rc) return true; - } - return rc; - } - - - @Override - public boolean allTrue(ModuleProperty<Boolean> key) { - return _allTrue(key); - } - @Override - public boolean allTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2) { - return _allTrue(key1, key2); - } - @Override - public boolean allTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3) { - return _allTrue(key1, key2, key3); - } - @Override - public boolean allTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3, ModuleProperty<Boolean> key4) { - return _allTrue(key1, key2, key3, key3); - } - @Override - public boolean allTrue(ModuleProperty<Boolean> key1, ModuleProperty<Boolean> key2, ModuleProperty<Boolean> key3, ModuleProperty<Boolean> key4, ModuleProperty<Boolean> key5) { - return _allTrue(key1, key2, key3, key4, key5); - } - - @SafeVarargs - protected final boolean _allTrue(ModuleProperty<Boolean>... keys) { - for(ModuleProperty<Boolean> key : keys) { - boolean rc = getBooleanSafe(key.name()); - if (!rc) return false; - } - return true; - } - - @Override - public <X> ModulePropertyValue<X> get(ModuleProperty<X> key) { - ModulePropertyValue<X> value = valueOf(key); - return value; - } - - @Override - public <X> void set(ModulePropertyValue<X> val) { - X value = val.val(); - config.set(key(val.name()), value); - } - - @Override - public <X> void set(ModuleProperty<X> key, X value) { - config.set(key(key.name()), value); - } - - @Override - public boolean hasAnyOf(ModuleProperty<?>... keys) { - for(ModuleProperty<?> key : keys) { - ModulePropertyValue<?> val = get(key); - if (val.isSet()) return true; - } - return false; - } - - protected <X> ModulePropertyValue<X> valueOf(ModuleProperty<X> key) { - Class<X> klass = key.rawType(); - X val = null; - String name = key.name(); - if(klass == Boolean.class) { - Boolean b = (key.hasDefault() ? config.getBooleanSafe(key(name), (Boolean)(key.getDefault())) : config.getBooleanEntry(key(name))); - val = klass.cast(b); - } else if (klass == Float.class) { - Float f = config.getFloatEntry(key(name)); - val = klass.cast(f); - } else if (klass == Integer.class) { - if(!key.hasDefault()) { - throw new IllegalArgumentException("Integer keys MUST define a default value"); - } - Integer i = config.getIntegerSafe(key(name), (Integer)key.getDefault()); - val = klass.cast(i); - } else if (klass == Date.class) { - Date d = config.getDateValue(key(name)); - val = klass.cast(d); - } else { - // This is no different than the normal CCE that would happen - // in the calling code when doing - // SomeType val = (SomeType) config.get("keyName"); - val = klass.cast(get(name)); - } - return new ModulePropertyValue<X>(val, key); - } - -} diff --git a/src/main/java/org/olat/modules/_spring/modulesContext.xml b/src/main/java/org/olat/modules/_spring/modulesContext.xml index 433de5bbde70d6b57d8219b240e2aa2a6564d29b..7ea6f1f3f7159d7bea4bd2a5382177e7c3468292 100644 --- a/src/main/java/org/olat/modules/_spring/modulesContext.xml +++ b/src/main/java/org/olat/modules/_spring/modulesContext.xml @@ -14,8 +14,6 @@ <import resource="classpath:/org/olat/modules/glossary/_spring/glossaryContext.xml"/> <import resource="classpath:/org/olat/modules/iq/_spring/iqContext.xml"/> <import resource="classpath:/org/olat/modules/lecture/_spring/lectureContext.xml"/> - <import resource="classpath:/org/olat/modules/openmeetings/_spring/openmeetingsContext.xml"/> - <import resource="classpath:/org/olat/modules/vitero/_spring/viteroContext.xml"/> <import resource="classpath:/org/olat/modules/webFeed/_spring/webFeedContext.xml"/> <import resource="classpath:/org/olat/modules/wiki/_spring/wikiContext.xml"/> <import resource="classpath:/org/olat/modules/reminder/_spring/reminderContext.xml"/> @@ -51,7 +49,7 @@ <property name="className" value="org.olat.modules.card2brain.ui.Card2BrainAdminController"/> </bean> </property> - <property name="navigationKey" value="gotomeeting" /> + <property name="navigationKey" value="card2brain" /> <property name="i18nActionKey" value="admin.menu.title"/> <property name="i18nDescriptionKey" value="admin.menu.title.alt"/> <property name="translationPackage" value="org.olat.modules.card2brain.ui"/> @@ -124,4 +122,46 @@ </property> </bean> + <!-- vitero admin. panel --> + <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> + <property name="order" value="8228" /> + <property name="actionController"> + <bean class="org.olat.core.gui.control.creator.FactoryControllerCreator" scope="prototype"> + <property name="factoryName" value="org.olat.modules.vitero.ViteroUIFactory"/> + <property name="factoryMethod" value="createViteroAdminController"/> + </bean> + </property> + <property name="navigationKey" value="vitero" /> + <property name="parentTreeNodeIdentifier" value="externalToolsParent" /> + <property name="i18nActionKey" value="admin.menu.title"/> + <property name="i18nDescriptionKey" value="admin.menu.title.alt"/> + <property name="translationPackage" value="org.olat.modules.vitero.ui"/> + <property name="extensionPoints"> + <list> + <value>org.olat.admin.SystemAdminMainController</value> + </list> + </property> + </bean> + + <!-- OpenMeetings admin. panel --> + <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> + <property name="order" value="7210" /> + <property name="actionController"> + <bean class="org.olat.core.gui.control.creator.FactoryControllerCreator" scope="prototype"> + <property name="factoryName" value="org.olat.modules.openmeetings.OpenMeetingsUIFactory"/> + <property name="factoryMethod" value="createAdminController"/> + </bean> + </property> + <property name="navigationKey" value="openmeetings" /> + <property name="parentTreeNodeIdentifier" value="externalToolsParent" /> + <property name="i18nActionKey" value="admin.menu.title"/> + <property name="i18nDescriptionKey" value="admin.menu.title.alt"/> + <property name="translationPackage" value="org.olat.modules.openmeetings.ui"/> + <property name="extensionPoints"> + <list> + <value>org.olat.admin.SystemAdminMainController</value> + </list> + </property> + </bean> + </beans> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/assessment/AssessmentEntry.java b/src/main/java/org/olat/modules/assessment/AssessmentEntry.java index 9370b4bcf31aeb62bf091f74b5cf84f8d241bcf1..5228d513d1c4f92abb35fef5e34fd9c6ec078340 100644 --- a/src/main/java/org/olat/modules/assessment/AssessmentEntry.java +++ b/src/main/java/org/olat/modules/assessment/AssessmentEntry.java @@ -40,6 +40,14 @@ public interface AssessmentEntry extends AssessmentEntryLight { public Date getLastModified(); + public Date getLastCoachModified(); + + public void setLastCoachModified(Date date); + + public Date getLastUserModified(); + + public void setLastUserModified(Date date); + public Long getAssessmentId(); public void setAssessmentId(Long assessmentId); diff --git a/src/main/java/org/olat/modules/assessment/AssessmentService.java b/src/main/java/org/olat/modules/assessment/AssessmentService.java index f9b386b069adb0e516ce4b2743b69865bbb588a3..d977c118d2fdf84a0a387713c1423d850ad16f3b 100644 --- a/src/main/java/org/olat/modules/assessment/AssessmentService.java +++ b/src/main/java/org/olat/modules/assessment/AssessmentService.java @@ -19,6 +19,7 @@ */ package org.olat.modules.assessment; +import java.util.Date; import java.util.List; import org.olat.core.id.Identity; @@ -46,7 +47,7 @@ public interface AssessmentService { * @return */ public AssessmentEntry createAssessmentEntry(Identity assessedIdentity, String anonymousIdentifier, - RepositoryEntry entry, String subIdent, RepositoryEntry referenceEntry, Float score, Boolean passed); + RepositoryEntry entry, String subIdent, RepositoryEntry referenceEntry, Float score, Boolean passed, Date lastUserModified, Date lastCoachModified); /** * diff --git a/src/main/java/org/olat/modules/assessment/Role.java b/src/main/java/org/olat/modules/assessment/Role.java new file mode 100644 index 0000000000000000000000000000000000000000..a7cf4ef15bbd1ddedbecf39dabe2f1b089cd2f30 --- /dev/null +++ b/src/main/java/org/olat/modules/assessment/Role.java @@ -0,0 +1,34 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.assessment; + +/** + * Say who has done the changes. + * + * Initial date: 14 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public enum Role { + coach, + user, + auto + +} diff --git a/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java b/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java index 9f5e28d17581aa4e3f9d29a55908e9758c663bb7..298e4564923ecadbcf3c10d5ccdbcf8958d37eb7 100644 --- a/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java +++ b/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java @@ -68,11 +68,13 @@ public class AssessmentEntryDAO { public AssessmentEntry createAssessmentEntry(Identity assessedIdentity, String anonymousIdentifier, RepositoryEntry entry, String subIdent, RepositoryEntry referenceEntry, - Float score, Boolean passed) { + Float score, Boolean passed, Date lastUserModified, Date lastCoachModified) { AssessmentEntryImpl data = new AssessmentEntryImpl(); data.setCreationDate(new Date()); data.setLastModified(data.getCreationDate()); + data.setLastUserModified(lastUserModified); + data.setLastCoachModified(lastCoachModified); data.setIdentity(assessedIdentity); data.setAnonymousIdentifier(anonymousIdentifier); data.setRepositoryEntry(entry); diff --git a/src/main/java/org/olat/modules/assessment/manager/AssessmentServiceImpl.java b/src/main/java/org/olat/modules/assessment/manager/AssessmentServiceImpl.java index f9f5890f1d6411a2dc44a7305d6f11858d134252..915da459e073a8122b56350b23225b3f46c7c928 100644 --- a/src/main/java/org/olat/modules/assessment/manager/AssessmentServiceImpl.java +++ b/src/main/java/org/olat/modules/assessment/manager/AssessmentServiceImpl.java @@ -21,6 +21,7 @@ package org.olat.modules.assessment.manager; import java.io.File; import java.util.Collections; +import java.util.Date; import java.util.List; import org.olat.core.commons.persistence.DB; @@ -51,8 +52,10 @@ public class AssessmentServiceImpl implements AssessmentService, UserDataDeletab @Override public AssessmentEntry createAssessmentEntry(Identity assessedIdentity, String anonymousIdentifier, - RepositoryEntry entry, String subIdent, RepositoryEntry referenceEntry, Float score, Boolean passed) { - return assessmentEntryDao.createAssessmentEntry(assessedIdentity, anonymousIdentifier, entry, subIdent, referenceEntry, score, passed); + RepositoryEntry entry, String subIdent, RepositoryEntry referenceEntry, + Float score, Boolean passed, Date lastUserModified, Date lastCoachModified) { + return assessmentEntryDao.createAssessmentEntry(assessedIdentity, anonymousIdentifier, entry, subIdent, referenceEntry, + score, passed, lastUserModified, lastCoachModified); } @Override diff --git a/src/main/java/org/olat/modules/assessment/model/AssessmentEntryImpl.java b/src/main/java/org/olat/modules/assessment/model/AssessmentEntryImpl.java index ad69459e5be157e630a71b18b73598c267f14c84..85a223f96ae774f678c940a6ca984c87a646e9a5 100644 --- a/src/main/java/org/olat/modules/assessment/model/AssessmentEntryImpl.java +++ b/src/main/java/org/olat/modules/assessment/model/AssessmentEntryImpl.java @@ -74,6 +74,11 @@ public class AssessmentEntryImpl implements Persistable, ModifiedInfo, CreateInf @Temporal(TemporalType.TIMESTAMP) @Column(name="lastmodified", nullable=false, insertable=true, updatable=true) private Date lastModified; + + @Column(name="lastcoachmodified", nullable=true, insertable=true, updatable=true) + private Date lastCoachModified; + @Column(name="lastusermodified", nullable=true, insertable=true, updatable=true) + private Date lastUserModified; @Column(name="a_attemtps", nullable=true, insertable=true, updatable=true) private Integer attempts; @@ -150,6 +155,24 @@ public class AssessmentEntryImpl implements Persistable, ModifiedInfo, CreateInf this.lastModified = lastModified; } + @Override + public Date getLastCoachModified() { + return lastCoachModified; + } + + public void setLastCoachModified(Date lastCoachModified) { + this.lastCoachModified = lastCoachModified; + } + + @Override + public Date getLastUserModified() { + return lastUserModified; + } + + public void setLastUserModified(Date lastUserModified) { + this.lastUserModified = lastUserModified; + } + @Override public Integer getAttempts() { return attempts; diff --git a/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityElementRow.java b/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityElementRow.java index 603127f241ee8f3a289ea418deb131713766bbbf..133b11cb9d5843bbd083ff10889024cf2cb51be2 100644 --- a/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityElementRow.java +++ b/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityElementRow.java @@ -43,7 +43,7 @@ public class AssessedIdentityElementRow extends UserPropertiesRow { private final BigDecimal score; private final Boolean passed; private final Date initialCourseLaunchDate; - private final Date lastModified; + private final Date lastModified, lastUserModified, lastCoachModified; private final int numOfAssessmentDocs; private final AssessmentEntryStatus status; @@ -57,6 +57,8 @@ public class AssessedIdentityElementRow extends UserPropertiesRow { passed = entry.getPassed(); userVisibility = entry.getUserVisibility(); lastModified = entry.getLastModified(); + lastUserModified = entry.getLastUserModified(); + lastCoachModified = entry.getLastCoachModified(); status = entry.getAssessmentStatus(); numOfAssessmentDocs = entry.getNumberOfAssessmentDocuments(); } else { @@ -64,7 +66,7 @@ public class AssessedIdentityElementRow extends UserPropertiesRow { score = null; passed = null; userVisibility = null; - lastModified = null; + lastModified = lastUserModified = lastCoachModified = null; status = null; numOfAssessmentDocs = 0; } @@ -90,6 +92,14 @@ public class AssessedIdentityElementRow extends UserPropertiesRow { public Date getLastModified() { return lastModified; } + + public Date getLastUserModified() { + return lastUserModified; + } + + public Date getLastCoachModified() { + return lastCoachModified; + } public int getNumOfAssessmentDocs() { return numOfAssessmentDocs; diff --git a/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityListController.java b/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityListController.java index f20d7030d75bd18ac6163ff5b58fcc56f3f08ada..9cc4aafad116dd3b3591bd4f0c30b21429db6859 100644 --- a/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityListController.java +++ b/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityListController.java @@ -172,9 +172,10 @@ public class AssessedIdentityListController extends FormBasicController implemen columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.assessmentStatus, new AssessmentStatusCellRenderer(getLocale()))); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.initialLaunchDate, "select")); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.lastScoreUpdate, "select")); - //columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.certificate, new DownloadCertificateCellRenderer())); - + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, IdentityCourseElementCols.lastModified, "select")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.lastUserModified, "select")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, IdentityCourseElementCols.lastCoachModified, "select")); + usersTableModel = new AssessedIdentityListTableModel(columnsModel, element); usersTableModel.setCertificateMap(new ConcurrentHashMap<>()); tableEl = uifactory.addTableElement(getWindowControl(), "table", usersTableModel, 20, false, getTranslator(), formLayout); diff --git a/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityListTableModel.java b/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityListTableModel.java index 2c264bb907d5a72def7e5e14c6b39cf07a9c6e44..fb80cfbef5266f1b2d968d608081e50f0ac79070 100644 --- a/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityListTableModel.java +++ b/src/main/java/org/olat/modules/assessment/ui/AssessedIdentityListTableModel.java @@ -137,7 +137,9 @@ public class AssessedIdentityListTableModel extends DefaultFlexiTableDataModel<A return certificateMap.get(row.getIdentityKey()); } case initialLaunchDate: return row.getInitialCourseLaunchDate(); - case lastScoreUpdate: return row.getLastModified(); + case lastModified: return row.getLastModified(); + case lastUserModified: return row.getLastUserModified(); + case lastCoachModified: return row.getLastCoachModified(); } } int propPos = col - AssessmentToolConstants.USER_PROPS_OFFSET; @@ -160,7 +162,9 @@ public class AssessedIdentityListTableModel extends DefaultFlexiTableDataModel<A assessmentStatus("table.header.assessmentStatus"), certificate("table.header.certificate"), initialLaunchDate("table.header.initialLaunchDate"), - lastScoreUpdate("table.header.lastScoreDate"); + lastModified("table.header.lastScoreDate"), + lastUserModified("table.header.lastUserModificationDate"), + lastCoachModified("table.header.lastCoachModificationDate"); private final String i18nKey; diff --git a/src/main/java/org/olat/modules/card2brain/Card2BrainManager.java b/src/main/java/org/olat/modules/card2brain/Card2BrainManager.java index 246cba6173d5bfa15f08aad17109f997f9961940..4ce85ab37d740d86b3fda1c47acd10cff65c8fa7 100644 --- a/src/main/java/org/olat/modules/card2brain/Card2BrainManager.java +++ b/src/main/java/org/olat/modules/card2brain/Card2BrainManager.java @@ -46,4 +46,15 @@ public interface Card2BrainManager { */ public Card2BrainVerificationResult checkEnterpriseLogin(String url, String key, String secret); + /** + * Parse the alias of the set of flashcards. Remove the unnecessary part + * if someone inserts the whole weblink from the card2brain website e.g. + * https://card2brain.ch/box/20170420_02_chemie_und_werkstoffe. + * + * @param alias + * the original alias value + * @return the parsed String + */ + public String parseAlias(String alias); + } diff --git a/src/main/java/org/olat/modules/card2brain/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/card2brain/ui/_i18n/LocalStrings_fr.properties index 9480110b6f3fcfb9d0f423b1abcec8c0c25a0ba7..3081ee884fe6060f106f9f34a4b4d1eee050358b 100644 --- a/src/main/java/org/olat/modules/card2brain/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/card2brain/ui/_i18n/LocalStrings_fr.properties @@ -1,9 +1,23 @@ -#Wed Jun 28 13:36:15 CEST 2017 +#Thu Jul 06 21:26:35 CEST 2017 admin.baseUrl=URL +admin.baseUrlHelpText=Utiliser '%s' comme texte de substitution pour l'alias des cartes d'apprentissage. +admin.description=card2brain est une application multi-canales pour l'apprentissage syst\u00E9matique de tous les domaines du savoir. Sur card2brain, vous pouvez cr\u00E9er des cartes d'apprentissage et les \u00E9tudier selon le syst\u00E8me \u00E0 cinq compartiments bien connu de Sebastian Leitner. Vous trouverez plus d'informations sur <a href\="http\://card2brain.ch" target\=_blank>card2brain.ch</a>. admin.enabled=Module "card2brain" admin.enterpriseKey=API Key +admin.enterpriseLoginEnabled=Authentification compte d'entreprise +admin.enterpriseLoginHelpText=Pour utiliser l'authentification entreprise, un compte d'entreprise chez card2brain est n\u00E9cessaire. admin.enterpriseLoginHelpUrl=https\://card2brain.ch/register/index?licence\=multiple&lang\=fr admin.enterpriseSecret=API Secret +admin.expertSettings=Configurations avanc\u00E9es admin.menu.title=card2brain +admin.menu.title.alt=card2brain admin.peekViewUrl=URL de l'aper\u00E7u +admin.peekViewUrlHelpText=Utiliser '%s' comme texte de substitution pour l'alias des cartes d'apprentissage. +admin.privateLoginEnabled=Authentification compte priv\u00E9 +admin.privateLoginHelpText=Montrer le champ d'authentification dans l'\u00E9l\u00E9ment de cours. admin.title=Configuration +admin.verifyKeySecret.button=V\u00E9rifier la paire Key/Secret +admin.verifyKeySecret.invalid=Key et Secret sont invalides. La r\u00E9ponse du serveur card2brain est la suivante\: {0} +admin.verifyKeySecret.unavaible=La v\u00E9rification n'a pas \u00EAtre effectu\u00E9e avec succ\u00E8s. +admin.verifyKeySecret.url=Lien LTI pour v\u00E9rification Key/Secret +admin.verifyKeySecret.valid=Key/Secret sont correctes. diff --git a/src/main/java/org/olat/modules/co/ContactForm.java b/src/main/java/org/olat/modules/co/ContactForm.java index 37229b53167bf7dac9c09d0ba96d1016ed4cb18f..b1f0ad06cb80cad008ca9dc926bea1c253708022 100644 --- a/src/main/java/org/olat/modules/co/ContactForm.java +++ b/src/main/java/org/olat/modules/co/ContactForm.java @@ -53,6 +53,7 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.util.CSSHelper; import org.olat.core.id.Identity; import org.olat.core.util.FileUtils; +import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.filter.FilterFactory; @@ -351,12 +352,13 @@ public class ContactForm extends FormBasicController { } attachmentEl.reset(); attachmentSize += size; - FormLink removeFile = uifactory.addFormLink(attachment.getName(), "delete", null, uploadCont, Link.BUTTON_SMALL); + FormLink removeFile = uifactory.addFormLink(attachment.getName(), "delete", null, uploadCont, Link.BUTTON_XSMALL); + removeFile.setIconLeftCSS("o_icon o_icon-fw o_icon_delete"); removeFile.setUserObject(attachment); attachmentLinks.add(removeFile); //pretty labels uploadCont.setLabel(NLS_CONTACT_ATTACHMENT, null); - attachmentNames.put(attachment.getName(), filename); + attachmentNames.put(attachment.getName(), filename + " <span class='text-muted'>(" + Formatter.formatBytes(size) + ")</span>"); attachmentCss.put(attachment.getName(), CSSHelper.createFiletypeIconCssClassFor(filename)); uploadCont.contextPut("attachments", attachmentLinks); uploadCont.contextPut("attachmentNames", attachmentNames); @@ -430,6 +432,7 @@ public class ContactForm extends FormBasicController { } } + @Override protected void doDispose() { cleanUpAttachments(); diff --git a/src/main/java/org/olat/modules/co/_content/attachments.html b/src/main/java/org/olat/modules/co/_content/attachments.html index 0398b274e0d753be4421390010d625eec0f8c0ab..684ec9636ef69140c2100c15ed78cc21b7d51e42 100644 --- a/src/main/java/org/olat/modules/co/_content/attachments.html +++ b/src/main/java/org/olat/modules/co/_content/attachments.html @@ -1,7 +1,8 @@ -<ul class="list-unstyled"> +<ul class="list-unstyled form-control-static"> #foreach ($attachment in $attachments) - <li> - <i class="o_icon o_icon-fw $r.getFiletypeIconCss($attachment.getName())"> </i>${attachmentNames.get($attachment.getName())} + <li class='clearfix o_highlight_on_hover'> + <span class="pull-right">$r.render("$attachment.getName()")</span> + <i class="o_icon o_icon-fw $r.getFiletypeIconCss($attachment.getName())"> </i>${attachmentNames.get($attachment.getName())} </li> #end </ul> diff --git a/src/main/java/org/olat/modules/coach/ui/CourseController.java b/src/main/java/org/olat/modules/coach/ui/CourseController.java index c41176c880430eed46c2c7b7980634befed9910d..9b7f5c422945371dc2a337d2ff186a3ad7cdbb5b 100644 --- a/src/main/java/org/olat/modules/coach/ui/CourseController.java +++ b/src/main/java/org/olat/modules/coach/ui/CourseController.java @@ -31,6 +31,7 @@ import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; @@ -89,7 +90,7 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class CourseController extends FormBasicController implements Activateable2, GenericEventListener, TooledController { - private final Link openCourse; + private FormLink openCourse; private Link nextCourse, detailsCourseCmp, previousCourse; private FlexiTableElement tableEl; @@ -138,10 +139,6 @@ public class CourseController extends FormBasicController implements Activateabl initForm(ureq); loadModel(); - openCourse = LinkFactory.createButton("open", flc.getFormItemComponent(), this); - openCourse.setIconLeftCSS("o_icon o_CourseModule_icon"); - flc.getFormItemComponent().put("open.group", openCourse); - CoordinatorManager.getInstance().getCoordinator().getEventBus() .registerFor(this, getIdentity(), CertificatesManager.ORES_CERTIFICATE_EVENT); } @@ -171,6 +168,9 @@ public class CourseController extends FormBasicController implements Activateabl @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + openCourse = uifactory.addFormLink("open.course", formLayout, Link.BUTTON); + openCourse.setIconLeftCSS("o_icon o_CourseModule_icon"); + if(formLayout instanceof FormLayoutContainer) { FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; layoutCont.contextPut("courseName", StringHelper.escapeHtml(course.getDisplayname())); @@ -200,7 +200,9 @@ public class CourseController extends FormBasicController implements Activateabl columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.recertification, new DateFlexiCellRenderer(getLocale()))); } } - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastModification)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Columns.lastModification)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastUserModified)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Columns.lastCoachModified)); model = new EfficiencyStatementEntryTableDataModel(columnsModel); tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout); @@ -275,7 +277,9 @@ public class CourseController extends FormBasicController implements Activateabl doSelectDetails(ureq, selectedRow); } } - } + } else if (source == openCourse) { + doOpenCourse(ureq); + } super.formInnerEvent(ureq, source, event); } @@ -290,8 +294,6 @@ public class CourseController extends FormBasicController implements Activateabl reloadModel(); } } - } else if (source == openCourse) { - doOpenCourse(ureq); } super.event(ureq, source, event); } diff --git a/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java b/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java index e798b68171539a53cccc1b886ca33dd97ca50f53..dd91320d55aa50b0df42eab353ba0139a71dcc4a 100644 --- a/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java +++ b/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java @@ -119,6 +119,14 @@ public class EfficiencyStatementEntryTableDataModel extends DefaultFlexiTableDat UserEfficiencyStatement s = entry.getUserEfficencyStatement(); return s == null ? null : s.getLastModified(); } + case lastUserModified: { + UserEfficiencyStatement s = entry.getUserEfficencyStatement(); + return s == null ? null : s.getLastUserModified(); + } + case lastCoachModified: { + UserEfficiencyStatement s = entry.getUserEfficencyStatement(); + return s == null ? null : s.getLastCoachModified(); + } case plannedLectures: { LectureBlockStatistics statistics = getLectureBlockStatistics(entry); return statistics == null ? null : statistics.getTotalPersonalPlannedLectures(); @@ -184,6 +192,8 @@ public class EfficiencyStatementEntryTableDataModel extends DefaultFlexiTableDat recertification("table.header.recertification"), progress("table.header.progress"), lastModification("table.header.lastScoreDate"), + lastUserModified("table.header.lastUserModificationDate"), + lastCoachModified("table.header.lastCoachModificationDate"), plannedLectures("table.header.planned.lectures"), attendedLectures("table.header.attended.lectures"), absentLectures("table.header.absent.lectures"), diff --git a/src/main/java/org/olat/modules/coach/ui/GroupController.java b/src/main/java/org/olat/modules/coach/ui/GroupController.java index 8a7d81863e9d16c6b39feb3854e1c8d52b090ad3..34627732203bb1c13e05b2997e542f8185012667 100644 --- a/src/main/java/org/olat/modules/coach/ui/GroupController.java +++ b/src/main/java/org/olat/modules/coach/ui/GroupController.java @@ -192,7 +192,9 @@ public class GroupController extends FormBasicController implements Activateable columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.score, new ScoreCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.certificate, new DownloadCertificateCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.recertification, new DateFlexiCellRenderer(getLocale()))); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastModification)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Columns.lastModification)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastUserModified)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Columns.lastCoachModified)); model = new EfficiencyStatementEntryTableDataModel(columnsModel); tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout); diff --git a/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java b/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java index 1803bf62ab2cfc022376a9f54f9235d7ca1338ac..d4564cc9b1fcd82baf69cf4e8c7cece616d6209e 100644 --- a/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java +++ b/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java @@ -216,7 +216,9 @@ public class StudentCoursesController extends FormBasicController implements Act columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.authorizedAbsenceLectures)); } } - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastModification)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Columns.lastModification)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastUserModified)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Columns.lastCoachModified)); model = new EfficiencyStatementEntryTableDataModel(columnsModel); tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout); diff --git a/src/main/java/org/olat/modules/coach/ui/UserEfficiencyStatementTableDataModel.java b/src/main/java/org/olat/modules/coach/ui/UserEfficiencyStatementTableDataModel.java index a63784518862f8e5e1aec1620f67c5e6c1425d42..a5f39cd2291bc595136a613bc6a7e18793c9a368 100644 --- a/src/main/java/org/olat/modules/coach/ui/UserEfficiencyStatementTableDataModel.java +++ b/src/main/java/org/olat/modules/coach/ui/UserEfficiencyStatementTableDataModel.java @@ -24,7 +24,6 @@ import java.util.List; import org.olat.core.gui.components.table.TableDataModel; import org.olat.course.assessment.UserEfficiencyStatement; -import org.olat.modules.coach.model.EfficiencyStatementEntry; /** * @@ -94,10 +93,6 @@ public class UserEfficiencyStatementTableDataModel implements TableDataModel<Use public UserEfficiencyStatement getObject(int row) { return group.get(row); } - - public int indexOf(EfficiencyStatementEntry obj) { - return group.indexOf(obj); - } @Override public void setObjects(List<UserEfficiencyStatement> objects) { diff --git a/src/main/java/org/olat/modules/coach/ui/_content/course.html b/src/main/java/org/olat/modules/coach/ui/_content/course.html index 554dd9746eec37756adc298df5ccdcd143f71af8..b1e3ce94d06a3286f26aa3ccc88477ee0d7e3b2d 100644 --- a/src/main/java/org/olat/modules/coach/ui/_content/course.html +++ b/src/main/java/org/olat/modules/coach/ui/_content/course.html @@ -1,7 +1,7 @@ <div class="o_header_with_buttons"> <h3><i class="o_icon o_CourseModule_icon"> </i> $courseName</h3> - #if($r.available("open")) - <div class="o_button_group">$r.render("open")</div> + #if($r.available("open.course")) + <div class="o_button_group">$r.render("open.course")</div> #end </div> $r.render("table") diff --git a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_de.properties index ac6edd14f7b61c1ad14be545035715ba8a8cb0fa..a685c759bc589c2ab5c9105753bb3b65fa375a42 100644 --- a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_de.properties @@ -27,8 +27,8 @@ next.group=\$:next next.student=\$:next next=N\u00e4chste only.active=Nur aktiven -open.course=\$:open -open.group=\$:open +open.course=Kurs \u00F6ffnen +open.group=Gruppe \u00F6ffnen open=\u00D6ffnen passed.false=$org.olat.course.assessment\:passed.false passed.true=$org.olat.course.assessment\:passed.true @@ -54,6 +54,8 @@ table.header.countCourses=# Kurs table.header.countStudents=# Teilnehmer table.header.course.name=Kurs table.header.lastScoreDate=$org.olat.course.assessment\:table.header.lastScoreDate +table.header.lastUserModificationDate=$org.olat.course.assessment\:table.header.lastUserModificationDate +table.header.lastCoachModificationDate=$org.olat.course.assessment\:table.header.lastCoachModificationDate table.header.login=Eingeloggt table.header.passed=$org.olat.course.assessment\:table.header.passed table.header.progress=Fortschritt @@ -64,4 +66,5 @@ table.header.planned.lectures=$org.olat.modules.lecture.ui\:table.header.planned table.header.attended.lectures=$org.olat.modules.lecture.ui\:table.header.attended.lectures table.header.absent.lectures=$org.olat.modules.lecture.ui\:table.header.absent.lectures table.header.authorized.absence=$org.olat.modules.lecture.ui\:table.header.authorized.absence +table.header.unauthorized.absence=$org.olat.modules.lecture.ui\:table.header.unauthorized.absence tooltip.of={0} von {1} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_en.properties index 4d6a0bd8bcaaa4da670854e64e2ebd28ad9a9b78..091fd79bd70b3893781f4a99a65cfda282b799c2 100644 --- a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_en.properties @@ -1,11 +1,11 @@ -#Wed Dec 17 15:24:45 CET 2014 +#Fri Aug 18 08:56:17 CEST 2017 coaching.enabled=Coaching enable coaching.on=on coaching.title=Coaching title contact.link=Contact contact.title=Contact -courses.menu.title.alt=Courses courses.menu.title=Courses +courses.menu.title.alt=Courses details.assessment=Assessment tool details.lectures=Lectures details.statement=Efficiency statement @@ -13,55 +13,58 @@ error.no.found=Nichts gefunden error.search.form.notempty=$org.olat.admin.user\:error.search.form.notempty error.search.form.too.many=Too many search results. Please narrow down your search group.name=Name -groups.menu.title.alt=Groups groups.menu.title=Groups +groups.menu.title.alt=Groups +home.link=visiting card lectures.menu.title=Lectures lectures.menu.title.alt=Lectures and absences management -home.link=visiting card -main.menu.title.alt=$\:site.title.alt main.menu.title=$\:site.title -menu.coaching.alt=$\:site.title.alt +main.menu.title.alt=$\:site.title.alt menu.coaching=$\:site.title +menu.coaching.alt=$\:site.title.alt +next=Next next.course=$\:next next.group=$\:next next.student=$\:next -next=Next only.active=Only active -open.course=$\:open -open.group=$\:open open=open +open.course=Open course +open.group=Open group passed.false=$org.olat.course.assessment\:passed.false passed.true=$org.olat.course.assessment\:passed.true +previous=Previous previous.course=$\:previous previous.group=$\:previous previous.student=$\:previous -previous=Previous results=Results +search=Search search.form.login=User name -search.menu.title.alt=User search search.menu.title=User search -search=Search -site.title.alt=Coaching +search.menu.title.alt=User search site.title=Coaching +site.title.alt=Coaching student.name=Name students.details={0} {1}/{2} -students.menu.title.alt=Members students.menu.title=Members +students.menu.title.alt=Members table.action.show=$org.olat.course.assessment\:table.action.show +table.header.absent.lectures=$org.olat.modules.lecture.ui\:table.header.absent.lectures +table.header.attended.lectures=$org.olat.modules.lecture.ui\:table.header.attended.lectures +table.header.authorized.absence=$org.olat.modules.lecture.ui\:table.header.authorized.absence +table.header.unauthorized.absence=$org.olat.modules.lecture.ui\:table.header.unauthorized.absence table.header.averageScore=Average table.header.certificate=Certificate table.header.countCourses=\# Courses table.header.countStudents=\# Members table.header.course.name=Courses +table.header.lastCoachModificationDate=$org.olat.course.assessment\:table.header.lastCoachModificationDate table.header.lastScoreDate=$org.olat.course.assessment\:table.header.lastScoreDate +table.header.lastUserModificationDate=$org.olat.course.assessment\:table.header.lastUserModificationDate table.header.login=Logged in table.header.passed=$org.olat.course.assessment\:table.header.passed +table.header.planned.lectures=$org.olat.modules.lecture.ui\:table.header.planned.lectures table.header.progress=Progress table.header.recertification=Recertification table.header.score=$org.olat.course.assessment\:table.header.score table.header.show=$org.olat.course.assessment\:table.header.show -table.header.planned.lectures=$org.olat.modules.lecture.ui\:table.header.planned.lectures -table.header.attended.lectures=$org.olat.modules.lecture.ui\:table.header.attended.lectures -table.header.absent.lectures=$org.olat.modules.lecture.ui\:table.header.absent.lectures -table.header.authorized.absence=$org.olat.modules.lecture.ui\:table.header.authorized.absence tooltip.of={0} of {1} diff --git a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_fr.properties index 1d0b768e144af4442a18ea84c3f8b47eaee3379e..7d2074b0b37e9582b0edbe9b6bf0ab490cb1bd81 100644 --- a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Mon Nov 14 21:35:11 CET 2016 +#Sun Aug 27 16:11:02 CEST 2017 coaching.enabled=Acc\u00E8s coaching coaching.on=on coaching.title=Coaching @@ -7,6 +7,7 @@ contact.title=Contacter courses.menu.title=Mes cours courses.menu.title.alt=Mes cours details.assessment=Outil d'\u00E9valuation +details.lectures=Cours blocs details.statement=Attestation de perfomance error.no.found=Rien trouv\u00E9 error.search.form.notempty=$org.olat.admin.user\:error.search.form.notempty @@ -15,6 +16,8 @@ group.name=Groupe groups.menu.title=Mes groupes groups.menu.title.alt=Mes groupes home.link=Carte-de-visite +lectures.menu.title=Cours blocs +lectures.menu.title.alt=Administration des cours blocs et des absences main.menu.title=$\:site.title main.menu.title.alt=$\:site.title.alt menu.coaching=$\:site.title @@ -45,14 +48,20 @@ students.details={0} {1}/{2} students.menu.title=Mes \u00E9tudiants students.menu.title.alt=Mes \u00E9tudiants table.action.show=$org.olat.course.assessment\:table.action.show +table.header.absent.lectures=$org.olat.modules.lecture.ui\:table.header.absent.lectures +table.header.attended.lectures=$org.olat.modules.lecture.ui\:table.header.attended.lectures +table.header.authorized.absence=$org.olat.modules.lecture.ui\:table.header.authorized.absence table.header.averageScore=Moyenne table.header.certificate=Certificat table.header.countCourses=\# cours table.header.countStudents=\# participants table.header.course.name=Cours +table.header.lastCoachModificationDate=$org.olat.course.assessment\:table.header.lastCoachModificationDate table.header.lastScoreDate=$org.olat.course.assessment\:table.header.lastScoreDate +table.header.lastUserModificationDate=$org.olat.course.assessment\:table.header.lastUserModificationDate table.header.login=Connect\u00E9 table.header.passed=$org.olat.course.assessment\:table.header.passed +table.header.planned.lectures=$org.olat.modules.lecture.ui\:table.header.planned.lectures table.header.progress=Progression table.header.recertification=Recertification table.header.score=$org.olat.course.assessment\:table.header.score diff --git a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_pt_BR.properties index 84b419a9f7acd9828fdd5db5ae7dd7c2560a273e..474779fa31bcedf405fcc605706b4c6b6b716b82 100644 --- a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Mon Nov 21 20:25:39 CET 2016 +#Tue Sep 05 19:40:09 CEST 2017 coaching.enabled=Coaching ativo coaching.on=Ativo coaching.title=T\u00EDtulo do Treinador @@ -7,6 +7,7 @@ contact.title=Contato courses.menu.title=Meu curso courses.menu.title.alt=Meu curso details.assessment=Ferramenta de avalia\u00E7\u00E3o +details.lectures=Palestras details.statement=Comprovante de conclus\u00E3o error.no.found=N\u00E3o encontrado error.search.form.notempty=$org.olat.admin.user\:error.search.form.notempty @@ -15,6 +16,8 @@ group.name=Grupo groups.menu.title=Meu grupo groups.menu.title.alt=Meu grupo home.link=Cart\u00E3o de visitas +lectures.menu.title=Palestras (li\u00E7\u00F5es) +lectures.menu.title.alt=Gest\u00E3o de palestras e faltas (aus\u00EAncias) main.menu.title=$\:site.title main.menu.title.alt=$\:site.title.alt menu.coaching=$\:site.title @@ -45,14 +48,20 @@ students.details={0} {1}/{2} students.menu.title=Meus alunos students.menu.title.alt=Meus estudantes table.action.show=$org.olat.course.assessment\:table.action.show +table.header.absent.lectures=$org.olat.modules.lecture.ui\:table.header.absent.lectures +table.header.attended.lectures=$org.olat.modules.lecture.ui\:table.header.attended.lectures +table.header.authorized.absence=$org.olat.modules.lecture.ui\:table.header.authorized.absence table.header.averageScore=M\u00E9dia table.header.certificate=Certificado table.header.countCourses=\# Cursos table.header.countStudents=\# Membros table.header.course.name=Cursos +table.header.lastCoachModificationDate=$org.olat.course.assessment\:table.header.lastCoachModificationDate table.header.lastScoreDate=$org.olat.course.assessment\:table.header.lastScoreDate +table.header.lastUserModificationDate=$org.olat.course.assessment\:table.header.lastUserModificationDate table.header.login=Logados table.header.passed=$org.olat.course.assessment\:table.header.passed +table.header.planned.lectures=$org.olat.modules.lecture.ui\:table.header.planned.lectures table.header.progress=Progresso table.header.recertification=Re-certifica\u00E7\u00E3o table.header.score=$org.olat.course.assessment\:table.header.score diff --git a/src/main/java/org/olat/modules/cp/CPDisplayController.java b/src/main/java/org/olat/modules/cp/CPDisplayController.java index 891c5dc6e54d6d41d1838947de48445aafff795d..035d50b4d8b41bd244602804059426a909b6c3c2 100644 --- a/src/main/java/org/olat/modules/cp/CPDisplayController.java +++ b/src/main/java/org/olat/modules/cp/CPDisplayController.java @@ -68,10 +68,12 @@ import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSMediaResource; import org.olat.course.ICourse; +import org.olat.search.SearchModule; import org.olat.search.SearchServiceUIFactory; import org.olat.search.SearchServiceUIFactory.DisplayOption; import org.olat.search.ui.SearchInputController; import org.olat.util.logging.activity.LoggingResourceable; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -100,6 +102,9 @@ public class CPDisplayController extends BasicController implements Activateable private CPSelectPrintPagesController printController; private CloseableModalController printPopup; + @Autowired + private SearchModule searchModule; + /** * @param ureq * @param cpRoot @@ -119,7 +124,7 @@ public class CPDisplayController extends BasicController implements Activateable myContent = createVelocityContainer("cpcontent"); // the cp component, added to the velocity - if(!ureq.getUserSession().getRoles().isGuestOnly()) { + if(searchModule.isSearchAllowed(ureq.getUserSession().getRoles())) { SearchServiceUIFactory searchServiceUIFactory = (SearchServiceUIFactory)CoreSpringFactory.getBean(SearchServiceUIFactory.class); searchCtrl = searchServiceUIFactory.createInputController(ureq, wControl, DisplayOption.BUTTON, null); myContent.put("search_input", searchCtrl.getInitialComponent()); diff --git a/src/main/java/org/olat/modules/fo/portfolio/ForumMediaHandler.java b/src/main/java/org/olat/modules/fo/portfolio/ForumMediaHandler.java index 3092fe515146f466622a9027105c775b9af5d822..ef47808a23cf8cb58310dd8e8607776d8edd63f9 100644 --- a/src/main/java/org/olat/modules/fo/portfolio/ForumMediaHandler.java +++ b/src/main/java/org/olat/modules/fo/portfolio/ForumMediaHandler.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -42,6 +43,7 @@ import org.olat.modules.fo.manager.ForumManager; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.handler.AbstractMediaHandler; import org.olat.modules.portfolio.manager.MediaDAO; @@ -160,8 +162,8 @@ public class ForumMediaHandler extends AbstractMediaHandler { } @Override - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { - return new ForumMessageMediaController(ureq, wControl, media); + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { + return new ForumMessageMediaController(ureq, wControl, media, hints); } @Override diff --git a/src/main/java/org/olat/modules/fo/portfolio/ForumMessageMediaController.java b/src/main/java/org/olat/modules/fo/portfolio/ForumMessageMediaController.java index 266540401cacee386ad1820422ed5ad644d038b6..9ca0ed954647f5655068ac5a7f43287bdaf2b257 100644 --- a/src/main/java/org/olat/modules/fo/portfolio/ForumMessageMediaController.java +++ b/src/main/java/org/olat/modules/fo/portfolio/ForumMessageMediaController.java @@ -31,11 +31,17 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.util.CSSHelper; import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.filters.SystemItemFilter; import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.MediaRenderingHints; +import org.olat.modules.portfolio.ui.MediaMetadataController; +import org.olat.modules.portfolio.ui.PortfolioHomeController; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -44,12 +50,25 @@ import org.olat.modules.portfolio.Media; * */ public class ForumMessageMediaController extends BasicController { + + @Autowired + private UserManager userManager; - public ForumMessageMediaController(UserRequest ureq, WindowControl wControl, Media media) { + public ForumMessageMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { super(ureq, wControl); + setTranslator(Util.createPackageTranslator(PortfolioHomeController.class, getLocale(), getTranslator())); VelocityContainer mainVC = createVelocityContainer("messageDetails"); mainVC.contextPut("text", media.getContent()); + + String desc = media.getDescription(); + mainVC.contextPut("description", StringHelper.containsNonWhitespace(desc) ? desc : null); + String title = media.getTitle(); + mainVC.contextPut("title", StringHelper.containsNonWhitespace(title) ? title : null); + + mainVC.contextPut("creationdate", media.getCreationDate()); + mainVC.contextPut("author", userManager.getUserDisplayName(media.getAuthor())); + if (StringHelper.containsNonWhitespace(media.getStoragePath())) { VFSContainer attachmentsContainer = new OlatRootFolderImpl("/" + media.getStoragePath(), null); List<VFSItem> attachments = attachmentsContainer.getItems(new SystemItemFilter()); @@ -66,7 +85,14 @@ public class ForumMessageMediaController extends BasicController { } mainVC.contextPut("attachments", attachments); mainVC.contextPut("hasAttachments", true); - } + + } + + if(hints.isExtendedMetadata()) { + MediaMetadataController metaCtrl = new MediaMetadataController(ureq, wControl, media); + listenTo(metaCtrl); + mainVC.put("meta", metaCtrl.getInitialComponent()); + } putInitialPanel(mainVC); } diff --git a/src/main/java/org/olat/modules/fo/portfolio/_content/messageDetails.html b/src/main/java/org/olat/modules/fo/portfolio/_content/messageDetails.html index 41e274a463aac5b8498cf629544a942d8608441f..dd1808c738b08e03e26af2e1766bb99be6fe48a8 100644 --- a/src/main/java/org/olat/modules/fo/portfolio/_content/messageDetails.html +++ b/src/main/java/org/olat/modules/fo/portfolio/_content/messageDetails.html @@ -1,15 +1,27 @@ <div class="o_forum"> -$text -#if ($hasAttachments) -<div class="o_forum_message_attachments" style="border-top-style:hidden;"> - <strong>$r.translateWithPackage("org.olat.modules.fo","attachments")</strong> - <ul> - #foreach( $attachment in $attachments ) - #set( $fsize = $attachment.getSize() / 1024 ) - #set( $downlCompName = "download${velocityCount}") - <li>$r.render($downlCompName)</li> - #end - </ul> -</div> -#end + #if($title) + <h5> + $title + <small>$r.translate("document.by",$author)</small> + </h5> + #end + + $text + #if ($hasAttachments) + <div class="o_forum_message_attachments" style="border-top-style:hidden;"> + <strong>$r.translateWithPackage("org.olat.modules.fo","attachments")</strong> + <ul> + #foreach( $attachment in $attachments ) + #set( $fsize = $attachment.getSize() / 1024 ) + #set( $downlCompName = "download${velocityCount}") + <li>$r.render($downlCompName)</li> + #end + </ul> + </div> + #end + #if($r.available("meta")) + <div class="panel panel-default o_artefact_metadata"> + $r.render("meta") + </div> + #end </div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/fo/restapi/ForumWebService.java b/src/main/java/org/olat/modules/fo/restapi/ForumWebService.java index 66e0646573f3f63bb197afa68cd4f0cd940f2396..484c84d8e149dd66fa4f7a02e15940a0d408bcbf 100644 --- a/src/main/java/org/olat/modules/fo/restapi/ForumWebService.java +++ b/src/main/java/org/olat/modules/fo/restapi/ForumWebService.java @@ -130,11 +130,11 @@ public class ForumWebService { /** * Retrieves the threads in the forum * @response.representation.200.qname {http://www.example.com}messageVOes - * @response.representation.200.mediaType application/xml, application/json - * @response.representation.200.doc The root message of the thread - * @response.representation.200.example {@link org.olat.modules.fo.restapi.Examples#SAMPLE_MESSAGEVOes} + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The root message of the thread + * @response.representation.200.example {@link org.olat.modules.fo.restapi.Examples#SAMPLE_MESSAGEVOes} * @response.representation.401.doc The roles of the authenticated user are not sufficient - * @response.representation.404.doc The author, forum or message not found + * @response.representation.404.doc The author, forum or message not found * @param start * @param limit * @param orderBy (value name,creationDate) diff --git a/src/main/java/org/olat/modules/fo/ui/MessageEditController.java b/src/main/java/org/olat/modules/fo/ui/MessageEditController.java index 6e34e26efc3c70df773ab79d7635c1cdc67f5a8b..d30f49dc10527830b23d6c6e00e6ade42f62f0cb 100644 --- a/src/main/java/org/olat/modules/fo/ui/MessageEditController.java +++ b/src/main/java/org/olat/modules/fo/ui/MessageEditController.java @@ -179,6 +179,7 @@ public class MessageEditController extends FormBasicController { bodyEl.setNotEmptyCheck("error.field.not.empty"); bodyEl.setMaxLength(MAX_BODY_LENGTH); bodyEl.setNotLongerThanCheck(MAX_BODY_LENGTH, "input.toolong"); + bodyEl.getEditorConfiguration().enableCharCount(); setEditPermissions(message); // list existing attachments. init attachment layout now, to place it in diff --git a/src/main/java/org/olat/modules/fo/ui/MessageListController.java b/src/main/java/org/olat/modules/fo/ui/MessageListController.java index ce8536ebf522a805cf1f7ed55846ca3f344e542a..30c9eb6e36588037077e5820f204e5ad961a67a2 100644 --- a/src/main/java/org/olat/modules/fo/ui/MessageListController.java +++ b/src/main/java/org/olat/modules/fo/ui/MessageListController.java @@ -30,6 +30,7 @@ import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.olat.basesecurity.BaseSecurityModule; +import org.olat.core.commons.fullWebApp.popup.BaseFullWebappPopupLayoutFactory; import org.olat.core.commons.modules.bc.meta.MetaInfo; import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; import org.olat.core.commons.persistence.DBFactory; @@ -47,10 +48,12 @@ 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.controller.BasicController; +import org.olat.core.gui.control.creator.ControllerCreator; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.gui.control.generic.popup.PopupBrowserWindow; import org.olat.core.gui.control.generic.wizard.Step; import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; import org.olat.core.gui.control.generic.wizard.StepsMainRunController; @@ -109,6 +112,7 @@ import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.resource.OLATResourceManager; import org.olat.user.DisplayPortraitController; +import org.olat.user.UserInfoMainController; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; import org.olat.util.logging.activity.LoggingResourceable; @@ -645,7 +649,7 @@ public class MessageListController extends BasicController implements GenericEve // Add link with username that is clickable String creatorFullName = StringHelper.escapeHtml(UserManager.getInstance().getUserDisplayName(creator)); Link visitingCardLink = LinkFactory.createCustomLink("vc_".concat(keyString), "vc", creatorFullName, Link.LINK_CUSTOM_CSS + Link.NONTRANSLATED, mainVC, this); - visitingCardLink.setUserObject(messageView); + visitingCardLink.setUserObject(creator); LinkPopupSettings settings = new LinkPopupSettings(800, 600, "_blank"); visitingCardLink.setPopup(settings); } @@ -777,7 +781,6 @@ public class MessageListController extends BasicController implements GenericEve Link link = (Link)source; String command = link.getCommand(); Object uobject = link.getUserObject(); - if (command.startsWith("qt")) { doReply(ureq, (MessageView)uobject, true); } else if (command.startsWith("rp")) { @@ -792,6 +795,8 @@ public class MessageListController extends BasicController implements GenericEve doMoveMessage(ureq, (MessageView)uobject); } else if (command.startsWith("exile")) { doExportForumItem(ureq, (MessageView)uobject); + } else if(command.equals("vc")) { + doOpenVisitingCard(ureq, (Identity)uobject); } } else if(mainVC == source) { String cmd = event.getCommand(); @@ -1301,7 +1306,11 @@ public class MessageListController extends BasicController implements GenericEve } } mainVC.contextPut("messages", oneView); - messageTableCtrl.setSelectView(oneView.get(0)); + if(oneView.size() > 0) { + messageTableCtrl.setSelectView(oneView.get(0)); + } else { + showWarning("error.message.deleted"); + } messageTableCtrl.loadMessages(new ArrayList<>(backupViews)); } } @@ -1418,6 +1427,19 @@ public class MessageListController extends BasicController implements GenericEve } } + private void doOpenVisitingCard(UserRequest ureq, Identity creator) { + ControllerCreator userInfoMainControllerCreator = new ControllerCreator() { + @Override + public Controller createController(UserRequest lureq, WindowControl lwControl) { + return new UserInfoMainController(lureq, lwControl, creator, true, false); + } + }; + //wrap the content controller into a full header layout + ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, userInfoMainControllerCreator); + PopupBrowserWindow pbw = getWindowControl().getWindowBackOffice().getWindowManager().createNewPopupBrowserWindowFor(ureq, layoutCtrlr); + pbw.open(ureq); + } + public enum LoadMode { thread, userMessages, diff --git a/src/main/java/org/olat/modules/fo/ui/ThreadListController.java b/src/main/java/org/olat/modules/fo/ui/ThreadListController.java index 53d32a7de2dd85a48645abd171d79c75321bc437..6583e94752f3da876b1a5b331c83c19f754e3e52 100644 --- a/src/main/java/org/olat/modules/fo/ui/ThreadListController.java +++ b/src/main/java/org/olat/modules/fo/ui/ThreadListController.java @@ -62,6 +62,7 @@ import org.olat.modules.fo.ui.MessageEditController.EditMode; import org.olat.modules.fo.ui.ThreadListDataModel.ThreadListCols; import org.olat.modules.fo.ui.events.SelectMessageEvent; import org.olat.modules.fo.ui.events.SelectUserListEvent; +import org.olat.search.SearchModule; import org.olat.search.SearchServiceUIFactory; import org.olat.search.SearchServiceUIFactory.DisplayOption; import org.olat.search.ui.SearchInputController; @@ -87,6 +88,8 @@ public class ThreadListController extends FormBasicController { private final boolean guestOnly; private final ForumCallback foCallback; + @Autowired + private SearchModule searchModule; @Autowired private ForumManager forumManager; @Autowired @@ -124,6 +127,10 @@ public class ThreadListController extends FormBasicController { if(formLayout instanceof FormLayoutContainer) { SearchServiceUIFactory searchServiceUIFactory = (SearchServiceUIFactory)CoreSpringFactory.getBean(SearchServiceUIFactory.class); searchController = searchServiceUIFactory.createInputController(ureq, getWindowControl(), DisplayOption.STANDARD, mainForm); + if(guestOnly && !searchModule.isGuestEnabled()) { + searchController.setResourceContextEnable(false); + } + listenTo(searchController); ((FormLayoutContainer)formLayout).add("search_input", searchController.getFormItem()); } diff --git a/src/main/java/org/olat/modules/forms/handler/HTMLRawHandler.java b/src/main/java/org/olat/modules/forms/handler/HTMLRawHandler.java index 517f1eaf5f91d04dbfbbf3bfa039584b0ef4723c..5264d44b20a2501d3f651cea9d8582005cfbd099 100644 --- a/src/main/java/org/olat/modules/forms/handler/HTMLRawHandler.java +++ b/src/main/java/org/olat/modules/forms/handler/HTMLRawHandler.java @@ -31,10 +31,11 @@ import org.olat.core.util.CodeHelper; import org.olat.core.util.Util; import org.olat.modules.forms.model.xml.HTMLRaw; import org.olat.modules.forms.ui.HTMLRawEditorController; -import org.olat.modules.portfolio.ui.editor.PageRunComponent; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementEditorController; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; +import org.olat.modules.portfolio.ui.editor.PageRunComponent; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.editor.SimpleAddPageElementHandler; @@ -57,7 +58,7 @@ public class HTMLRawHandler implements PageElementHandler, SimpleAddPageElementH } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints hints) { String content = ""; if(element instanceof HTMLRaw) { content = ((HTMLRaw)element).getContent(); diff --git a/src/main/java/org/olat/modules/forms/handler/RubricHandler.java b/src/main/java/org/olat/modules/forms/handler/RubricHandler.java index 588b968f1ec8edf747d971794e05ac788fd81621..ee8a5ae53ff31ff62faf524fef2180c4f2ae8697 100644 --- a/src/main/java/org/olat/modules/forms/handler/RubricHandler.java +++ b/src/main/java/org/olat/modules/forms/handler/RubricHandler.java @@ -33,6 +33,7 @@ import org.olat.modules.forms.ui.RubricEditorController; import org.olat.modules.portfolio.ui.editor.PageRunControllerElement; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.editor.SimpleAddPageElementHandler; @@ -61,7 +62,7 @@ public class RubricHandler implements PageElementHandler, SimpleAddPageElementHa } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints hints) { if(element instanceof Rubric) { Controller ctrl = new RubricController(ureq, wControl, (Rubric)element); return new PageRunControllerElement(ctrl); diff --git a/src/main/java/org/olat/modules/forms/handler/SpacerHandler.java b/src/main/java/org/olat/modules/forms/handler/SpacerHandler.java index 77afe28ce37e5b42010290ed09dbcd17c6fe9a94..09eef2b15b14f5050aae955fbe1d2a3c3dda0ecd 100644 --- a/src/main/java/org/olat/modules/forms/handler/SpacerHandler.java +++ b/src/main/java/org/olat/modules/forms/handler/SpacerHandler.java @@ -33,6 +33,7 @@ import org.olat.modules.portfolio.ui.editor.PageRunComponent; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementEditorController; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.editor.SimpleAddPageElementHandler; @@ -57,7 +58,7 @@ public class SpacerHandler implements PageElementHandler, SimpleAddPageElementHa } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints hints) { if(element instanceof Spacer) { Component cmp = new SpacerElementComponent("spacer_" + idGenerator.incrementAndGet()); return new PageRunComponent(cmp); diff --git a/src/main/java/org/olat/modules/forms/handler/TextInputHandler.java b/src/main/java/org/olat/modules/forms/handler/TextInputHandler.java index 003242b7caa5c90f138fc94311fe2b151b5cac50..87ca1e556bb25e58478712b6049260a43b456cbf 100644 --- a/src/main/java/org/olat/modules/forms/handler/TextInputHandler.java +++ b/src/main/java/org/olat/modules/forms/handler/TextInputHandler.java @@ -32,6 +32,7 @@ import org.olat.modules.portfolio.ui.editor.PageRunControllerElement; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementEditorController; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.editor.SimpleAddPageElementHandler; @@ -54,7 +55,7 @@ public class TextInputHandler implements PageElementHandler, SimpleAddPageElemen } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints hints) { if(element instanceof TextInput) { Controller ctrl = new TextInputController(ureq, wControl, (TextInput)element); return new PageRunControllerElement(ctrl); diff --git a/src/main/java/org/olat/modules/forms/handler/TitleHandler.java b/src/main/java/org/olat/modules/forms/handler/TitleHandler.java index 74549c0345494d2447b7137e0eb6ed5bdfe4769a..7fd79c5c1d1ad1507a3e1943fdfb02425e50d220 100644 --- a/src/main/java/org/olat/modules/forms/handler/TitleHandler.java +++ b/src/main/java/org/olat/modules/forms/handler/TitleHandler.java @@ -35,6 +35,7 @@ import org.olat.modules.portfolio.ui.editor.PageRunComponent; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementEditorController; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.editor.SimpleAddPageElementHandler; @@ -59,7 +60,7 @@ public class TitleHandler implements PageElementHandler, SimpleAddPageElementHan } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints hints) { String content = ""; if(element instanceof Title) { content = ((Title)element).getContent(); diff --git a/src/main/java/org/olat/modules/forms/ui/_content/rubric.html b/src/main/java/org/olat/modules/forms/ui/_content/rubric.html index 823b997299d026b5bfdf1720b380bce0ccd8e0ad..b12b1cd30faae162259deb815c45986c52760750 100644 --- a/src/main/java/org/olat/modules/forms/ui/_content/rubric.html +++ b/src/main/java/org/olat/modules/forms/ui/_content/rubric.html @@ -21,28 +21,30 @@ #end #if($element.isSliderOverview()) - #if($element.isStepLabels()) - <div class="clearfix"> - <div class="$colLeft"></div> - <div class="$colMiddle o_evaluation_step_labels"> - #foreach($stepLabel in $element.stepLabels)<div style="width:${element.getStepInPercent()}%;">$r.escapeHtml($stepLabel)</div>#end + <div class="o_evaluation_block o_evaluation_slider_overview"> + #if($element.isStepLabels()) + <div class="clearfix"> + <div class="$colLeft"></div> + <div class="$colMiddle o_evaluation_step_labels"> + #foreach($stepLabel in $element.stepLabels)<div style="width:${element.getStepInPercent()}%;">$r.escapeHtml($stepLabel)</div>#end + </div> + <div class="$colRight"></div> </div> - <div class="$colRight"></div> - </div> - #end - #foreach($slider in $element.getSliders()) - <div class="o_slider clearfix"> - <div class="$colLeft o_evaluation_left_label">$slider.startLabel</div> - <div class="$colMiddle">$r.render($slider.overviewEl)</div> - <div class="$colRight o_evaluation_right_label">$slider.endLabel</div> + #end + #foreach($slider in $element.getSliders()) + <div class="o_slider clearfix"> + <div class="$colLeft o_evaluation_left_label">$slider.startLabel</div> + <div class="$colMiddle">$r.render($slider.overviewEl)</div> + <div class="$colRight o_evaluation_right_label">$slider.endLabel</div> + </div> + #end </div> - #end #elseif($element.isRadarOverview()) - <div class="clearfix"> + <div class="o_evaluation_block o_evaluation_radar_overview clearfix"> $r.render($element.radarEl) </div> #elseif($element.isDiscreteRubric()) -<div class="o_evaluation_discrete_radio"> +<div class="o_evaluation_block o_evaluation_discrete_radio"> #if($element.isStepLabels()) <div class="clearfix"> <div class="$colLeft"></div> @@ -63,7 +65,7 @@ #end </div> #elseif($element.isDiscreteSliderRubric()) -<div class="o_evaluation_discrete_slider"> +<div class="o_evaluation_block o_evaluation_discrete_slider"> #if($element.isStepLabels()) <div class="clearfix"> <div class="$colLeft"></div> @@ -92,7 +94,7 @@ #end </div> #else -<div class="o_evaluation_slider"> +<div class="o_evaluation_block o_evaluation_slider"> #foreach($slider in $element.getSliders()) <div class="o_slider clearfix"> <div class="$colLeft o_evaluation_left_label">$slider.startLabel</div> diff --git a/src/main/java/org/olat/modules/forms/ui/_content/run.html b/src/main/java/org/olat/modules/forms/ui/_content/run.html index 20c05fd5bb95cc39acf4e42bfdbc115bfa43cf35..e3f4b7eb0a3112423a904bca9686819985c30dd2 100644 --- a/src/main/java/org/olat/modules/forms/ui/_content/run.html +++ b/src/main/java/org/olat/modules/forms/ui/_content/run.html @@ -29,28 +29,30 @@ #end #if($element.isSliderOverview()) - #if($element.isStepLabels()) - <div class="clearfix"> - <div class="$colLeft"></div> - <div class="$colMiddle o_evaluation_step_labels"> - #foreach($stepLabel in $element.stepLabels)<div style="width:${element.getStepInPercent()}%;">$r.escapeHtml($stepLabel)</div>#end + <div class="o_evaluation_block o_evaluation_slider_overview"> + #if($element.isStepLabels()) + <div class="clearfix"> + <div class="$colLeft"></div> + <div class="$colMiddle o_evaluation_step_labels"> + #foreach($stepLabel in $element.stepLabels)<div style="width:${element.getStepInPercent()}%;">$r.escapeHtml($stepLabel)</div>#end + </div> + <div class="$colRight"></div> </div> - <div class="$colRight"></div> - </div> - #end - #foreach($slider in $element.getSliders()) - <div class="o_slider clearfix"> - <div class="$colLeft o_evaluation_left_label">$slider.startLabel</div> - <div class="$colMiddle">$r.render($slider.overviewEl)</div> - <div class="$colRight o_evaluation_right_label">$slider.endLabel</div> + #end + #foreach($slider in $element.getSliders()) + <div class="o_slider clearfix"> + <div class="$colLeft o_evaluation_left_label">$slider.startLabel</div> + <div class="$colMiddle">$r.render($slider.overviewEl)</div> + <div class="$colRight o_evaluation_right_label">$slider.endLabel</div> + </div> + #end </div> - #end #elseif($element.isRadarOverview()) - <div class="clearfix"> + <div class="o_evaluation_block o_evaluation_radar_overview clearfix"> $r.render($element.radarEl) </div> #elseif($element.isDiscreteRubric()) - <div class="o_evaluation_discrete_radio"> + <div class="o_evaluation_block o_evaluation_discrete_radio"> #if($element.isStepLabels()) <div class="clearfix"> <div class="$colLeft"></div> @@ -71,7 +73,7 @@ #end </div> #elseif($element.isDiscreteSliderRubric()) - <div class="o_evaluation_discrete_slider"> + <div class="o_evaluation_block o_evaluation_discrete_slider"> #if($element.isStepLabels()) <div class="clearfix"> <div class="$colLeft"></div> @@ -100,7 +102,7 @@ #end </div> #else - <div class="o_evaluation_slider"> + <div class="o_evaluation_block o_evaluation_slider"> #foreach($slider in $element.getSliders()) <div class="o_slider clearfix"> <div class="$colLeft o_evaluation_left_label">$slider.startLabel</div> @@ -111,7 +113,7 @@ </div> #end #elseif($element.isTextInput()) - <div class="o_evaluation_textinput clearfix o_block_large"> + <div class="o_evaluation_block o_evaluation_textinput clearfix o_block_large"> #if($r.isNotNull($element.textInputWrapper.textEl)) $r.render($element.textInputWrapper.textEl) #if($r.visible($element.textInputWrapper.saveButton)) diff --git a/src/main/java/org/olat/modules/gotomeeting/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/gotomeeting/ui/_i18n/LocalStrings_pt_BR.properties index 9934c0362eafea1a919ff4706fb3beccce591a4f..81d787e787493937f9d055b0c1250994ab049687 100644 --- a/src/main/java/org/olat/modules/gotomeeting/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/gotomeeting/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Fri Jun 23 15:09:12 CEST 2017 +#Tue Sep 05 19:40:17 CEST 2017 add.my.account=Eu tenho uma conta add.organizer=Adicionar um novo organizador add.training=Adicionar novo treinamento diff --git a/src/main/java/org/olat/modules/lecture/LectureBlock.java b/src/main/java/org/olat/modules/lecture/LectureBlock.java index a4e3f58b8ce226315bbb852f25dbf80e6feb0a89..2c423ca54217aa0fd206cb3150628120f1d61718 100644 --- a/src/main/java/org/olat/modules/lecture/LectureBlock.java +++ b/src/main/java/org/olat/modules/lecture/LectureBlock.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -76,8 +77,6 @@ public interface LectureBlock extends LectureBlockRef, ModifiedInfo, CreateInfo, public void setEffectiveLecturesNumber(int effectiveLecturesNumber); - public String getLog(); - public Date getStartDate(); public void setStartDate(Date startDate); @@ -109,6 +108,8 @@ public interface LectureBlock extends LectureBlockRef, ModifiedInfo, CreateInfo, * @param rollCallStatus Cannot be null */ public void setRollCallStatus(LectureRollCallStatus rollCallStatus); + + public Date getAutoClosedDate(); public RepositoryEntry getEntry(); diff --git a/src/main/java/org/olat/modules/lecture/LectureBlockAuditLog.java b/src/main/java/org/olat/modules/lecture/LectureBlockAuditLog.java new file mode 100644 index 0000000000000000000000000000000000000000..26621e9898f2f97932d70202045e481e9a0e4d8e --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/LectureBlockAuditLog.java @@ -0,0 +1,70 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture; + +import java.util.Date; + +/** + * + * Initial date: 11 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface LectureBlockAuditLog { + + public Date getCreationDate(); + + public String getAction(); + + public String getBefore(); + + public String getAfter(); + + public String getMessage(); + + public Long getLectureBlockKey(); + + public Long getRollCallKey(); + + public Long getEntryKey(); + + public Long getIdentityKey(); + + public Long getAuthorKey(); + + public enum Action { + autoclose, + saveLectureBlock, + createLectureBlock, + updateLectureBlock, + cancelLectureBlock, + closeLectureBlock, + reopenLectureBlock, + + createRollCall, + addToRollCall, + removeFromRollCall, + updateAuthorizedAbsence, + updateRollCall, + adaptRollCall, + + } + +} diff --git a/src/main/java/org/olat/modules/lecture/LectureBlockRollCall.java b/src/main/java/org/olat/modules/lecture/LectureBlockRollCall.java index 10b5141412d5791952ce1367c6f1bac3eeae0424..54a55b487879a4ec7639a881516e918454ca0111 100644 --- a/src/main/java/org/olat/modules/lecture/LectureBlockRollCall.java +++ b/src/main/java/org/olat/modules/lecture/LectureBlockRollCall.java @@ -19,6 +19,7 @@ */ package org.olat.modules.lecture; +import java.util.Date; import java.util.List; import org.olat.core.id.CreateInfo; @@ -59,4 +60,8 @@ public interface LectureBlockRollCall extends ModifiedInfo, CreateInfo { public void setComment(String comment); + public Date getAbsenceSupervisorNotificationDate(); + + public void setAbsenceSupervisorNotificationDate(Date absenceSupervisorNotificationDate); + } diff --git a/src/main/java/org/olat/modules/lecture/LectureBlockRollCallSearchParameters.java b/src/main/java/org/olat/modules/lecture/LectureBlockRollCallSearchParameters.java new file mode 100644 index 0000000000000000000000000000000000000000..744841a6e77f91e564921aa78de81d9dd7e06a41 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/LectureBlockRollCallSearchParameters.java @@ -0,0 +1,76 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture; + +/** + * + * Initial date: 28 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LectureBlockRollCallSearchParameters { + + private Boolean closed; + private Boolean hasAbsence; + private Boolean hasSupervisorNotificationDate; + + private Long rollCallKey; + private Long lectureBlockKey; + + public Boolean getClosed() { + return closed; + } + + public void setClosed(Boolean closed) { + this.closed = closed; + } + + public Boolean getHasAbsence() { + return hasAbsence; + } + + public void setHasAbsence(Boolean hasAbsence) { + this.hasAbsence = hasAbsence; + } + + public Boolean getHasSupervisorNotificationDate() { + return hasSupervisorNotificationDate; + } + + public void setHasSupervisorNotificationDate(Boolean hasSupervisorNotificationDate) { + this.hasSupervisorNotificationDate = hasSupervisorNotificationDate; + } + + public Long getRollCallKey() { + return rollCallKey; + } + + public void setRollCallKey(Long rollCallKey) { + this.rollCallKey = rollCallKey; + } + + public Long getLectureBlockKey() { + return lectureBlockKey; + } + + public void setLectureBlockKey(Long lectureBlockKey) { + this.lectureBlockKey = lectureBlockKey; + } +} diff --git a/src/main/java/org/olat/modules/lecture/LectureBlockStatus.java b/src/main/java/org/olat/modules/lecture/LectureBlockStatus.java index 8127f020e6f18efb60a9b803283130e7c0d76b1c..c1fcd09495b79b1d4a4e3cb6b5a65f259cf412ee 100644 --- a/src/main/java/org/olat/modules/lecture/LectureBlockStatus.java +++ b/src/main/java/org/olat/modules/lecture/LectureBlockStatus.java @@ -28,7 +28,6 @@ package org.olat.modules.lecture; public enum LectureBlockStatus { active, - partiallydone, done, cancelled diff --git a/src/main/java/org/olat/modules/lecture/LectureService.java b/src/main/java/org/olat/modules/lecture/LectureService.java index 9e5aea25d3da19010015206817b60da4368de0fc..4097ff0a76ae8e9b1381e7558b94e3d8c1aaceec 100644 --- a/src/main/java/org/olat/modules/lecture/LectureService.java +++ b/src/main/java/org/olat/modules/lecture/LectureService.java @@ -54,6 +54,14 @@ public interface LectureService { */ public RepositoryEntryLectureConfiguration getRepositoryEntryLectureConfiguration(RepositoryEntry entry); + /** + * + * + * @param entry + * @return + */ + public boolean isRepositoryEntryLectureEnabled(RepositoryEntryRef entry); + /** * Update the specified configuration * @param config The configuration to merge @@ -92,9 +100,10 @@ public interface LectureService { * the status of the roll call. * * @param lectureBlock The lecture block to close + * @param author The user which trigger the action * @return The updated lecture block */ - public LectureBlock close(LectureBlock lectureBlock); + public LectureBlock close(LectureBlock lectureBlock, Identity author); /** * The method will set the status of the lecture block and @@ -105,13 +114,37 @@ public interface LectureService { */ public LectureBlock cancel(LectureBlock lectureBlock); + public String toAuditXml(LectureBlock lectureBlock); + + public LectureBlock toAuditLectureBlock(String xml); + + public String toAuditXml(LectureBlockRollCall rollCall); + + public LectureBlockRollCall toAuditLectureBlockRollCall(String xml); + + /** * Append content to the log saved on the lecture block. * * @param lectureBlock The lecture block * @param log The content to append */ - public void appendToLectureBlockLog(LectureBlockRef lectureBlock, Identity user, Identity assessedIdentity, String log); + public void auditLog(LectureBlockAuditLog.Action action, String before, String after, String message, + LectureBlockRef lectureBlock, LectureBlockRollCall rollCall, + RepositoryEntryRef entry, IdentityRef assessedIdentity, IdentityRef author); + + public List<LectureBlockAuditLog> getAuditLog(LectureBlockRef lectureBlock); + + /** + * The audit log of a specific user. + * + * @param assessedIdentity + * @return A list of roll call changes. + */ + public List<LectureBlockAuditLog> getAuditLog(IdentityRef assessedIdentity); + + + public List<LectureBlockAuditLog> getAuditLog(RepositoryEntryRef entry); /** * Reload the lecture block. @@ -235,6 +268,10 @@ public interface LectureService { public List<LectureBlockRollCall> getRollCalls(LectureBlockRef block); + + public List<LectureBlockRollCall> getRollCalls(LectureBlockRollCallSearchParameters searchParams); + + /** * Create a roll call with some settings. * @@ -263,6 +300,13 @@ public interface LectureService { */ public void adaptRollCalls(LectureBlock lectureBlock); + /** + * Adapt all roll call on the database. Use with cautions! + * + * @param author The user which trigger the action + */ + public void adaptAll(Identity author); + /** * Add the specified lectures to the ones the identity follows. * @@ -288,7 +332,8 @@ public interface LectureService { String comment, List<Integer> absences); /** - * Remove the specified lectures to the ones the identity follows. + * Remove the specified lectures to the ones the identity follows. If the number of absences is zero, + * the authorized absence flag is set ot NULL. * * @param identity The participant of the lecture * @param lectureBlock The lecture block @@ -316,6 +361,14 @@ public interface LectureService { */ public List<LectureBlock> getLectureBlocks(RepositoryEntryRef entry); + /** + * Search lecture blocks. + * + * @param searchParams The search parameters + * @return A list of lecture blocks + */ + public List<LectureBlock> getLectureBlocks(LecturesBlockSearchParameters searchParams); + /** * Return the list of lecture blocks of a course with the teachers. * diff --git a/src/main/java/org/olat/modules/lecture/_spring/lectureContext.xml b/src/main/java/org/olat/modules/lecture/_spring/lectureContext.xml index 0bda9385b784aaf867f3f28f6bc4441cc0b43e7c..7b76f6e05bc6f0fba06e7df9365ffdc55ae65a85 100644 --- a/src/main/java/org/olat/modules/lecture/_spring/lectureContext.xml +++ b/src/main/java/org/olat/modules/lecture/_spring/lectureContext.xml @@ -77,7 +77,7 @@ </bean> <!-- Lectures reminder job --> - <bean id="reminderLecturesTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="reminderLecturesTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="reminderLecturesJob.${cluster.singleton.services}" /> <!-- adjust cron style syntax for your notification needs "0 10 0 * *" e.g. 10 minutes after midnight @@ -99,17 +99,17 @@ <property name="startDelay" value="60000" /> </bean> - <bean id="reminderLecturesJob.enabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="reminderLecturesJob.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.modules.lecture.manager.ReminderLecturesJob" /> </bean> <!-- dummy bean --> - <bean id="reminderLecturesJob.disabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="reminderLecturesJob.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" /> </bean> <!-- Lectures auto close job --> - <bean id="autoCloseLecturesTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="autoCloseLecturesTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="autoCloseLecturesJob.${cluster.singleton.services}" /> <!-- adjust cron style syntax for your notification needs "0 10 0 * *" e.g. 10 minutes after midnight @@ -131,12 +131,12 @@ <property name="startDelay" value="60000" /> </bean> - <bean id="autoCloseLecturesJob.enabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="autoCloseLecturesJob.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.modules.lecture.manager.AutoCloseLecturesJob" /> </bean> <!-- dummy bean --> - <bean id="autoCloseLecturesJob.disabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="autoCloseLecturesJob.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" /> </bean> diff --git a/src/main/java/org/olat/modules/lecture/manager/LectureBlockAuditLogDAO.java b/src/main/java/org/olat/modules/lecture/manager/LectureBlockAuditLogDAO.java new file mode 100644 index 0000000000000000000000000000000000000000..8b18b6a1297e5bee9affae47b2c6cf1245f76e49 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/manager/LectureBlockAuditLogDAO.java @@ -0,0 +1,177 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.manager; + +import java.util.Date; +import java.util.List; + +import org.olat.basesecurity.IdentityRef; +import org.olat.core.commons.persistence.DB; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.xml.XStreamHelper; +import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; +import org.olat.modules.lecture.LectureBlockRef; +import org.olat.modules.lecture.LectureBlockRollCall; +import org.olat.modules.lecture.model.LectureBlockAuditLogImpl; +import org.olat.modules.lecture.model.LectureBlockImpl; +import org.olat.modules.lecture.model.LectureBlockRollCallImpl; +import org.olat.modules.lecture.model.ReasonImpl; +import org.olat.repository.RepositoryEntryRef; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.thoughtworks.xstream.XStream; + +/** + * + * Initial date: 11 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class LectureBlockAuditLogDAO { + + private static final OLog log = Tracing.createLoggerFor(LectureBlockAuditLogDAO.class); + + @Autowired + private DB dbInstance; + + private static final XStream lectureBlockXStream = XStreamHelper.createXStreamInstanceForDBObjects(); + static { + lectureBlockXStream.ignoreUnknownElements(); + + lectureBlockXStream.alias("lectureBlock", LectureBlockImpl.class); + lectureBlockXStream.omitField(LectureBlockImpl.class, "entry"); + lectureBlockXStream.omitField(LectureBlockImpl.class, "teacherGroup"); + lectureBlockXStream.omitField(LectureBlockImpl.class, "groups"); + lectureBlockXStream.omitField(LectureBlockImpl.class, "lastModified"); + + lectureBlockXStream.alias("reason", ReasonImpl.class); + lectureBlockXStream.omitField(ReasonImpl.class, "lastModified"); + lectureBlockXStream.omitField(ReasonImpl.class, "creationDate"); + lectureBlockXStream.omitField(ReasonImpl.class, "description"); + } + + private static final XStream rollCallXStream = XStreamHelper.createXStreamInstanceForDBObjects(); + static { + rollCallXStream.alias("rollcall", LectureBlockRollCallImpl.class); + rollCallXStream.ignoreUnknownElements(); + rollCallXStream.omitField(LectureBlockRollCallImpl.class, "identity"); + rollCallXStream.omitField(LectureBlockRollCallImpl.class, "lectureBlock"); + rollCallXStream.omitField(LectureBlockRollCallImpl.class, "lastModified"); + } + + public void auditLog(LectureBlockAuditLog.Action action, String before, String after, String message, + LectureBlockRef lectureBlock, LectureBlockRollCall rollCall, + RepositoryEntryRef entry, IdentityRef assessedIdentity, IdentityRef author) { + LectureBlockAuditLogImpl auditLog = new LectureBlockAuditLogImpl(); + auditLog.setCreationDate(new Date()); + auditLog.setAction(action.name()); + auditLog.setBefore(before); + auditLog.setAfter(after); + auditLog.setMessage(message); + if(lectureBlock != null) { + auditLog.setLectureBlockKey(lectureBlock.getKey()); + } + if(rollCall != null) { + auditLog.setRollCallKey(rollCall.getKey()); + } + if(entry != null) { + auditLog.setEntryKey(entry.getKey()); + } + if(assessedIdentity != null) { + auditLog.setIdentityKey(assessedIdentity.getKey()); + } + if(author != null) { + auditLog.setAuthorKey(author.getKey()); + } + dbInstance.getCurrentEntityManager().persist(auditLog); + } + + public List<LectureBlockAuditLog> getAuditLog(LectureBlockRef lectureBlock) { + StringBuilder sb = new StringBuilder(); + sb.append("select log from lectureblockauditlog log where log.lectureBlockKey=:lectureBlockKey"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), LectureBlockAuditLog.class) + .setParameter("lectureBlockKey", lectureBlock.getKey()) + .getResultList(); + } + + public List<LectureBlockAuditLog> getAuditLog(IdentityRef identity) { + StringBuilder sb = new StringBuilder(); + sb.append("select log from lectureblockauditlog log where log.identityKey=:identityKey"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), LectureBlockAuditLog.class) + .setParameter("identityKey", identity.getKey()) + .getResultList(); + } + + public List<LectureBlockAuditLog> getAuditLog(RepositoryEntryRef entry) { + StringBuilder sb = new StringBuilder(); + sb.append("select log from lectureblockauditlog log where log.entryKey=:repoEntryKey"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), LectureBlockAuditLog.class) + .setParameter("repoEntryKey", entry.getKey()) + .getResultList(); + } + + public String toXml(LectureBlock lectureBlock) { + if(lectureBlock == null) return null; + return lectureBlockXStream.toXML(lectureBlock); + } + + public LectureBlock lectureBlockFromXml(String xml) { + if(StringHelper.containsNonWhitespace(xml)) { + try { + Object obj = lectureBlockXStream.fromXML(xml); + if(obj instanceof LectureBlock) { + return (LectureBlock)obj; + } + } catch (Exception e) { + log.error("", e); + return null; + } + } + return null; + } + + public String toXml(LectureBlockRollCall rollCall) { + if(rollCall == null) return null; + return rollCallXStream.toXML(rollCall); + } + + public LectureBlockRollCall rollCallFromXml(String xml) { + if(StringHelper.containsNonWhitespace(xml)) { + try { + Object obj = rollCallXStream.fromXML(xml); + if(obj instanceof LectureBlockRollCall) { + return (LectureBlockRollCall)obj; + } + } catch (Exception e) { + log.error("", e); + return null; + } + } + return null; + } +} diff --git a/src/main/java/org/olat/modules/lecture/manager/LectureBlockDAO.java b/src/main/java/org/olat/modules/lecture/manager/LectureBlockDAO.java index e628d8fcd345bbc32f5be0cc65a56a772d0f780b..70ed0f8bfccbcb759b2cb12336cb7360ddbcc05e 100644 --- a/src/main/java/org/olat/modules/lecture/manager/LectureBlockDAO.java +++ b/src/main/java/org/olat/modules/lecture/manager/LectureBlockDAO.java @@ -85,16 +85,6 @@ public class LectureBlockDAO { return block; } - public boolean appendLog(LectureBlockRef block, String log) { - String update = "update lectureblocklog blocklog set blocklog.log=case when blocklog.log is null then :newLog else concat(blocklog.log,'\n',:newLog) end where blocklog.key=:blockKey"; - int rows = dbInstance.getCurrentEntityManager() - .createQuery(update) - .setParameter("blockKey", block.getKey()) - .setParameter("newLog", log) - .executeUpdate(); - return rows > 0; - } - public LectureBlock loadByKey(Long key) { StringBuilder sb = new StringBuilder(); sb.append("select block from lectureblock block") @@ -146,6 +136,15 @@ public class LectureBlockDAO { return rows; } + public List<LectureBlock> getLectureBlocks() { + StringBuilder sb = new StringBuilder(); + sb.append("select block from lectureblock block") + .append(" inner join fetch block.entry entry"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), LectureBlock.class) + .getResultList(); + } + public List<LectureBlock> getLectureBlocks(RepositoryEntryRef entry) { return dbInstance.getCurrentEntityManager() .createNamedQuery("lectureBlocksByRepositoryEntry", LectureBlock.class) @@ -153,6 +152,21 @@ public class LectureBlockDAO { .getResultList(); } + public List<LectureBlock> searchLectureBlocks(LecturesBlockSearchParameters searchParams) { + StringBuilder sb = new StringBuilder(); + sb.append("select block from lectureblock block") + .append(" inner join block.teacherGroup tGroup") + .append(" inner join tGroup.members membership") + .append(" inner join fetch block.entry entry"); + boolean where = false; + where = addSearchParametersToQuery(sb, where, searchParams); + + TypedQuery<LectureBlock> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), LectureBlock.class); + addSearchParametersToQuery(query, searchParams); + return query.getResultList(); + } + public List<LectureBlock> loadByTeacher(IdentityRef identityRef, LecturesBlockSearchParameters searchParams) { StringBuilder sb = new StringBuilder(); sb.append("select block from lectureblock block") @@ -160,7 +174,7 @@ public class LectureBlockDAO { .append(" inner join tGroup.members membership") .append(" inner join fetch block.entry entry") .append(" where membership.identity.key=:teacherKey"); - addSearchParametersToQuery(sb, searchParams); + addSearchParametersToQuery(sb, true, searchParams); TypedQuery<LectureBlock> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), LectureBlock.class) @@ -225,7 +239,7 @@ public class LectureBlockDAO { .append(" inner join membership.identity coach") .append(" inner join fetch coach.user usercoach") .append(" where membership.role='").append("teacher").append("' and block.entry.key=:repoEntryKey"); - addSearchParametersToQuery(sc, searchParams); + addSearchParametersToQuery(sc, true, searchParams); if(teacher != null) { sc.append(" and exists (select teachership.key from bgroupmember teachership where") .append(" teachership.group.key=tGroup.key and teachership.identity.key=:teacherKey") @@ -257,11 +271,12 @@ public class LectureBlockDAO { return new ArrayList<>(blockMap.values()); } - private void addSearchParametersToQuery(StringBuilder sb, LecturesBlockSearchParameters searchParams) { - if(searchParams == null) return; + private boolean addSearchParametersToQuery(StringBuilder sb, boolean where, LecturesBlockSearchParameters searchParams) { + if(searchParams == null) return where; if(StringHelper.containsNonWhitespace(searchParams.getSearchString())) { - sb.append(" and (entry.externalRef=:searchString or "); + where = PersistenceHelper.appendAnd(sb, where); + sb.append(" (entry.externalRef=:searchString or "); PersistenceHelper.appendFuzzyLike(sb, "entry.displayname", "fuzzySearchString", dbInstance.getDbVendor()); sb.append(" or "); PersistenceHelper.appendFuzzyLike(sb, "block.title", "fuzzySearchString", dbInstance.getDbVendor()); @@ -269,11 +284,14 @@ public class LectureBlockDAO { } if(searchParams.getStartDate() != null) { - sb.append(" and block.startDate>=:startDate"); + where = PersistenceHelper.appendAnd(sb, where); + sb.append(" block.startDate>=:startDate"); } if(searchParams.getEndDate() != null) { - sb.append(" and block.endDate<=:endDate"); + where = PersistenceHelper.appendAnd(sb, where); + sb.append(" block.endDate<=:endDate"); } + return where; } private void addSearchParametersToQuery(TypedQuery<?> query, LecturesBlockSearchParameters searchParams) { diff --git a/src/main/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAO.java b/src/main/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAO.java index 8ac2041b13bf4ddf0eba8cc87acf498de7a2d36d..4680e95f3fa54dd260e2f74b0b04ec9dd85dbeba 100644 --- a/src/main/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAO.java +++ b/src/main/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAO.java @@ -19,7 +19,6 @@ */ package org.olat.modules.lecture.manager; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -36,8 +35,10 @@ import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.id.Identity; import org.olat.core.util.StringHelper; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureBlockRef; import org.olat.modules.lecture.LectureBlockRollCall; +import org.olat.modules.lecture.LectureBlockRollCallSearchParameters; import org.olat.modules.lecture.LectureBlockStatus; import org.olat.modules.lecture.LectureRollCallStatus; import org.olat.modules.lecture.RepositoryEntryLectureConfiguration; @@ -62,13 +63,13 @@ import org.springframework.stereotype.Service; */ @Service public class LectureBlockRollCallDAO { - - private static final SimpleDateFormat sdb = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - + @Autowired private DB dbInstance; @Autowired private UserManager userManager; + @Autowired + private LectureBlockAuditLogDAO auditLogDao; public LectureBlockRollCall createAndPersistRollCall(LectureBlock lectureBlock, Identity identity, Boolean authorizedAbsence, String absenceReason, String comment, List<Integer> absences) { @@ -93,9 +94,7 @@ public class LectureBlockRollCallDAO { private void addInternalLecture(LectureBlock lectureBlock, LectureBlockRollCall rollCall, List<Integer> absences) { if(absences != null) { LectureBlockRollCallImpl call = (LectureBlockRollCallImpl)rollCall; - String currentAbsent = call.getLecturesAbsent(); - String currentAttended = call.getLecturesAttended(); - + List<Integer> currentAbsentList = call.getLecturesAbsentList(); for(int i=absences.size(); i-->0; ) { Integer absence = absences.get(i); @@ -105,23 +104,23 @@ public class LectureBlockRollCallDAO { } call.setLecturesAbsentList(currentAbsentList); call.setLecturesAbsentNumber(currentAbsentList.size()); - - int plannedLecture = lectureBlock.getPlannedLecturesNumber(); + + int numOfLectures = lectureBlock.getEffectiveLecturesNumber(); + if(numOfLectures <= 0 && lectureBlock.getStatus() != LectureBlockStatus.cancelled) { + numOfLectures = lectureBlock.getPlannedLecturesNumber(); + } List<Integer> attendedList = new ArrayList<>(); - for(int i=0; i<plannedLecture; i++) { + for(int i=0; i<numOfLectures; i++) { if(!currentAbsentList.contains(i)) { attendedList.add(i); } } call.setLecturesAttendedList(attendedList); - call.setLecturesAttendedNumber(plannedLecture - currentAbsentList.size()); - updateLog(call, currentAbsent, currentAttended); + call.setLecturesAttendedNumber(numOfLectures - currentAbsentList.size()); } } - - public LectureBlockRollCall removeLecture(LectureBlock lectureBlock, LectureBlockRollCall rollCall, List<Integer> absences) { removeInternalLecture(lectureBlock, rollCall, absences); return dbInstance.getCurrentEntityManager().merge(rollCall); @@ -130,8 +129,6 @@ public class LectureBlockRollCallDAO { private void removeInternalLecture(LectureBlock lectureBlock, LectureBlockRollCall rollCall, List<Integer> absences) { if(absences != null) { LectureBlockRollCallImpl call = (LectureBlockRollCallImpl)rollCall; - String currentAbsent = call.getLecturesAbsent(); - String currentAttended = call.getLecturesAttended(); List<Integer> currentAbsentList = call.getLecturesAbsentList(); for(int i=absences.size(); i-->0; ) { @@ -139,27 +136,36 @@ public class LectureBlockRollCallDAO { } call.setLecturesAbsentList(currentAbsentList); call.setLecturesAbsentNumber(currentAbsentList.size()); - - int plannedLecture = lectureBlock.getPlannedLecturesNumber(); - + + int numOfLectures = lectureBlock.getEffectiveLecturesNumber(); + if(numOfLectures <= 0 && lectureBlock.getStatus() != LectureBlockStatus.cancelled) { + numOfLectures = lectureBlock.getPlannedLecturesNumber(); + } + List<Integer> attendedList = new ArrayList<>(); - for(int i=0; i<plannedLecture; i++) { + for(int i=0; i<numOfLectures; i++) { if(!currentAbsentList.contains(i)) { attendedList.add(i); } } call.setLecturesAttendedList(attendedList); - call.setLecturesAttendedNumber(plannedLecture - currentAbsentList.size()); - updateLog(call, currentAbsent, currentAttended); + call.setLecturesAttendedNumber(numOfLectures - currentAbsentList.size()); + + if(currentAbsentList.size() == 0) { + call.setAbsenceAuthorized(null); + } } } - public LectureBlockRollCall adaptLecture(LectureBlockRollCall rollCall, int numberOfLectures) { + public LectureBlockRollCall adaptLecture(LectureBlock lectureBlock, + LectureBlockRollCall rollCall, int numberOfLectures, Identity author) { LectureBlockRollCallImpl call = (LectureBlockRollCallImpl)rollCall; List<Integer> currentAbsentList = call.getLecturesAbsentList(); List<Integer> currentAttendedList = call.getLecturesAttendedList(); if((currentAbsentList != null && currentAbsentList.size() > 0) || (currentAttendedList != null && currentAttendedList.size() > 0)) { + String before = auditLogDao.toXml(rollCall); + int currentLectures = currentAbsentList.size() + currentAttendedList.size(); if(currentLectures > numberOfLectures) { // need to reduce @@ -193,23 +199,16 @@ public class LectureBlockRollCallDAO { call.setLecturesAttendedNumber(attendedList.size()); call = (LectureBlockRollCallImpl)update(call); } + + String after = auditLogDao.toXml(rollCall); + if(before == null || !before.equals(after)) { + auditLogDao.auditLog(LectureBlockAuditLog.Action.adaptRollCall, before, after, + null, lectureBlock, rollCall, lectureBlock.getEntry(), rollCall.getIdentity(), author); + } } return call; } - private void updateLog(LectureBlockRollCallImpl call, String currentAbsent, String currentAttended) { - String log = call.getLog() == null ? "" : call.getLog(); - - Date now = new Date(); - String date; - synchronized(sdb) { - date = sdb.format(now); - } - log += date + " Absent: " + currentAbsent + "->" + call.getLecturesAbsent() + ";"; - log += "Attended: " + currentAttended + "->" + call.getLecturesAttended() + " \n"; - call.setLog(log); - } - public LectureBlockRollCall loadByKey(Long key) { StringBuilder sb = new StringBuilder(); sb.append("select rollcall from lectureblockrollcall rollcall") @@ -262,6 +261,67 @@ public class LectureBlockRollCallDAO { return rollCalls != null && rollCalls.size() > 0 ? rollCalls.get(0) : null; } + public List<LectureBlockRollCall> getRollCalls(LectureBlockRollCallSearchParameters searchParams) { + StringBuilder sb = new StringBuilder(); + sb.append("select rollcall from lectureblockrollcall rollcall") + .append(" inner join fetch rollcall.identity ident") + .append(" inner join fetch ident.user user") + .append(" inner join fetch rollcall.lectureBlock block"); + + boolean where = false; + if(searchParams.getHasAbsence() != null) { + where = PersistenceHelper.appendAnd(sb, where); + if(searchParams.getHasAbsence().booleanValue()) { + sb.append("rollcall.lecturesAbsentNumber>0"); + } else { + sb.append("(rollcall.lecturesAbsentNumber = 0 or rollcall.lecturesAbsentNumber is null)"); + } + } + + if(searchParams.getHasSupervisorNotificationDate() != null) { + where = PersistenceHelper.appendAnd(sb, where); + if(searchParams.getHasSupervisorNotificationDate().booleanValue()) { + sb.append("rollcall.absenceSupervisorNotificationDate is not null"); + } else { + sb.append("rollcall.absenceSupervisorNotificationDate is null"); + } + } + + if(searchParams.getClosed() != null) { + where = PersistenceHelper.appendAnd(sb, where); + if(searchParams.getClosed().booleanValue()) { + sb.append("(block.statusString='").append(LectureBlockStatus.done.name()).append("'") + .append(" or block.rollCallStatusString='").append(LectureRollCallStatus.closed.name()).append("'") + .append(" or block.rollCallStatusString='").append(LectureRollCallStatus.autoclosed.name()).append("')"); + } else { + sb.append("(block.statusString!='").append(LectureBlockStatus.done.name()).append("'") + .append(" and block.rollCallStatusString!='").append(LectureRollCallStatus.closed.name()).append("'") + .append(" and block.rollCallStatusString!='").append(LectureRollCallStatus.autoclosed.name()).append("')"); + } + } + + if(searchParams.getRollCallKey() != null) { + where = PersistenceHelper.appendAnd(sb, where); + sb.append("rollcall.key=:rollCallKey"); + } + + if(searchParams.getLectureBlockKey() != null) { + where = PersistenceHelper.appendAnd(sb, where); + sb.append("rollcall.lectureBlock.key=:lectureBlockKey"); + } + + TypedQuery<LectureBlockRollCall> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), LectureBlockRollCall.class); + if(searchParams.getRollCallKey() != null) { + query.setParameter("rollCallKey", searchParams.getRollCallKey()); + } + if(searchParams.getLectureBlockKey() != null) { + query.setParameter("lectureBlockKey", searchParams.getLectureBlockKey()); + } + + return query.getResultList(); + } + public List<LectureBlockAndRollCall> getParticipantLectureBlockAndRollCalls(RepositoryEntryRef entry, IdentityRef identity) { StringBuilder sb = new StringBuilder(); sb.append("select block, call, re.displayname") @@ -491,7 +551,7 @@ public class LectureBlockRollCallDAO { } Map<String,Object> queryParams = new HashMap<>(); - appendUsersStatisticsSearchParams(params, queryParams, sb); + appendUsersStatisticsSearchParams(params, queryParams, userPropertyHandlers, sb); TypedQuery<Object[]> rawQuery = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Object[].class); @@ -585,7 +645,8 @@ public class LectureBlockRollCallDAO { return statisticsList; } - private void appendUsersStatisticsSearchParams(LectureStatisticsSearchParameters params, Map<String,Object> queryParams, StringBuilder sb) { + private void appendUsersStatisticsSearchParams(LectureStatisticsSearchParameters params, Map<String,Object> queryParams, + List<UserPropertyHandler> userPropertyHandlers, StringBuilder sb) { if(StringHelper.containsNonWhitespace(params.getLogin())) { String login = PersistenceHelper.makeFuzzyQueryString(params.getLogin()); if (login.contains("_") && dbInstance.isOracle()) { @@ -609,6 +670,14 @@ public class LectureBlockRollCallDAO { String qName = "p_" + ++count; UserPropertyHandler handler = userManager.getUserPropertiesConfig().getPropertyHandler(propName); + if(handler == null) {// fallback if the haandler is disabled + for(UserPropertyHandler userPropertyHandler:userPropertyHandlers) { + if(propName.equals(userPropertyHandler.getName())) { + handler = userPropertyHandler; + } + } + } + if(dbInstance.isMySQL()) { sb.append(" and user.").append(handler.getName()).append(" like :").append(qName); } else { diff --git a/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java b/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java index 8eb40a1e56f1c62a756c330e94a149c4e19a4043..070bb392dc55ebcef66ac40b61417b48e5b9922f 100644 --- a/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java +++ b/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java @@ -21,7 +21,6 @@ package org.olat.modules.lecture.manager; import java.io.File; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -60,8 +59,10 @@ import org.olat.core.util.mail.MailManager; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureBlockRef; import org.olat.modules.lecture.LectureBlockRollCall; +import org.olat.modules.lecture.LectureBlockRollCallSearchParameters; import org.olat.modules.lecture.LectureBlockStatus; import org.olat.modules.lecture.LectureBlockToGroup; import org.olat.modules.lecture.LectureModule; @@ -100,7 +101,6 @@ import org.springframework.stereotype.Service; @Service public class LectureServiceImpl implements LectureService, UserDataDeletable { private static final OLog log = Tracing.createLoggerFor(LectureServiceImpl.class); - private static final SimpleDateFormat sdb = new SimpleDateFormat("yyyy-MM-dd HH:mm"); private static final CalendarManagedFlag[] CAL_MANAGED_FLAGS = new CalendarManagedFlag[] { CalendarManagedFlag.all }; @Autowired @@ -122,6 +122,8 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { @Autowired private LectureBlockDAO lectureBlockDao; @Autowired + private LectureBlockAuditLogDAO auditLogDao; + @Autowired private RepositoryEntryDAO repositoryEntryDao; @Autowired private LectureBlockToGroupDAO lectureBlockToGroupDao; @@ -149,6 +151,14 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { return config; } + @Override + public boolean isRepositoryEntryLectureEnabled(RepositoryEntryRef entry) { + if(!lectureModule.isEnabled()) { + return false; + } + return lectureConfigurationDao.isConfigurationEnabledFor(entry); + } + @Override public RepositoryEntryLectureConfiguration copyRepositoryEntryLectureConfiguration(RepositoryEntry sourceEntry, RepositoryEntry targetEntry) { RepositoryEntryLectureConfiguration config = lectureConfigurationDao.getConfiguration(sourceEntry); @@ -201,17 +211,19 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { } @Override - public LectureBlock close(LectureBlock lectureBlock) { + public LectureBlock close(LectureBlock lectureBlock, Identity author) { lectureBlock.setStatus(LectureBlockStatus.done); lectureBlock.setRollCallStatus(LectureRollCallStatus.closed); LectureBlockImpl block = (LectureBlockImpl)lectureBlockDao.update(lectureBlock); + + int numOfLectures = block.getEffectiveLecturesNumber(); + if(numOfLectures <= 0 && block.getStatus() != LectureBlockStatus.cancelled) { + numOfLectures = block.getPlannedLecturesNumber(); + } + List<LectureBlockRollCall> rollCallList = lectureBlockRollCallDao.getRollCalls(lectureBlock); for(LectureBlockRollCall rollCall:rollCallList) { - int numOfLectures = lectureBlock.getEffectiveLecturesNumber(); - if(numOfLectures <= 0 && lectureBlock.getStatus() != LectureBlockStatus.cancelled) { - numOfLectures = lectureBlock.getPlannedLecturesNumber(); - } - lectureBlockRollCallDao.adaptLecture(rollCall, numOfLectures); + lectureBlockRollCallDao.adaptLecture(block, rollCall, numOfLectures, author); } dbInstance.commit(); recalculateSummary(block.getEntry()); @@ -230,24 +242,45 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { } @Override - public void appendToLectureBlockLog(LectureBlockRef lectureBlock, Identity user, Identity assessedIdentity, String audit) { - Date now = new Date(); - String date; - synchronized(sdb) { - date = sdb.format(now); - } - - StringBuilder sb = new StringBuilder(256); - sb.append("Date: ").append(date).append(" \n"); - if(user != null) { - sb.append("User: ").append(userManager.getUserDisplayName(user)).append(" (").append(user.getKey()).append(") \n"); - } - if(assessedIdentity != null) { - sb.append("Assessed user: ").append(userManager.getUserDisplayName(assessedIdentity)).append(" (").append(user.getKey()).append(") \n"); - } - sb.append(audit); - log.audit(sb.toString()); - lectureBlockDao.appendLog(lectureBlock, sb.toString()); + public String toAuditXml(LectureBlock lectureBlock) { + return auditLogDao.toXml(lectureBlock); + } + + @Override + public String toAuditXml(LectureBlockRollCall rollCall) { + return auditLogDao.toXml(rollCall); + } + + @Override + public LectureBlock toAuditLectureBlock(String xml) { + return auditLogDao.lectureBlockFromXml(xml); + } + + @Override + public LectureBlockRollCall toAuditLectureBlockRollCall(String xml) { + return auditLogDao.rollCallFromXml(xml); + } + + @Override + public void auditLog(LectureBlockAuditLog.Action action, String before, String after, String message, + LectureBlockRef lectureBlock, LectureBlockRollCall rollCall, + RepositoryEntryRef entry, IdentityRef assessedIdentity, IdentityRef author) { + auditLogDao.auditLog(action, before, after, message, lectureBlock, rollCall, entry, assessedIdentity, author); + } + + @Override + public List<LectureBlockAuditLog> getAuditLog(LectureBlockRef lectureBlock) { + return auditLogDao.getAuditLog(lectureBlock); + } + + @Override + public List<LectureBlockAuditLog> getAuditLog(IdentityRef assessedIdentity) { + return auditLogDao.getAuditLog(assessedIdentity); + } + + @Override + public List<LectureBlockAuditLog> getAuditLog(RepositoryEntryRef entry) { + return auditLogDao.getAuditLog(entry); } @Override @@ -398,6 +431,11 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { return lectureBlockRollCallDao.getRollCalls(block); } + @Override + public List<LectureBlockRollCall> getRollCalls(LectureBlockRollCallSearchParameters searchParams) { + return lectureBlockRollCallDao.getRollCalls(searchParams); + } + @Override public LectureBlockRollCall getOrCreateRollCall(Identity identity, LectureBlock lectureBlock, Boolean authorizedAbsence, String reasonAbsence) { @@ -423,9 +461,18 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { if(rollCall == null) {//reload in case of concurrent usage rollCall = lectureBlockRollCallDao.getRollCall(lectureBlock, identity); } + + boolean checkAuthorized = lectureModule.isAuthorizedAbsenceEnabled() && lectureModule.isAbsenceDefaultAuthorized(); if(rollCall == null) { - rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, identity, null, null, null, absences); + Boolean authorized = null; + if(checkAuthorized && absences != null && absences.size() > 0) { + authorized = Boolean.TRUE; + } + rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, identity, authorized, null, null, absences); } else { + if(checkAuthorized && absences != null && absences.size() > 0 && rollCall.getAbsenceAuthorized() == null) { + rollCall.setAbsenceAuthorized(Boolean.TRUE); + } rollCall = lectureBlockRollCallDao.addLecture(lectureBlock, rollCall, absences); } return rollCall; @@ -436,12 +483,20 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { if(rollCall == null) {//reload in case of concurrent usage rollCall = lectureBlockRollCallDao.getRollCall(lectureBlock, identity); } + boolean checkAuthorized = lectureModule.isAuthorizedAbsenceEnabled() && lectureModule.isAbsenceDefaultAuthorized(); if(rollCall == null) { - rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, identity, null, null, comment, absences); + Boolean authorized = null; + if(checkAuthorized && absences != null && absences.size() > 0) { + authorized = Boolean.TRUE; + } + rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, identity, authorized, null, comment, absences); } else { if(comment != null) { rollCall.setComment(comment); } + if(checkAuthorized && absences != null && absences.size() > 0 && rollCall.getAbsenceAuthorized() == null) { + rollCall.setAbsenceAuthorized(Boolean.TRUE); + } rollCall = lectureBlockRollCallDao.addLecture(lectureBlock, rollCall, absences); } return rollCall; @@ -475,7 +530,23 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { if(numOfLectures <= 0 && lectureBlock.getStatus() != LectureBlockStatus.cancelled) { numOfLectures = lectureBlock.getPlannedLecturesNumber(); } - lectureBlockRollCallDao.adaptLecture(rollCall, lectureBlock.getPlannedLecturesNumber()); + lectureBlockRollCallDao.adaptLecture(lectureBlock, rollCall, numOfLectures, null); + } + } + + @Override + public void adaptAll(Identity author) { + List<LectureBlock> lectureBlocks = lectureBlockDao.getLectureBlocks(); + for(LectureBlock lectureBlock:lectureBlocks) { + List<LectureBlockRollCall> rollCallList = lectureBlockRollCallDao.getRollCalls(lectureBlock); + for(LectureBlockRollCall rollCall:rollCallList) { + int numOfLectures = lectureBlock.getEffectiveLecturesNumber(); + if(numOfLectures <= 0 && lectureBlock.getStatus() != LectureBlockStatus.cancelled) { + numOfLectures = lectureBlock.getPlannedLecturesNumber(); + } + lectureBlockRollCallDao.adaptLecture(lectureBlock, rollCall, numOfLectures, author); + } + dbInstance.commitAndCloseSession(); } } @@ -525,6 +596,7 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { } private void autoClose(LectureBlockImpl lectureBlock) { + String blockBefore = auditLogDao.toXml(lectureBlock); lectureBlock.setStatus(LectureBlockStatus.done); lectureBlock.setRollCallStatus(LectureRollCallStatus.autoclosed); if(lectureBlock.getEffectiveLecturesNumber() <= 0 && lectureBlock.getStatus() != LectureBlockStatus.cancelled) { @@ -544,15 +616,22 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { } if(participantAndSummary.getSummary() != null) { LectureBlockRollCall rollCall = rollCallMap.get(participantAndSummary.getIdentity()); + + String before = auditLogDao.toXml(rollCall); if(rollCall == null) { - lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, participantAndSummary.getIdentity(), null, null, null, new ArrayList<>()); + rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, participantAndSummary.getIdentity(), null, null, null, new ArrayList<>()); } else if(rollCall.getLecturesAbsentList().isEmpty() && rollCall.getLecturesAttendedList().isEmpty()) { - lectureBlockRollCallDao.addLecture(lectureBlock, rollCall, new ArrayList<>()); + rollCall = lectureBlockRollCallDao.addLecture(lectureBlock, rollCall, new ArrayList<>()); } + + String after = auditLogDao.toXml(rollCall); + auditLogDao.auditLog(LectureBlockAuditLog.Action.autoclose, before, after, null, + lectureBlock, rollCall, lectureBlock.getEntry(), participantAndSummary.getIdentity(), null); } } - - appendToLectureBlockLog(lectureBlock, null, null, "Auto-closed"); + + String blockAfter = auditLogDao.toXml(lectureBlock); + auditLogDao.auditLog(LectureBlockAuditLog.Action.autoclose, blockBefore, blockAfter, null, lectureBlock, null, lectureBlock.getEntry(), null, null); dbInstance.commit(); recalculateSummary(lectureBlock.getEntry()); @@ -618,6 +697,11 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { return lectureBlockDao.getLectureBlocks(entry); } + @Override + public List<LectureBlock> getLectureBlocks(LecturesBlockSearchParameters searchParams) { + return lectureBlockDao.searchLectureBlocks(searchParams); + } + @Override public List<LectureBlock> getLectureBlocks(IdentityRef teacher, LecturesBlockSearchParameters searchParams) { return lectureBlockDao.loadByTeacher(teacher, searchParams); @@ -939,7 +1023,7 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { KalendarEvent event = new KalendarEvent(eventId, null, title, lectureBlock.getStartDate(), lectureBlock.getEndDate()); event.setExternalId(generateExternalId(lectureBlock, entry)); event.setLocation(lectureBlock.getLocation()); - event.setDescription(lectureBlock.getDescription()); + updateEventDescription(lectureBlock, event); event.setManagedFlags(CAL_MANAGED_FLAGS); return event; } @@ -947,13 +1031,25 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable { private boolean updateEvent(LectureBlock lectureBlock, KalendarEvent event) { event.setSubject(lectureBlock.getTitle()); event.setLocation(lectureBlock.getLocation()); - event.setDescription(lectureBlock.getDescription()); + updateEventDescription(lectureBlock, event); event.setBegin(lectureBlock.getStartDate()); event.setEnd(lectureBlock.getEndDate()); event.setManagedFlags(CAL_MANAGED_FLAGS); return true; } + private void updateEventDescription(LectureBlock lectureBlock, KalendarEvent event) { + StringBuilder descr = new StringBuilder(); + if(StringHelper.containsNonWhitespace(lectureBlock.getDescription())) { + descr.append(lectureBlock.getDescription()); + } + if(StringHelper.containsNonWhitespace(lectureBlock.getPreparation())) { + if(descr.length() > 0) descr.append("\n"); + descr.append(lectureBlock.getPreparation()); + } + event.setDescription(descr.toString()); + } + private String generateExternalIdPrefix(RepositoryEntry entry) { StringBuilder sb = new StringBuilder(); sb.append("lecture-block-").append(entry.getKey()).append("-"); diff --git a/src/main/java/org/olat/modules/lecture/manager/RepositoryEntryLectureConfigurationDAO.java b/src/main/java/org/olat/modules/lecture/manager/RepositoryEntryLectureConfigurationDAO.java index d09e87f7c5ae3b3cc9a4d7c39086f70be41c070a..ed34cd557362da00e0a066f295c6a6c411423923 100644 --- a/src/main/java/org/olat/modules/lecture/manager/RepositoryEntryLectureConfigurationDAO.java +++ b/src/main/java/org/olat/modules/lecture/manager/RepositoryEntryLectureConfigurationDAO.java @@ -78,6 +78,18 @@ public class RepositoryEntryLectureConfigurationDAO { return configs == null || configs.isEmpty() ? null : configs.get(0); } + public boolean isConfigurationEnabledFor(RepositoryEntryRef entry) { + String query = "select config.key from lectureentryconfig config where config.entry.key=:entryKey and config.lectureEnabled=true"; + + List<Long> configs = dbInstance.getCurrentEntityManager() + .createQuery(query, Long.class) + .setParameter("entryKey", entry.getKey()) + .setFirstResult(0) + .setMaxResults(1) + .getResultList(); + return configs != null && configs.size() > 0 && configs.get(0).intValue() > 0; + } + public RepositoryEntryLectureConfiguration getConfiguration(LectureBlockRef entry) { StringBuilder sb = new StringBuilder(); sb.append("select config from lectureentryconfig config") diff --git a/src/main/java/org/olat/modules/lecture/model/LectureBlockAndRollCall.java b/src/main/java/org/olat/modules/lecture/model/LectureBlockAndRollCall.java index 5741ff75f332d77c5ba18621c878b5fd5723b96d..f17d10bff71b2d368c3946c331ecde5d78ca794b 100644 --- a/src/main/java/org/olat/modules/lecture/model/LectureBlockAndRollCall.java +++ b/src/main/java/org/olat/modules/lecture/model/LectureBlockAndRollCall.java @@ -25,6 +25,7 @@ import org.olat.modules.lecture.LectureBlock; import org.olat.modules.lecture.LectureBlockRef; import org.olat.modules.lecture.LectureBlockRollCall; import org.olat.modules.lecture.LectureBlockStatus; +import org.olat.modules.lecture.LectureRollCallStatus; /** * @@ -43,6 +44,7 @@ public class LectureBlockAndRollCall { private final Date startDate; private final boolean compulsory; private final LectureBlockStatus status; + private final LectureRollCallStatus rollCallStatus; private final Long rollCallKey; private final int lecturesAbsentNumber; @@ -61,6 +63,7 @@ public class LectureBlockAndRollCall { effectiveLectures = lectureBlock.getEffectiveLecturesNumber(); compulsory = lectureBlock.isCompulsory(); status = lectureBlock.getStatus(); + rollCallStatus = lectureBlock.getRollCallStatus(); if(rollCall == null) { rollCallKey = null; @@ -71,7 +74,7 @@ public class LectureBlockAndRollCall { rollCallKey = rollCall.getKey(); lecturesAttendedNumber = rollCall.getLecturesAttendedNumber(); lecturesAbsentNumber = rollCall.getLecturesAbsentNumber(); - lecturesAuthorizedAbsent = rollCall.getAbsenceAuthorized(); + lecturesAuthorizedAbsent = rollCall.getAbsenceAuthorized(); } } @@ -92,7 +95,11 @@ public class LectureBlockAndRollCall { } public LectureBlockStatus getStatus() { - return status; + return status == null ? LectureBlockStatus.active : status; + } + + public LectureRollCallStatus getRollCallStatus() { + return rollCallStatus == null ? LectureRollCallStatus.open : rollCallStatus; } public boolean isRollCalled() { diff --git a/src/main/java/org/olat/modules/lecture/model/LectureBlockAuditLogImpl.java b/src/main/java/org/olat/modules/lecture/model/LectureBlockAuditLogImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..7b322b2db84bac1d3f8183af1955a69379ad66d4 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/model/LectureBlockAuditLogImpl.java @@ -0,0 +1,194 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.olat.core.id.Persistable; +import org.olat.modules.lecture.LectureBlockAuditLog; + +/** + * + * + * Initial date: 11 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Entity(name="lectureblockauditlog") +@Table(name="o_lecture_block_audit_log") +public class LectureBlockAuditLogImpl implements LectureBlockAuditLog, Persistable { + + private static final long serialVersionUID = -1009831288341614553L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + + @Column(name="l_action", nullable=true, insertable=true, updatable=false) + private String action; + @Column(name="l_val_before", nullable=true, insertable=true, updatable=false) + private String before; + @Column(name="l_val_after", nullable=true, insertable=true, updatable=false) + private String after; + @Column(name="l_message", nullable=true, insertable=true, updatable=false) + private String message; + + @Column(name="fk_lecture_block", nullable=true, insertable=true, updatable=false) + private Long lectureBlockKey; + @Column(name="fk_roll_call", nullable=true, insertable=true, updatable=false) + private Long rollCallKey; + + @Column(name="fk_entry", nullable=true, insertable=true, updatable=false) + private Long entryKey; + @Column(name="fk_identity", nullable=true, insertable=true, updatable=false) + private Long identityKey; + @Column(name="fk_author", nullable=true, insertable=true, updatable=false) + private Long authorKey; + + @Override + public Long getKey() { + return key; + } + + @Override + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + @Override + public String getBefore() { + return before; + } + + public void setBefore(String before) { + this.before = before; + } + + @Override + public String getAfter() { + return after; + } + + public void setAfter(String after) { + this.after = after; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public Long getLectureBlockKey() { + return lectureBlockKey; + } + + public void setLectureBlockKey(Long lectureBlockKey) { + this.lectureBlockKey = lectureBlockKey; + } + + @Override + public Long getRollCallKey() { + return rollCallKey; + } + + public void setRollCallKey(Long rollCallKey) { + this.rollCallKey = rollCallKey; + } + + @Override + public Long getEntryKey() { + return entryKey; + } + + public void setEntryKey(Long entryKey) { + this.entryKey = entryKey; + } + + @Override + public Long getIdentityKey() { + return identityKey; + } + + public void setIdentityKey(Long identityKey) { + this.identityKey = identityKey; + } + + @Override + public Long getAuthorKey() { + return authorKey; + } + + public void setAuthorKey(Long authorKey) { + this.authorKey = authorKey; + } + + @Override + public int hashCode() { + return key == null ? 236520 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(obj == this) { + return true; + } + if(obj instanceof LectureBlockAuditLogImpl) { + LectureBlockAuditLogImpl auditLog = (LectureBlockAuditLogImpl)obj; + return key != null && key.equals(auditLog.getKey()); + } + return super.equals(obj); + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/model/LectureBlockImpl.java b/src/main/java/org/olat/modules/lecture/model/LectureBlockImpl.java index d8cf58ef86f05bf22557bc64fae4da011ee08137..6596c3de987d799c457871774b70f795b1182219 100644 --- a/src/main/java/org/olat/modules/lecture/model/LectureBlockImpl.java +++ b/src/main/java/org/olat/modules/lecture/model/LectureBlockImpl.java @@ -92,8 +92,6 @@ public class LectureBlockImpl implements Persistable, LectureBlock { private String location; @Column(name="l_comment", nullable=true, insertable=true, updatable=true) private String comment; - @Column(name="l_log", nullable=true, insertable=false, updatable=false) - private String log; @Temporal(TemporalType.TIMESTAMP) @Column(name="l_start_date", nullable=false, insertable=true, updatable=true) @@ -275,11 +273,6 @@ public class LectureBlockImpl implements Persistable, LectureBlock { this.effectiveLecturesNumber = effectiveLecturesNumber; } - @Override - public String getLog() { - return log; - } - @Override public Date getStartDate() { return startDate; diff --git a/src/main/java/org/olat/modules/lecture/model/LectureBlockLog.java b/src/main/java/org/olat/modules/lecture/model/LectureBlockLog.java deleted file mode 100644 index 48053f19b103c9a0d3696418da4b9f215866208b..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/modules/lecture/model/LectureBlockLog.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.modules.lecture.model; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; - -import org.olat.core.id.Persistable; - -/** - * Mapping used to update the log of a lecture block. - * - * Initial date: 28 juin 2017<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -@Entity(name="lectureblocklog") -@Table(name="o_lecture_block") -public class LectureBlockLog implements Persistable { - - private static final long serialVersionUID = -8262907202789409370L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) - private Long key; - - @Column(name="l_log", nullable=true, insertable=false, updatable=true) - private String log; - - @Override - public Long getKey() { - return key; - } - - public String getLog() { - return log; - } - - public void setLog(String log) { - this.log = log; - } - - @Override - public int hashCode() { - return key == null ? 56483658 : key.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if(this == obj) { - return true; - } - if(obj instanceof LectureBlockLog) { - LectureBlockLog blockLog = (LectureBlockLog)obj; - return key != null && key.equals(blockLog.key); - } - return super.equals(obj); - } - - @Override - public boolean equalsByPersistableKey(Persistable persistable) { - return equals(persistable); - } -} diff --git a/src/main/java/org/olat/modules/lecture/model/LectureBlockRollCallImpl.java b/src/main/java/org/olat/modules/lecture/model/LectureBlockRollCallImpl.java index 837bcb9a7b7ec3638a0e1129375d463ab5b6ed3a..58ff369f596cc9de1a15f8b822fba033542f62f9 100644 --- a/src/main/java/org/olat/modules/lecture/model/LectureBlockRollCallImpl.java +++ b/src/main/java/org/olat/modules/lecture/model/LectureBlockRollCallImpl.java @@ -87,9 +87,9 @@ public class LectureBlockRollCallImpl implements Persistable, LectureBlockRollCa @Temporal(TemporalType.TIMESTAMP) @Column(name="l_absence_appeal_date", nullable=true, insertable=true, updatable=true) private Date absenceAppealDate; - - @Column(name="l_log", nullable=true, insertable=true, updatable=true) - private String log; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="l_absence_supervisor_noti_date", nullable=true, insertable=true, updatable=true) + private Date absenceSupervisorNotificationDate; @ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=false) @JoinColumn(name="fk_identity", nullable=false, insertable=true, updatable=false) @@ -160,14 +160,6 @@ public class LectureBlockRollCallImpl implements Persistable, LectureBlockRollCa this.absenceAppealDate = absenceAppealDate; } - public String getLog() { - return log; - } - - public void setLog(String log) { - this.log = log; - } - @Override public Identity getIdentity() { return identity; @@ -257,6 +249,16 @@ public class LectureBlockRollCallImpl implements Persistable, LectureBlockRollCa this.lecturesAbsentNumber = lecturesAbsentNumber; } + @Override + public Date getAbsenceSupervisorNotificationDate() { + return absenceSupervisorNotificationDate; + } + + @Override + public void setAbsenceSupervisorNotificationDate(Date absenceSupervisorNotificationDate) { + this.absenceSupervisorNotificationDate = absenceSupervisorNotificationDate; + } + @Override public LectureBlock getLectureBlock() { return lectureBlock; diff --git a/src/main/java/org/olat/modules/lecture/model/ReasonImpl.java b/src/main/java/org/olat/modules/lecture/model/ReasonImpl.java index 8d4e8bdf272be6d08d73b878c2f576d19da6fb08..f6e0e75db93adffdda9cbbcaf21ff0a79d69f58a 100644 --- a/src/main/java/org/olat/modules/lecture/model/ReasonImpl.java +++ b/src/main/java/org/olat/modules/lecture/model/ReasonImpl.java @@ -91,6 +91,7 @@ public class ReasonImpl implements Persistable, Reason { return title; } + @Override public void setTitle(String title) { this.title = title; } @@ -100,6 +101,7 @@ public class ReasonImpl implements Persistable, Reason { return description; } + @Override public void setDescription(String description) { this.description = description; } diff --git a/src/main/java/org/olat/modules/lecture/restapi/Examples.java b/src/main/java/org/olat/modules/lecture/restapi/Examples.java new file mode 100644 index 0000000000000000000000000000000000000000..bb6681e84e6ac00e079f7a5b3e3bbea846b2f939 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/restapi/Examples.java @@ -0,0 +1,69 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.restapi; + +import java.util.Date; + +/** + * + * + * Initial date: 20 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class Examples { + + public static final LectureBlockVO SAMPLE_LECTUREBLOCKVO = new LectureBlockVO(); + public static final LectureBlockRollCallVO SAMPLE_LECTUREBLOCKROLLCALLVO = new LectureBlockRollCallVO(); + public static final RepositoryEntryLectureConfigurationVO SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO = new RepositoryEntryLectureConfigurationVO(); + + static { + SAMPLE_LECTUREBLOCKVO.setKey(345l); + SAMPLE_LECTUREBLOCKVO.setTitle("Lecture"); + SAMPLE_LECTUREBLOCKVO.setDescription("A little description"); + SAMPLE_LECTUREBLOCKVO.setComment("A comment"); + SAMPLE_LECTUREBLOCKVO.setLocation("The secret location"); + SAMPLE_LECTUREBLOCKVO.setManagedFlagsString("all"); + SAMPLE_LECTUREBLOCKVO.setPreparation("Lot of"); + SAMPLE_LECTUREBLOCKVO.setPlannedLectures(4); + SAMPLE_LECTUREBLOCKVO.setExternalId("EXT-234"); + SAMPLE_LECTUREBLOCKVO.setStartDate(new Date()); + SAMPLE_LECTUREBLOCKVO.setEndDate(new Date()); + + SAMPLE_LECTUREBLOCKROLLCALLVO.setKey(23l); + SAMPLE_LECTUREBLOCKROLLCALLVO.setLecturesAbsentNumber(2); + SAMPLE_LECTUREBLOCKROLLCALLVO.setLecturesAttendedNumber(3); + SAMPLE_LECTUREBLOCKROLLCALLVO.setComment("A comment"); + SAMPLE_LECTUREBLOCKROLLCALLVO.setAbsenceReason("The reason of the absence"); + SAMPLE_LECTUREBLOCKROLLCALLVO.setAbsenceAuthorized(Boolean.TRUE); + SAMPLE_LECTUREBLOCKROLLCALLVO.setAbsenceSupervisorNotificationDate(new Date()); + SAMPLE_LECTUREBLOCKROLLCALLVO.setIdentityKey(2439873895l); + SAMPLE_LECTUREBLOCKROLLCALLVO.setLectureBlockKey(345l); + + SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO.setCalculateAttendanceRate(Boolean.TRUE); + SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO.setLectureEnabled(Boolean.TRUE); + SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO.setCalculateAttendanceRate(Boolean.TRUE); + SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO.setOverrideModuleDefault(Boolean.TRUE); + SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO.setCourseCalendarSyncEnabled(Boolean.TRUE); + SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO.setRequiredAttendanceRate(34.0d); + SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO.setRollCallEnabled(Boolean.TRUE); + SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO.setTeacherCalendarSyncEnabled(Boolean.TRUE); + } +} diff --git a/src/main/java/org/olat/modules/lecture/restapi/LectureBlockRollCallVO.java b/src/main/java/org/olat/modules/lecture/restapi/LectureBlockRollCallVO.java new file mode 100644 index 0000000000000000000000000000000000000000..afc774f1dc41c686a9282e734a391223dd398b26 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/restapi/LectureBlockRollCallVO.java @@ -0,0 +1,139 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.restapi; + +import java.util.Date; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.olat.modules.lecture.LectureBlockRollCall; + +/** + * + * Initial date: 28 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "lectureBlockRollCallVO") +public class LectureBlockRollCallVO { + + private Long key; + + private Integer lecturesAttendedNumber; + private Integer lecturesAbsentNumber; + + private String comment; + private String absenceReason; + private Boolean absenceAuthorized; + private Date absenceSupervisorNotificationDate; + + private Long identityKey; + private Long lectureBlockKey; + + public LectureBlockRollCallVO() { + // + } + + public LectureBlockRollCallVO(LectureBlockRollCall rollCall) { + key = rollCall.getKey(); + comment = rollCall.getComment(); + absenceReason = rollCall.getAbsenceReason(); + absenceAuthorized = rollCall.getAbsenceAuthorized(); + absenceSupervisorNotificationDate = rollCall.getAbsenceSupervisorNotificationDate(); + + identityKey = rollCall.getIdentity().getKey(); + lectureBlockKey = rollCall.getLectureBlock().getKey(); + } + + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + public Integer getLecturesAttendedNumber() { + return lecturesAttendedNumber; + } + + public void setLecturesAttendedNumber(Integer lecturesAttendedNumber) { + this.lecturesAttendedNumber = lecturesAttendedNumber; + } + + public Integer getLecturesAbsentNumber() { + return lecturesAbsentNumber; + } + + public void setLecturesAbsentNumber(Integer lecturesAbsentNumber) { + this.lecturesAbsentNumber = lecturesAbsentNumber; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public String getAbsenceReason() { + return absenceReason; + } + + public void setAbsenceReason(String absenceReason) { + this.absenceReason = absenceReason; + } + + public Boolean getAbsenceAuthorized() { + return absenceAuthorized; + } + + public void setAbsenceAuthorized(Boolean absenceAuthorized) { + this.absenceAuthorized = absenceAuthorized; + } + + public Date getAbsenceSupervisorNotificationDate() { + return absenceSupervisorNotificationDate; + } + + public void setAbsenceSupervisorNotificationDate(Date absenceSupervisorNotificationDate) { + this.absenceSupervisorNotificationDate = absenceSupervisorNotificationDate; + } + + public Long getIdentityKey() { + return identityKey; + } + + public void setIdentityKey(Long identityKey) { + this.identityKey = identityKey; + } + + public Long getLectureBlockKey() { + return lectureBlockKey; + } + + public void setLectureBlockKey(Long lectureBlockKey) { + this.lectureBlockKey = lectureBlockKey; + } +} diff --git a/src/main/java/org/olat/modules/lecture/restapi/LectureBlockRollCallWebService.java b/src/main/java/org/olat/modules/lecture/restapi/LectureBlockRollCallWebService.java new file mode 100644 index 0000000000000000000000000000000000000000..9da864ffe1b58001788a5d3c2acab81efce845ab --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/restapi/LectureBlockRollCallWebService.java @@ -0,0 +1,216 @@ +/** + + + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.restapi; + +import static org.olat.restapi.security.RestSecurityHelper.getRoles; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.id.Roles; +import org.olat.modules.lecture.LectureBlockRollCall; +import org.olat.modules.lecture.LectureBlockRollCallSearchParameters; +import org.olat.modules.lecture.LectureService; + +/** + * + * Initial date: 28 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LectureBlockRollCallWebService { + + /** + * Return a list lecture block roll call. + * + * @response.representation.200.qname {http://www.example.com}lectureBlockRollCallVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc A lecture block roll call + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_LECTUREBLOCKROLLCALLVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @param closed If true, the status of the block is done or the status of the roll call is closed or auto closed + * @param hasAbsence If true, the roll call has an absence + * @param hasSupervisorNotificationDate If true, the roll call has a supervisor notification date set + * @param httpRequest The HTTP request + * @return The roll calls + */ + @GET + @Path("/") + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response getRollCalls(@QueryParam("closed") Boolean closed, @QueryParam("hasAbsence") Boolean hasAbsence, + @QueryParam("hasSupervisorNotificationDate") Boolean hasSupervisorNotificationDate, + @QueryParam("lectureBlockKey") Long lectureBlockKey, + @Context HttpServletRequest httpRequest) { + Roles roles = getRoles(httpRequest); + if(!roles.isOLATAdmin()) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + + LectureService lectureService = CoreSpringFactory.getImpl(LectureService.class); + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + if(hasAbsence != null) { + searchParams.setHasAbsence(hasAbsence); + } + if(hasSupervisorNotificationDate != null) { + searchParams.setHasSupervisorNotificationDate(hasSupervisorNotificationDate); + } + if(closed != null) { + searchParams.setClosed(closed); + } + if(lectureBlockKey != null) { + searchParams.setLectureBlockKey(lectureBlockKey); + } + + List<LectureBlockRollCall> rollCalls = lectureService.getRollCalls(searchParams); + List<LectureBlockRollCallVO> voList = new ArrayList<>(rollCalls.size()); + for(LectureBlockRollCall rollCall:rollCalls) { + voList.add(new LectureBlockRollCallVO(rollCall)); + } + LectureBlockRollCallVO[] voes = voList.toArray(new LectureBlockRollCallVO[voList.size()]); + return Response.ok(voes).build(); + } + + /** + * Return the lecture block roll call specified by the primary key. + * + * @response.representation.200.qname {http://www.example.com}lectureBlockRollCallVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc A lecture block roll call + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_LECTUREBLOCKROLLCALLVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The role call was not found + * @param rollCallKey The primary key of the roll call + * @param httpRequest The HTTP request + * @return The roll call + */ + @GET + @Path("{rollCallKey}") + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response getRollCall(@PathParam("rollCallKey") Long rollCallKey, @Context HttpServletRequest httpRequest) { + Roles roles = getRoles(httpRequest); + if(!roles.isOLATAdmin()) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + + LectureService lectureService = CoreSpringFactory.getImpl(LectureService.class); + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setRollCallKey(rollCallKey); + List<LectureBlockRollCall> rollCalls = lectureService.getRollCalls(searchParams); + if(rollCalls.size() == 1) { + LectureBlockRollCall rollCall = rollCalls.get(0); + LectureBlockRollCallVO vo = new LectureBlockRollCallVO(rollCall); + return Response.ok(vo).build(); + } + return Response.serverError().status(Status.NOT_FOUND).build(); + } + + /** + * Update a roll call. The absence are not updated by this method! Only the + * supervisor notification date, the comment and the reason. The method doesn't + * create a new roll call. + * + * @response.representation.200.qname {http://www.example.com}lectureBlockRollCallVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc A lecture block roll call + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_LECTUREBLOCKROLLCALLVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The role call was not found + * @param rollCallVo The roll call to update + * @param httpRequest The HTTP request + * @return The updated roll call + */ + @PUT + @Path("/") + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response updateRollCallPut(LectureBlockRollCallVO rollCallVo, @Context HttpServletRequest httpRequest) { + return updateLectureBlockRollCall(rollCallVo, httpRequest); + } + + /** + * Update a roll call. The absence are not updated by this method! Only the + * supervisor notification date, the comment and the reason. The method doesn't + * create a new roll call. + * + * @response.representation.200.qname {http://www.example.com}lectureBlockRollCallVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc A lecture block roll call + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_LECTUREBLOCKROLLCALLVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The role call was not found + * @param rollCallVo The roll call to update + * @param httpRequest The HTTP request + * @return The updated roll call + */ + @POST + @Path("/") + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response updateRollCall(LectureBlockRollCallVO rollCallVo, @Context HttpServletRequest httpRequest) { + return updateLectureBlockRollCall(rollCallVo, httpRequest); + } + + private Response updateLectureBlockRollCall(LectureBlockRollCallVO rollCallVo, HttpServletRequest httpRequest) { + Roles roles = getRoles(httpRequest); + if(!roles.isOLATAdmin()) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + if(rollCallVo.getKey() == null) { + return Response.serverError().status(Status.BAD_REQUEST).build(); + } + + LectureService lectureService = CoreSpringFactory.getImpl(LectureService.class); + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setRollCallKey(rollCallVo.getKey()); + List<LectureBlockRollCall> rollCalls = lectureService.getRollCalls(searchParams); + if(rollCalls.size() == 1) { + LectureBlockRollCall rollCall = rollCalls.get(0); + rollCall.setAbsenceSupervisorNotificationDate(rollCallVo.getAbsenceSupervisorNotificationDate()); + if(rollCallVo.getAbsenceReason() != null) { + rollCall.setAbsenceReason(rollCallVo.getAbsenceReason()); + } + if(rollCallVo.getComment() != null) { + rollCall.setComment(rollCallVo.getComment()); + } + rollCall = lectureService.updateRollCall(rollCall); + LectureBlockRollCallVO vo = new LectureBlockRollCallVO(rollCall); + return Response.ok(vo).build(); + } + return Response.serverError().status(Status.NOT_FOUND).build(); + } + +} diff --git a/src/main/java/org/olat/modules/lecture/restapi/LectureBlockWebService.java b/src/main/java/org/olat/modules/lecture/restapi/LectureBlockWebService.java index 9d7e1588552a5e8b49ad3930b8a3d123c522a257..1f5fb08d06dd99189996e374d195f5bbf9b663d4 100644 --- a/src/main/java/org/olat/modules/lecture/restapi/LectureBlockWebService.java +++ b/src/main/java/org/olat/modules/lecture/restapi/LectureBlockWebService.java @@ -68,12 +68,29 @@ public class LectureBlockWebService { securityManager = CoreSpringFactory.getImpl(BaseSecurity.class); } + /** + * Return a specific lecture blocks. + * @response.representation.200.qname {http://www.example.com}lectureBlocksVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc A lecture blocks + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_LECTUREBLOCKVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course not found + * @return The lecture blocks + */ @GET @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public Response getLectureBlock() { return Response.ok(new LectureBlockVO(lectureBlock, entry.getKey())).build(); } - + + /** + * Delete a specific lecture blocks. + * @response.representation.200.doc Lecture blocks deleted + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course not found + * @return Nothing + */ @DELETE public Response deleteLectureBlock() { lectureService.deleteLectureBlock(lectureBlock); @@ -81,6 +98,15 @@ public class LectureBlockWebService { return Response.ok().build(); } + /** + * Get all teachers of the specific lecture blocks. + * @response.representation.200.qname {http://www.example.com}userVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The array of authors + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course not found + * @return It returns an array of <code>UserVO</code> + */ @GET @Path("teachers") @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @@ -89,6 +115,14 @@ public class LectureBlockWebService { return identitiesToResponse(teachers); } + /** + * Add a teacher to the lecture block + * @response.representation.200.doc The user is a teacher of the lecture block + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course or the user not found + * @param identityKey The user identifier + * @return It returns 200 if the user is added as teacher of the lecture block. + */ @PUT @Path("teachers/{identityKey}") public Response addTeacher(@PathParam("identityKey") Long identityKey) { @@ -100,6 +134,14 @@ public class LectureBlockWebService { return Response.ok().build(); } + /** + * Remove a teacher of the lecture block + * @response.representation.200.doc The user was successfully removed as teacher of the lecture block + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course, the lecture block or the user not found + * @param identityKey The user identifier + * @return It returns 200 if the user is removed as teacher of the lecture block + */ @DELETE @Path("teachers/{identityKey}") public Response removeTeacher(@PathParam("identityKey") Long identityKey) { @@ -114,7 +156,6 @@ public class LectureBlockWebService { /** * Add the group of the course to the lecture block participants list. - * * @response.representation.200.doc Successfully added * @return 200 if all ok */ @@ -135,7 +176,6 @@ public class LectureBlockWebService { /** * Remove the group of the course from the lecture block participants. - * * @response.representation.200.doc Successfully removed * @return 200 if all ok */ @@ -155,7 +195,6 @@ public class LectureBlockWebService { /** * Synchronize the calendars based on the lecture block. - * * @response.representation.200.doc The calendar is successfully synchronized * @return 200 if all ok */ diff --git a/src/main/java/org/olat/modules/lecture/restapi/LectureBlocksRootWebService.java b/src/main/java/org/olat/modules/lecture/restapi/LectureBlocksRootWebService.java new file mode 100644 index 0000000000000000000000000000000000000000..22ab3b8c9cff147a4faf3ca5ac232e3d5b6ccc4e --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/restapi/LectureBlocksRootWebService.java @@ -0,0 +1,97 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.restapi; + +import static org.olat.restapi.security.RestSecurityHelper.getRoles; +import static org.olat.restapi.security.RestSecurityHelper.parseDate; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.olat.commons.calendar.CalendarUtils; +import org.olat.core.CoreSpringFactory; +import org.olat.core.id.Roles; +import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureService; +import org.olat.modules.lecture.model.LecturesBlockSearchParameters; + +/** + * + * Initial date: 8 juin 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Path("repo/lectures") +public class LectureBlocksRootWebService { + + + /** + * Return the lecture blocks of the specified course or repository entry. + * @response.representation.200.qname {http://www.example.com}lectureBlocksVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc An array of lecture blocks + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_LECTUREBLOCKVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course not found + * @param httpRequest The HTTP request + * @return The lecture blocks + */ + @GET + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response searchLectureBlocks(@QueryParam("date") String date, @Context HttpServletRequest httpRequest) { + Roles roles = getRoles(httpRequest); + if(!roles.isOLATAdmin()) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + + LecturesBlockSearchParameters searchParams = new LecturesBlockSearchParameters(); + if(date != null) { + Date d = parseDate(date, Locale.ENGLISH); + Date startDate = CalendarUtils.removeTime(d); + Date endDate = CalendarUtils.endOfDay(d); + searchParams.setStartDate(startDate); + searchParams.setEndDate(endDate); + } + List<LectureBlock> blockList = CoreSpringFactory.getImpl(LectureService.class).getLectureBlocks(searchParams); + List<LectureBlockVO> voList = new ArrayList<>(blockList.size()); + for(LectureBlock block:blockList) { + voList.add(new LectureBlockVO(block, block.getEntry().getKey())); + } + LectureBlockVO[] voes = voList.toArray(new LectureBlockVO[voList.size()]); + return Response.ok(voes).build(); + } + + @Path("rollcalls") + public LectureBlockRollCallWebService getLectureBlockRollCallWebService() { + return new LectureBlockRollCallWebService(); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/restapi/LectureBlocksWebService.java b/src/main/java/org/olat/modules/lecture/restapi/LectureBlocksWebService.java index 4e431a5794d38d99601a4b338535181dccbdc871..a46fcf2ccd6cc64a4b686433b3adc831b6146341 100644 --- a/src/main/java/org/olat/modules/lecture/restapi/LectureBlocksWebService.java +++ b/src/main/java/org/olat/modules/lecture/restapi/LectureBlocksWebService.java @@ -19,6 +19,7 @@ */ package org.olat.modules.lecture.restapi; +import static org.olat.restapi.security.RestSecurityHelper.getIdentity; import static org.olat.restapi.security.RestSecurityHelper.getRoles; import java.util.ArrayList; @@ -63,12 +64,18 @@ public class LectureBlocksWebService { } /** - * Return the lecture block. - * + * Return the lecture blocks of the specified course or repository entry. + * @response.representation.200.qname {http://www.example.com}lectureBlocksVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc An array of lecture blocks + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_LECTUREBLOCKVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course not found * @param httpRequest The HTTP request - * @return The web service for a single lecture block. + * @return The lecture blocks */ @GET + @Path("") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getLectureBlocks(@Context HttpServletRequest httpRequest) { Roles roles = getRoles(httpRequest); @@ -85,7 +92,20 @@ public class LectureBlocksWebService { return Response.ok(voes).build(); } + /** + * Create or update a lecture block. + * @response.representation.200.qname {http://www.example.com}lectureBlocksVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The updated configuration + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_LECTUREBLOCKVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course not found + * @param block The lecture block + * @param request The HTTP request + * @return It returns the updated / created lecture block. + */ @PUT + @Path("") @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public Response putLectureBlocks(LectureBlockVO block, @Context HttpServletRequest httpRequest) { @@ -97,7 +117,20 @@ public class LectureBlocksWebService { return Response.ok(new LectureBlockVO(updatedBlock, entry.getKey())).build(); } + /** + * Create or update a lecture block. + * @response.representation.200.qname {http://www.example.com}lectureBlocksVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The updated configuration + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_LECTUREBLOCKVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course not found + * @param block The lecture block + * @param request The HTTP request + * @return It returns the updated / created lecture block. + */ @POST + @Path("") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Consumes({MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public Response postLectureBlocks(LectureBlockVO block, @Context HttpServletRequest httpRequest) { @@ -158,6 +191,17 @@ public class LectureBlocksWebService { return savedLectureBlock; } + /** + * Return the configuration of the specified course or repository entry. + * @response.representation.200.qname {http://www.example.com}repositoryEntryLectureConfigurationVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The configuration of the lecture's feature + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course not found + * @param httpRequest The HTTP request + * @return The configuration + */ @GET @Path("configuration") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @@ -177,6 +221,19 @@ public class LectureBlocksWebService { return Response.ok(configVo).build(); } + /** + * Update the configuration of the lecture's feature of a specified + * course or repository entry. + * @response.representation.200.qname {http://www.example.com}repositoryEntryLectureConfigurationVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The updated configuration + * @response.representation.200.example {@link org.olat.modules.lecture.restapi.Examples#SAMPLE_REPOSITORYENTRYLECTURECONFIGURATIONVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The course not found + * @param configuration The configuration + * @param request The HTTP request + * @return It returns the updated configuration. + */ @POST @Path("configuration") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @@ -214,7 +271,6 @@ public class LectureBlocksWebService { /** * To get the web service for a specific lecture block. - * * @param lectureBlockKey The primary key of the lecture block * @param httpRequest The HTTP request * @return The web service for a single lecture block. @@ -233,10 +289,9 @@ public class LectureBlocksWebService { } /** - * Synchronize the calendars based on the lecture block. - * + * Synchronize the calendars based on the lecture blocks. * @response.representation.200.doc The calendar is successfully synchronized - * @return 200 if all ok + * @return 200 if the calendar is successfully synchronized */ @POST @Path("sync/calendar") @@ -244,4 +299,22 @@ public class LectureBlocksWebService { lectureService.syncCalendars(entry); return Response.ok().build(); } + + /** + * Adapt all roll call to the effective number of lectures. Use with caution! + * @response.representation.200.doc The adaptation is successful + * @param httpRequest The HTTP request + * @return 200 if the adaptation is successful + */ + @GET + @Path("adaptation") + public Response adapatation(@Context HttpServletRequest httpRequest) { + Roles roles = getRoles(httpRequest); + if(!roles.isOLATAdmin()) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + + lectureService.adaptAll(getIdentity(httpRequest)); + return Response.ok().build(); + } } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/AbstractTeacherOverviewController.java b/src/main/java/org/olat/modules/lecture/ui/AbstractTeacherOverviewController.java index eee5838290e6aac82646b9b661031732df434f8a..e8fb0d1b71553413275aea962f4618434a83ddd1 100644 --- a/src/main/java/org/olat/modules/lecture/ui/AbstractTeacherOverviewController.java +++ b/src/main/java/org/olat/modules/lecture/ui/AbstractTeacherOverviewController.java @@ -100,9 +100,9 @@ public abstract class AbstractTeacherOverviewController extends BasicController mainVC = createVelocityContainer("teacher_view"); - startButton = LinkFactory.createButton("start", mainVC, this); + startButton = LinkFactory.createButton("start.desktop", mainVC, this); startButton.setVisible(false); - startWizardButton = LinkFactory.createButton("start.wizard", mainVC, this); + startWizardButton = LinkFactory.createButton("start.mobile", mainVC, this); startWizardButton.setVisible(false); allTeachersSwitch = LinkFactory.createToolLink("all.teachers.switch", translate("all.teachers.switch"), this); @@ -110,8 +110,10 @@ public abstract class AbstractTeacherOverviewController extends BasicController allTeachersSwitch.setUserObject(all); if(all) { allTeachersSwitch.setIconLeftCSS("o_icon o_icon-lg o_icon_toggle_on"); + allTeachersSwitch.setTooltip(translate("all.teachers.switch.tooltip.on")); } else { allTeachersSwitch.setIconLeftCSS("o_icon o_icon-lg o_icon_toggle_off"); + allTeachersSwitch.setTooltip(translate("all.teachers.switch.tooltip.off")); } searchCtrl = new TeacherOverviewSearchController(ureq, getWindowControl(), withRepositoryEntry); @@ -119,23 +121,23 @@ public abstract class AbstractTeacherOverviewController extends BasicController mainVC.put("search", searchCtrl.getInitialComponent()); currentLecturesBlockCtrl = new TeacherLecturesTableController(ureq, getWindowControl(), - admin, "empty.table.current.lectures.blocks", withRepositoryEntry, withTeachers); + admin, "empty.table.current.lectures.blocks", false, "current", withRepositoryEntry, withTeachers); listenTo(currentLecturesBlockCtrl); mainVC.put("currentLectures", currentLecturesBlockCtrl.getInitialComponent()); pendingLecturesBlockCtrl = new TeacherLecturesTableController(ureq, getWindowControl(), - admin, "empty.table.lectures.blocks", withRepositoryEntry, withTeachers); + admin, "empty.table.lectures.blocks", false, "pending", withRepositoryEntry, withTeachers); listenTo(pendingLecturesBlockCtrl); mainVC.put("pendingLectures", pendingLecturesBlockCtrl.getInitialComponent()); nextLecturesBlockCtrl = new TeacherLecturesTableController(ureq, getWindowControl(), - admin, "empty.table.lectures.blocks", withRepositoryEntry, withTeachers); + admin, "empty.table.lectures.blocks", true, "next", withRepositoryEntry, withTeachers); nextLecturesBlockCtrl.setTablePageSize(5); listenTo(nextLecturesBlockCtrl); mainVC.put("nextLectures", nextLecturesBlockCtrl.getInitialComponent()); closedLecturesBlockCtrl = new TeacherLecturesTableController(ureq, getWindowControl(), - admin, "empty.table.lectures.blocks", withRepositoryEntry, withTeachers); + admin, "empty.table.lectures.blocks", false, "closed", withRepositoryEntry, withTeachers); closedLecturesBlockCtrl.setTablePageSize(10); listenTo(closedLecturesBlockCtrl); mainVC.put("closedLectures", closedLecturesBlockCtrl.getInitialComponent()); @@ -184,7 +186,9 @@ public abstract class AbstractTeacherOverviewController extends BasicController startWizardButton.setUserObject(block); currentBlocks.add(row); - } else if(block.getRollCallStatus() == LectureRollCallStatus.closed || block.getRollCallStatus() == LectureRollCallStatus.autoclosed) { + } else if(block.getStatus() == LectureBlockStatus.cancelled + || block.getRollCallStatus() == LectureRollCallStatus.closed + || block.getRollCallStatus() == LectureRollCallStatus.autoclosed) { closedBlocks.add(row); } else if(block.getStartDate() != null && block.getStartDate().after(now)) { nextBlocks.add(row); @@ -201,6 +205,8 @@ public abstract class AbstractTeacherOverviewController extends BasicController mainVC.contextPut("nextBlockSize", nextBlocks.size()); closedLecturesBlockCtrl.loadModel(closedBlocks); mainVC.contextPut("closedBlockSize", closedBlocks.size()); + mainVC.contextPut("totalBlockSize", getRowCount()); + dirtyTables = false; } @@ -356,7 +362,7 @@ public abstract class AbstractTeacherOverviewController extends BasicController RollCallSecurityCallback secCallback = getRollCallSecurityCallback(reloadedBlock, teachers.contains(getIdentity())); rollCallWizardCtrl = new TeacherRollCallWizardController(ureq, getWindowControl(), reloadedBlock, participants, secCallback); if(withRepositoryEntry) { - rollCallCtrl.addLoggingResourceable(CoreLoggingResourceable.wrap(reloadedBlock.getEntry().getOlatResource(), + rollCallWizardCtrl.addLoggingResourceable(CoreLoggingResourceable.wrap(reloadedBlock.getEntry().getOlatResource(), OlatResourceableType.course, reloadedBlock.getEntry().getDisplayname())); } listenTo(rollCallWizardCtrl); @@ -387,8 +393,10 @@ public abstract class AbstractTeacherOverviewController extends BasicController } if(newValue) { allTeachersSwitch.setIconLeftCSS("o_icon o_icon-lg o_icon_toggle_on"); + allTeachersSwitch.setTooltip(translate("all.teachers.switch.tooltip.on")); } else { allTeachersSwitch.setIconLeftCSS("o_icon o_icon-lg o_icon_toggle_off"); + allTeachersSwitch.setTooltip(translate("all.teachers.switch.tooltip.off")); } allTeachersSwitch.setUserObject(newValue); } diff --git a/src/main/java/org/olat/modules/lecture/ui/CancelRollCallConfirmationController.java b/src/main/java/org/olat/modules/lecture/ui/CancelRollCallConfirmationController.java index 5121e2df26f94bf74e714a590472e4780cb6a957..3eb1fd0fe93edb2ce3409f38ef13ce0f063a73ec 100644 --- a/src/main/java/org/olat/modules/lecture/ui/CancelRollCallConfirmationController.java +++ b/src/main/java/org/olat/modules/lecture/ui/CancelRollCallConfirmationController.java @@ -35,6 +35,7 @@ import org.olat.core.logging.activity.LearningResourceLoggingAction; import org.olat.core.logging.activity.OlatResourceableType; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.Reason; import org.olat.modules.lecture.RollCallSecurityCallback; @@ -127,13 +128,15 @@ public class CancelRollCallConfirmationController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { + String before = lectureService.toAuditXml(lectureBlock); Long reasonKey = new Long(effectiveEndReasonEl.getSelectedKey()); Reason selectedReason = lectureService.getReason(reasonKey); lectureBlock.setReasonEffectiveEnd(selectedReason); lectureBlock = lectureService.cancel(lectureBlock); + String after = lectureService.toAuditXml(lectureBlock); + lectureService.auditLog(LectureBlockAuditLog.Action.cancelLectureBlock, before, after, null, lectureBlock, null, lectureBlock.getEntry(), null, getIdentity()); fireEvent(ureq, Event.DONE_EVENT); - lectureService.appendToLectureBlockLog(lectureBlock, getIdentity(), null, "Cancelled"); ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LECTURE_BLOCK_ROLL_CALL_CANCELLED, getClass(), CoreLoggingResourceable.wrap(lectureBlock, OlatResourceableType.lectureBlock, lectureBlock.getTitle())); } diff --git a/src/main/java/org/olat/modules/lecture/ui/CloseRollCallConfirmationController.java b/src/main/java/org/olat/modules/lecture/ui/CloseRollCallConfirmationController.java index 848f12de3e64d3802ea3e14aaba190ab631b629f..333dc4fab9c0d010c70c9acfddb77f9f2d8bb6f6 100644 --- a/src/main/java/org/olat/modules/lecture/ui/CloseRollCallConfirmationController.java +++ b/src/main/java/org/olat/modules/lecture/ui/CloseRollCallConfirmationController.java @@ -25,11 +25,15 @@ import java.util.Date; import java.util.List; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; @@ -39,6 +43,8 @@ import org.olat.core.logging.activity.OlatResourceableType; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.StringHelper; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; +import org.olat.modules.lecture.LectureModule; import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.Reason; import org.olat.modules.lecture.RollCallSecurityCallback; @@ -52,6 +58,7 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class CloseRollCallConfirmationController extends FormBasicController { + private FormLink quickSaveButton; private TextElement blockCommentEl; private SingleSelection effectiveLecturesEl; private SingleSelection effectiveEndReasonEl; @@ -60,6 +67,8 @@ public class CloseRollCallConfirmationController extends FormBasicController { private LectureBlock lectureBlock; private final RollCallSecurityCallback secCallback; + @Autowired + private LectureModule lectureModule; @Autowired private LectureService lectureService; @@ -78,26 +87,28 @@ public class CloseRollCallConfirmationController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - - int plannedLectures = lectureBlock.getPlannedLecturesNumber(); - String[] effectiveKeys = new String[plannedLectures]; - for(int i=plannedLectures; i-->0; ) { - effectiveKeys[i] = Integer.toString(i + 1); - } - effectiveLecturesEl = uifactory.addDropdownSingleselect("effective.lectures", formLayout, effectiveKeys, effectiveKeys, null); - int selectedEffectiveLectures = lectureBlock.getPlannedLecturesNumber(); - if(lectureBlock.getEffectiveLecturesNumber() > 0) { - selectedEffectiveLectures = lectureBlock.getEffectiveLecturesNumber(); - } - String selectedKey = Integer.toString(selectedEffectiveLectures); - for(String effectiveKey:effectiveKeys) { - if(effectiveKey.equals(selectedKey)) { - effectiveLecturesEl.select(effectiveKey, true); - break; + formLayout.setElementCssClass("o_sel_lecture_confirm_close_form"); + if(lectureModule.isStatusPartiallyDoneEnabled()) { + int plannedLectures = lectureBlock.getPlannedLecturesNumber(); + String[] effectiveKeys = new String[plannedLectures]; + for(int i=plannedLectures; i-->0; ) { + effectiveKeys[i] = Integer.toString(i + 1); + } + effectiveLecturesEl = uifactory.addDropdownSingleselect("effective.lectures", formLayout, effectiveKeys, effectiveKeys, null); + int selectedEffectiveLectures = lectureBlock.getPlannedLecturesNumber(); + if(lectureBlock.getEffectiveLecturesNumber() > 0) { + selectedEffectiveLectures = lectureBlock.getEffectiveLecturesNumber(); + } + String selectedKey = Integer.toString(selectedEffectiveLectures); + for(String effectiveKey:effectiveKeys) { + if(effectiveKey.equals(selectedKey)) { + effectiveLecturesEl.select(effectiveKey, true); + break; + } } } - String datePage = velocity_root + "/date_start_end.html"; + String datePage = velocity_root + "/date_end.html"; FormLayoutContainer dateCont = FormLayoutContainer.createCustomFormLayout("start_end", getTranslator(), datePage); dateCont.setLabel("lecture.block.effective.end", null); formLayout.add(dateCont); @@ -163,6 +174,7 @@ public class CloseRollCallConfirmationController extends FormBasicController { buttonsCont.setRootForm(mainForm); formLayout.add(buttonsCont); uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); + quickSaveButton = uifactory.addFormLink("save.temporary", buttonsCont, Link.BUTTON); uifactory.addFormSubmitButton("close.lecture.blocks", buttonsCont); } @@ -173,37 +185,26 @@ public class CloseRollCallConfirmationController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { - lectureBlock.setComment(blockCommentEl.getValue()); - - String selectedKey = effectiveLecturesEl.getSelectedKey(); - int effectiveLectures = lectureBlock.getPlannedLecturesNumber(); - try { - effectiveLectures = Integer.parseInt(selectedKey); - } catch(Exception ex) { - logError("", ex); - } - lectureBlock.setEffectiveLecturesNumber(effectiveLectures); - Date effectiveEndDate = getEffectiveEndDate(); - if(effectiveEndDate == null) { - lectureBlock.setReasonEffectiveEnd(null); - } else { - lectureBlock.setEffectiveEndDate(effectiveEndDate); - if("-".equals(effectiveEndReasonEl.getSelectedKey())) { - lectureBlock.setReasonEffectiveEnd(null); - } else { - Long reasonKey = new Long(effectiveEndReasonEl.getSelectedKey()); - Reason selectedReason = lectureService.getReason(reasonKey); - lectureBlock.setReasonEffectiveEnd(selectedReason); - } - } - lectureBlock = lectureService.close(lectureBlock); + String before = lectureService.toAuditXml(lectureBlock); + commitLectureBlocks(); + lectureBlock = lectureService.close(lectureBlock, getIdentity()); fireEvent(ureq, Event.DONE_EVENT); - lectureService.appendToLectureBlockLog(lectureBlock, getIdentity(), null, "Closed"); + String after = lectureService.toAuditXml(lectureBlock); + lectureService.auditLog(LectureBlockAuditLog.Action.closeLectureBlock, before, after, null, lectureBlock, null, lectureBlock.getEntry(), null, getIdentity()); + ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LECTURE_BLOCK_ROLL_CALL_CLOSED, getClass(), CoreLoggingResourceable.wrap(lectureBlock, OlatResourceableType.lectureBlock, lectureBlock.getTitle())); } - + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(quickSaveButton == source) { + doQuickSave(ureq); + } + super.formInnerEvent(ureq, source, event); + } + @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; @@ -228,10 +229,12 @@ public class CloseRollCallConfirmationController extends FormBasicController { allOk &= false; } - effectiveLecturesEl.clearError(); - if(!effectiveLecturesEl.isOneSelected()) { - effectiveLecturesEl.setErrorKey("form.legende.mandatory", null); - allOk &= false; + if(effectiveLecturesEl != null) { + effectiveLecturesEl.clearError(); + if(!effectiveLecturesEl.isOneSelected()) { + effectiveLecturesEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } } return allOk & super.validateFormLogic(ureq); @@ -285,4 +288,43 @@ public class CloseRollCallConfirmationController extends FormBasicController { protected void formCancelled(UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); } + + private void doQuickSave(UserRequest ureq) { + String before = lectureService.toAuditXml(lectureBlock); + commitLectureBlocks(); + lectureBlock = lectureService.save(lectureBlock, null); + lectureService.recalculateSummary(lectureBlock.getEntry()); + fireEvent(ureq, Event.DONE_EVENT); + + String after = lectureService.toAuditXml(lectureBlock); + lectureService.auditLog(LectureBlockAuditLog.Action.saveLectureBlock, before, after, null, lectureBlock, null, lectureBlock.getEntry(), null, getIdentity()); + } + + private void commitLectureBlocks() { + lectureBlock.setComment(blockCommentEl.getValue()); + + int effectiveLectures = lectureBlock.getPlannedLecturesNumber(); + if(effectiveLecturesEl != null) { + try { + String selectedKey = effectiveLecturesEl.getSelectedKey(); + effectiveLectures = Integer.parseInt(selectedKey); + } catch(Exception ex) { + logError("", ex); + } + } + lectureBlock.setEffectiveLecturesNumber(effectiveLectures); + Date effectiveEndDate = getEffectiveEndDate(); + if(effectiveEndDate == null) { + lectureBlock.setReasonEffectiveEnd(null); + } else { + lectureBlock.setEffectiveEndDate(effectiveEndDate); + if("-".equals(effectiveEndReasonEl.getSelectedKey())) { + lectureBlock.setReasonEffectiveEnd(null); + } else { + Long reasonKey = new Long(effectiveEndReasonEl.getSelectedKey()); + Reason selectedReason = lectureService.getReason(reasonKey); + lectureBlock.setReasonEffectiveEnd(selectedReason); + } + } + } } diff --git a/src/main/java/org/olat/modules/lecture/ui/ConfigurationHelper.java b/src/main/java/org/olat/modules/lecture/ui/ConfigurationHelper.java index 47c40cab5404d3ccb17910984db7206692d60290..2128bf0502eba598297c9b05ad09c4c8d9e241fa 100644 --- a/src/main/java/org/olat/modules/lecture/ui/ConfigurationHelper.java +++ b/src/main/java/org/olat/modules/lecture/ui/ConfigurationHelper.java @@ -30,10 +30,11 @@ import org.olat.modules.lecture.RepositoryEntryLectureConfiguration; * */ public class ConfigurationHelper { - + public static boolean isRollCallEnabled(RepositoryEntryLectureConfiguration lectureConfig, LectureModule lectureModule) { return (lectureConfig != null && lectureConfig.isOverrideModuleDefault() && lectureConfig.getRollCallEnabled() != null && lectureConfig.getRollCallEnabled().booleanValue()) - || ((lectureConfig == null || !lectureConfig.isOverrideModuleDefault()) && lectureModule.isRollCallDefaultEnabled()); + || ((lectureConfig == null || !lectureConfig.isOverrideModuleDefault()) && lectureModule.isRollCallDefaultEnabled()) + || (lectureModule.isCanOverrideStandardConfiguration() && (lectureConfig == null || lectureConfig.getRollCallEnabled() == null) && lectureModule.isRollCallDefaultEnabled()); } public static boolean isSyncTeacherCalendarEnabled(RepositoryEntryLectureConfiguration lectureConfig, LectureModule lectureModule) { diff --git a/src/main/java/org/olat/modules/lecture/ui/EditLectureBlockController.java b/src/main/java/org/olat/modules/lecture/ui/EditLectureBlockController.java index 32b3f40b5356a4e5d5caf0ad1698c4e49e6158eb..75c8d2cfb0d9bf6af953581a720b423e7ff1eb3b 100644 --- a/src/main/java/org/olat/modules/lecture/ui/EditLectureBlockController.java +++ b/src/main/java/org/olat/modules/lecture/ui/EditLectureBlockController.java @@ -58,6 +58,7 @@ import org.olat.group.BusinessGroupOrder; import org.olat.group.BusinessGroupService; import org.olat.group.model.SearchBusinessGroupParams; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureBlockManagedFlag; import org.olat.modules.lecture.LectureBlockStatus; import org.olat.modules.lecture.LectureRollCallStatus; @@ -84,9 +85,10 @@ public class EditLectureBlockController extends FormBasicController { private TextElement descriptionEl; private TextElement preparationEl; private AutoCompleter locationEl; - private DateChooser startDateEl; + private DateChooser dateEl; private SingleSelection plannedLecturesEl; private TextElement endHourEl, endMinuteEl; + private TextElement startHourEl, startMinuteEl; private MultipleSelectionElement groupsEl, teacherEl, compulsoryEl; private RepositoryEntry entry; @@ -126,16 +128,20 @@ public class EditLectureBlockController extends FormBasicController { } initForm(ureq); + updateUI(); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + formLayout.setElementCssClass("o_sel_repo_edit_lecture_form"); + if(lectureBlock != null && StringHelper.containsNonWhitespace(lectureBlock.getManagedFlagsString())) { setFormWarning("form.managedflags.intro.short", null); } String title = lectureBlock == null ? null : lectureBlock.getTitle(); titleEl = uifactory.addTextElement("title", "lecture.title", 128, title, formLayout); + titleEl.setElementCssClass("o_sel_repo_lecture_title"); titleEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.title)); titleEl.setMandatory(true); @@ -162,6 +168,7 @@ public class EditLectureBlockController extends FormBasicController { boolean compulsory = lectureBlock == null ? true : lectureBlock.isCompulsory(); compulsoryEl = uifactory.addCheckboxesVertical("compulsory", "lecture.compulsory", formLayout, onKeys, onValues, 1); compulsoryEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.compulsory)); + compulsoryEl.addActionListener(FormEvent.ONCHANGE); if(compulsory) { compulsoryEl.select(onKeys[0], true); } @@ -175,9 +182,9 @@ public class EditLectureBlockController extends FormBasicController { teacherValues[i] = userManager.getUserDisplayName(coach); } teacherKeys[0] = "-"; - teacherValues[0] = "-"; - + teacherValues[0] = translate("no.teachers"); teacherEl = uifactory.addCheckboxesVertical("teacher", "lecture.teacher", formLayout, teacherKeys, teacherValues, 2); + teacherEl.setElementCssClass("o_sel_repo_lecture_teachers"); teacherEl.setMandatory(true); teacherEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.teachers)); @@ -227,28 +234,41 @@ public class EditLectureBlockController extends FormBasicController { String description = lectureBlock == null ? "" : lectureBlock.getDescription(); descriptionEl = uifactory.addTextAreaElement("lecture.descr", 4, 72, description, formLayout); + descriptionEl.setElementCssClass("o_sel_repo_lecture_description"); descriptionEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.description)); String preparation = lectureBlock == null ? "" : lectureBlock.getPreparation(); preparationEl = uifactory.addTextAreaElement("lecture.preparation", 4, 72, preparation, formLayout); + preparationEl.setElementCssClass("o_sel_repo_lecture_preparation"); preparationEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.preparation)); String location = lectureBlock == null ? "" : lectureBlock.getLocation(); locationEl = uifactory.addTextElementWithAutoCompleter("location", "lecture.location", 128, location, formLayout); + locationEl.setElementCssClass("o_sel_repo_lecture_location"); locationEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.location)); locationEl.setListProvider(new LocationListProvider(), ureq.getUserSession()); locationEl.setMinLength(1); Date startDate = lectureBlock == null ? null : lectureBlock.getStartDate(); - startDateEl = uifactory.addDateChooser("lecture.start", startDate, formLayout); - startDateEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates)); - startDateEl.setDomReplacementWrapperRequired(false); - startDateEl.setDateChooserTimeEnabled(true); - startDateEl.setMandatory(true); + dateEl = uifactory.addDateChooser("lecture.date", startDate, formLayout); + dateEl.setElementCssClass("o_sel_repo_lecture_date"); + dateEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates)); + dateEl.setDomReplacementWrapperRequired(false); + dateEl.setMandatory(true); String datePage = velocity_root + "/date_start_end.html"; FormLayoutContainer dateCont = FormLayoutContainer.createCustomFormLayout("start_end", getTranslator(), datePage); - dateCont.setLabel("lecture.end", null); + dateCont.setLabel("lecture.time", null); formLayout.add(dateCont); + startHourEl = uifactory.addTextElement("lecture.start.hour", null, 2, "", dateCont); + startHourEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates)); + startHourEl.setDomReplacementWrapperRequired(false); + startHourEl.setDisplaySize(2); + startHourEl.setMandatory(true); + startMinuteEl = uifactory.addTextElement("lecture.start.minute", null, 2, "", dateCont); + startMinuteEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates)); + startMinuteEl.setDomReplacementWrapperRequired(false); + startMinuteEl.setDisplaySize(2); + endHourEl = uifactory.addTextElement("lecture.end.hour", null, 2, "", dateCont); endHourEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates)); endHourEl.setDomReplacementWrapperRequired(false); @@ -258,17 +278,23 @@ public class EditLectureBlockController extends FormBasicController { endMinuteEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates)); endMinuteEl.setDomReplacementWrapperRequired(false); endMinuteEl.setDisplaySize(2); - - if(lectureBlock != null && lectureBlock.getEndDate() != null) { + + if(lectureBlock != null) { Calendar cal = Calendar.getInstance(); - cal.setTime(lectureBlock.getEndDate()); - int hour = cal.get(Calendar.HOUR_OF_DAY); - int minute = cal.get(Calendar.MINUTE); - endHourEl.setValue(Integer.toString(hour)); - endMinuteEl.setValue(Integer.toString(minute)); - } else { - endHourEl.setValue("00"); - endMinuteEl.setValue("00"); + if(lectureBlock.getStartDate() != null) { + cal.setTime(lectureBlock.getStartDate()); + int hour = cal.get(Calendar.HOUR_OF_DAY); + int minute = cal.get(Calendar.MINUTE); + startHourEl.setValue(Integer.toString(hour)); + startMinuteEl.setValue(formatMinute(minute)); + } + if(lectureBlock.getEndDate() != null) { + cal.setTime(lectureBlock.getEndDate()); + int hour = cal.get(Calendar.HOUR_OF_DAY); + int minute = cal.get(Calendar.MINUTE); + endHourEl.setValue(Integer.toString(hour)); + endMinuteEl.setValue(formatMinute(minute)); + } } FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); @@ -276,6 +302,24 @@ public class EditLectureBlockController extends FormBasicController { uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); uifactory.addFormSubmitButton("save", buttonsCont); } + + private String formatMinute(int minute) { + if(minute < 0) { + return ""; + } + if(minute < 10) { + return "0" + minute; + } + return Integer.toString(minute); + } + + private void updateUI() { + if(compulsoryEl.isAtLeastSelected(1)) { + setFormWarning(null); + } else { + setFormWarning("warning.edit.lecture"); + } + } @Override protected void doDispose() { @@ -310,12 +354,14 @@ public class EditLectureBlockController extends FormBasicController { allOk &= false; } - startDateEl.clearError(); - if(startDateEl.getDate() == null) { - startDateEl.setErrorKey("form.legende.mandatory", null); + dateEl.clearError(); + if(dateEl.getDate() == null) { + dateEl.setErrorKey("form.legende.mandatory", null); allOk &= false; } - + + allOk &= validateInt(startHourEl, 24); + allOk &= validateInt(startMinuteEl, 60); allOk &= validateInt(endHourEl, 24); allOk &= validateInt(endMinuteEl, 60); return allOk & super.validateFormLogic(ureq); @@ -346,31 +392,41 @@ public class EditLectureBlockController extends FormBasicController { @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(compulsoryEl == source) { + updateUI(); + } super.formInnerEvent(ureq, source, event); } @Override protected void formOK(UserRequest ureq) { boolean create = false; - StringBuilder audit = new StringBuilder(); int currentPlannedLectures = -1; + + String beforeXml; + LectureBlockAuditLog.Action action; + StringBuilder audit = new StringBuilder(); if(lectureBlock == null) { - audit.append("Create;"); + beforeXml = null; + action = LectureBlockAuditLog.Action.createLectureBlock; lectureBlock = lectureService.createLectureBlock(entry); create = true; } else { + beforeXml = lectureService.toAuditXml(lectureBlock); + action = LectureBlockAuditLog.Action.createLectureBlock; currentPlannedLectures = lectureBlock.getPlannedLecturesNumber(); - audit.append("Update;"); } lectureBlock.setTitle(titleEl.getValue()); lectureBlock.setCompulsory(compulsoryEl.isAtLeastSelected(1)); lectureBlock.setDescription(descriptionEl.getValue()); lectureBlock.setPreparation(preparationEl.getValue()); lectureBlock.setLocation(locationEl.getValue()); - lectureBlock.setStartDate(startDateEl.getDate()); Calendar cal = Calendar.getInstance(); - cal.setTime(startDateEl.getDate()); + cal.setTime(dateEl.getDate()); + cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(startHourEl.getValue())); + cal.set(Calendar.MINUTE, Integer.parseInt(startMinuteEl.getValue())); + lectureBlock.setStartDate(cal.getTime()); cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(endHourEl.getValue())); cal.set(Calendar.MINUTE, Integer.parseInt(endMinuteEl.getValue())); lectureBlock.setEndDate(cal.getTime()); @@ -425,7 +481,9 @@ public class EditLectureBlockController extends FormBasicController { } } } - + + String afterxml = lectureService.toAuditXml(lectureBlock); + lectureService.auditLog(action, beforeXml, afterxml, audit.toString(), lectureBlock, null, entry, null, getIdentity()); dbInstance.commit(); if(currentPlannedLectures >= 0) { lectureService.adaptRollCalls(lectureBlock); @@ -434,7 +492,6 @@ public class EditLectureBlockController extends FormBasicController { lectureService.syncCalendars(lectureBlock); fireEvent(ureq, Event.DONE_EVENT); - lectureService.appendToLectureBlockLog(lectureBlock, getIdentity(), null, audit.toString()); if(create) { ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LECTURE_BLOCK_CREATED, getClass(), CoreLoggingResourceable.wrap(lectureBlock, OlatResourceableType.lectureBlock, lectureBlock.getTitle())); diff --git a/src/main/java/org/olat/modules/lecture/ui/EditParticipantSummaryController.java b/src/main/java/org/olat/modules/lecture/ui/EditParticipantSummaryController.java index 5b64ca6b9362e8977abf678bd81f1f4bd469e106..65063baa1b50b6fa2a55187682dfe46de32c440f 100644 --- a/src/main/java/org/olat/modules/lecture/ui/EditParticipantSummaryController.java +++ b/src/main/java/org/olat/modules/lecture/ui/EditParticipantSummaryController.java @@ -83,7 +83,7 @@ public class EditParticipantSummaryController extends FormBasicController { long cRate = Math.round(participantSummary.getRequiredAttendanceRate().doubleValue() * 100.0d); customRate = Long.toString(cRate); } - rateEl = uifactory.addTextElement("participant.rate", "participant.rate", 4, customRate, formLayout); + rateEl = uifactory.addTextElement("participant.rate.edit", "participant.rate.edit", 4, customRate, formLayout); rateEl.setVisible(rateEnabled); Date firstAdmission = participantSummary.getFirstAdmissionDate(); @@ -92,7 +92,9 @@ public class EditParticipantSummaryController extends FormBasicController { FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); formLayout.add(buttonsCont); uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl()); - removeCustomRateButton = uifactory.addFormLink("remove.custom.rate", "remove.custom.rate", null, buttonsCont, Link.BUTTON); + if(rateEnabled) { + removeCustomRateButton = uifactory.addFormLink("remove.custom.rate", "remove.custom.rate", null, buttonsCont, Link.BUTTON); + } uifactory.addFormSubmitButton("save", buttonsCont); } @@ -109,8 +111,9 @@ public class EditParticipantSummaryController extends FormBasicController { if(StringHelper.containsNonWhitespace(rateEl.getValue())) { try { int val = Integer.parseInt(rateEl.getValue()); - if(val < 0 && val > 100) { + if(val < 0 || val > 100) { rateEl.setErrorKey("error.integer.between", new String[] {"0", "100"}); + allOk &= false; } } catch (NumberFormatException e) { rateEl.setErrorKey("form.error.nointeger", null); diff --git a/src/main/java/org/olat/modules/lecture/ui/LectureBlockAndRollCallRow.java b/src/main/java/org/olat/modules/lecture/ui/LectureBlockAndRollCallRow.java new file mode 100644 index 0000000000000000000000000000000000000000..a2a969e2728a1f84e5c03558d5e0bc27dd3de2bc --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/LectureBlockAndRollCallRow.java @@ -0,0 +1,51 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui; + +import org.olat.core.gui.components.form.flexible.elements.FormLink; +import org.olat.modules.lecture.model.LectureBlockAndRollCall; + +/** + * + * Initial date: 10 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LectureBlockAndRollCallRow { + + private final LectureBlockAndRollCall row; + private FormLink appealButton; + + public LectureBlockAndRollCallRow(LectureBlockAndRollCall row) { + this.row = row; + } + + public LectureBlockAndRollCall getRow() { + return row; + } + + public FormLink getAppealButton() { + return appealButton; + } + + public void setAppealButton(FormLink appealButton) { + this.appealButton = appealButton; + } +} diff --git a/src/main/java/org/olat/modules/lecture/ui/LectureListRepositoryController.java b/src/main/java/org/olat/modules/lecture/ui/LectureListRepositoryController.java index 2c28fa96ac5655d415aaf5443f7a48ac13c3b5ea..a25369373657dcc2d9de0e64669175286fc2ee44 100644 --- a/src/main/java/org/olat/modules/lecture/ui/LectureListRepositoryController.java +++ b/src/main/java/org/olat/modules/lecture/ui/LectureListRepositoryController.java @@ -58,11 +58,13 @@ import org.olat.core.logging.activity.OlatResourceableType; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.StringHelper; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureBlockManagedFlag; import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.model.LectureBlockRow; import org.olat.modules.lecture.model.LectureBlockWithTeachers; import org.olat.modules.lecture.ui.LectureListRepositoryDataModel.BlockCols; +import org.olat.modules.lecture.ui.export.LectureBlockAuditLogExport; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryManagedFlag; import org.olat.user.UserManager; @@ -111,6 +113,7 @@ public class LectureListRepositoryController extends FormBasicController { if(!lectureManagementManaged) { addLectureButton = uifactory.addFormLink("add.lecture", formLayout, Link.BUTTON); addLectureButton.setIconLeftCSS("o_icon o_icon_add"); + addLectureButton.setElementCssClass("o_sel_repo_add_lecture"); deleteLecturesButton = uifactory.addFormLink("delete", formLayout, Link.BUTTON); } @@ -144,11 +147,12 @@ public class LectureListRepositoryController extends FormBasicController { tableEl.setExportEnabled(true); tableEl.setMultiSelect(true); tableEl.setSelectAllEnable(true); + tableEl.setEmtpyTableMessageKey("empty.table.lectures.blocks.admin"); FlexiTableSortOptions options = new FlexiTableSortOptions(); options.setDefaultOrderBy(new SortKey(BlockCols.date.name(), false)); tableEl.setSortSettings(options); - //TODO absence tableEl.setAndLoadPersistedPreferences(ureq, "repo-lecture-block-list"); + tableEl.setAndLoadPersistedPreferences(ureq, "repo-lecture-block-list"); } private void loadModel() { @@ -174,6 +178,8 @@ public class LectureListRepositoryController extends FormBasicController { } tableModel.setObjects(rows); tableEl.reset(true, true, true); + + deleteLecturesButton.setVisible(rows.size() > 0); } @Override @@ -347,6 +353,13 @@ public class LectureListRepositoryController extends FormBasicController { showInfo("lecture.deleted"); } + private void doExportLog(UserRequest ureq, LectureBlockRow row) { + LectureBlock lectureBlock = lectureService.getLectureBlock(row); + List<LectureBlockAuditLog> auditLog = lectureService.getAuditLog(row); + LectureBlockAuditLogExport export = new LectureBlockAuditLogExport(entry, lectureBlock, auditLog, getTranslator()); + ureq.getDispatchResult().setResultingMediaResource(export); + } + private void doOpenTools(UserRequest ureq, LectureBlockRow row, FormLink link) { removeAsListenerAndDispose(toolsCtrl); removeAsListenerAndDispose(toolsCalloutCtrl); @@ -362,7 +375,7 @@ public class LectureListRepositoryController extends FormBasicController { private class ToolsController extends BasicController { - private Link deleteLink, copyLink; + private Link deleteLink, copyLink, logLink; private final LectureBlockRow row; @@ -378,6 +391,8 @@ public class LectureListRepositoryController extends FormBasicController { deleteLink = LinkFactory.createLink("delete", "delete", getTranslator(), mainVC, this, Link.LINK); deleteLink.setIconLeftCSS("o_icon o_icon-fw o_icon_delete_item"); } + logLink = LinkFactory.createLink("log", "log", getTranslator(), mainVC, this, Link.LINK); + logLink.setIconLeftCSS("o_icon o_icon-fw o_icon_log"); putInitialPanel(mainVC); } @@ -393,6 +408,8 @@ public class LectureListRepositoryController extends FormBasicController { doCopy(row); } else if(deleteLink == source) { doConfirmDelete(ureq, row); + } else if(logLink == source) { + doExportLog(ureq, row); } } } diff --git a/src/main/java/org/olat/modules/lecture/ui/LectureRepositoryAdminController.java b/src/main/java/org/olat/modules/lecture/ui/LectureRepositoryAdminController.java index 2cb6ef380918021a0f06fae0a1c13b5fa76175fe..1a2dc66150245f1d7cf713625935f6523b174bf0 100644 --- a/src/main/java/org/olat/modules/lecture/ui/LectureRepositoryAdminController.java +++ b/src/main/java/org/olat/modules/lecture/ui/LectureRepositoryAdminController.java @@ -19,6 +19,8 @@ */ package org.olat.modules.lecture.ui; +import java.util.List; + import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; @@ -26,12 +28,25 @@ import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.segmentedview.SegmentViewComponent; import org.olat.core.gui.components.segmentedview.SegmentViewEvent; import org.olat.core.gui.components.segmentedview.SegmentViewFactory; +import org.olat.core.gui.components.stack.TooledController; +import org.olat.core.gui.components.stack.TooledStackedPanel; +import org.olat.core.gui.components.stack.TooledStackedPanel.Align; 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.controller.BasicController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.id.OLATResourceable; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.resource.OresHelper; +import org.olat.modules.lecture.LectureBlockAuditLog; +import org.olat.modules.lecture.LectureService; +import org.olat.modules.lecture.ui.export.LecturesBlocksEntryExport; +import org.olat.modules.lecture.ui.export.RepositoryEntryAuditLogExport; import org.olat.repository.RepositoryEntry; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -39,10 +54,12 @@ import org.olat.repository.RepositoryEntry; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class LectureRepositoryAdminController extends BasicController { +public class LectureRepositoryAdminController extends BasicController implements TooledController, Activateable2 { + private Link archiveLink, logLink; private final VelocityContainer mainVC; private final SegmentViewComponent segmentView; + private final TooledStackedPanel stackPanel; private final Link lecturesLink, settingsLink, participantsLink; private LectureListRepositoryController lecturesCtrl; @@ -52,9 +69,14 @@ public class LectureRepositoryAdminController extends BasicController { private RepositoryEntry entry; private boolean configurationChanges = false; - public LectureRepositoryAdminController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) { + @Autowired + private LectureService lectureService; + + public LectureRepositoryAdminController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, + RepositoryEntry entry) { super(ureq, wControl); this.entry = entry; + this.stackPanel = stackPanel; mainVC = createVelocityContainer("admin_repository"); @@ -65,7 +87,8 @@ public class LectureRepositoryAdminController extends BasicController { participantsLink = LinkFactory.createLink("repo.participants", mainVC, this); settingsLink = LinkFactory.createLink("repo.settings", mainVC, this); - settingsCtrl = new LectureRepositorySettingsController(ureq, getWindowControl(), entry); + WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType("Settings"), null); + settingsCtrl = new LectureRepositorySettingsController(ureq, swControl, entry); listenTo(settingsCtrl); if(settingsCtrl.isLectureEnabled()) { @@ -73,7 +96,7 @@ public class LectureRepositoryAdminController extends BasicController { segmentView.addSegment(participantsLink, false); doOpenLectures(ureq); } else { - doOpenSettings(); + doOpenSettings(ureq); } segmentView.addSegment(settingsLink, !settingsCtrl.isLectureEnabled()); @@ -93,6 +116,36 @@ public class LectureRepositoryAdminController extends BasicController { // } + @Override + public void initTools() { + archiveLink = LinkFactory.createToolLink("archive.entry", translate("archive.entry"), this); + archiveLink.setIconLeftCSS("o_icon o_icon_archive_tool"); + archiveLink.setVisible(settingsCtrl.isLectureEnabled()); + stackPanel.addTool(archiveLink, Align.right); + + logLink = LinkFactory.createToolLink("log", translate("log"), this); + logLink.setIconLeftCSS("o_icon o_icon_log"); + logLink.setVisible(settingsCtrl.isLectureEnabled()); + stackPanel.addTool(logLink, Align.right); + } + + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + String name = entries.get(0).getOLATResourceable().getResourceableTypeName(); + if("LectureBlocks".equalsIgnoreCase(name)) { + doOpenLectures(ureq); + segmentView.select(lecturesLink); + } else if("Participants".equalsIgnoreCase(name)) { + doOpenParticipants(ureq); + segmentView.select(participantsLink); + } else if("Settings".equalsIgnoreCase(name)) { + doOpenSettings(ureq); + segmentView.select(settingsLink); + } + } + @Override protected void event(UserRequest ureq, Component source, Event event) { if(source == segmentView) { @@ -103,11 +156,15 @@ public class LectureRepositoryAdminController extends BasicController { if (clickedLink == lecturesLink) { doOpenLectures(ureq); } else if (clickedLink == settingsLink){ - doOpenSettings(); + doOpenSettings(ureq); } else if(clickedLink == participantsLink) { doOpenParticipants(ureq); } } + } else if(archiveLink == source) { + doExportArchive(ureq); + } else if(logLink == source) { + doExportLog(ureq); } } @@ -139,21 +196,41 @@ public class LectureRepositoryAdminController extends BasicController { private void doOpenLectures(UserRequest ureq) { if(lecturesCtrl == null) { - lecturesCtrl = new LectureListRepositoryController(ureq, getWindowControl(), entry); + OLATResourceable ores = OresHelper.createOLATResourceableType("LectureBlocks"); + WindowControl swControl = addToHistory(ureq, ores, null); + lecturesCtrl = new LectureListRepositoryController(ureq, swControl, entry); listenTo(lecturesCtrl); + } else { + addToHistory(ureq, lecturesCtrl); } mainVC.put("segmentCmp", lecturesCtrl.getInitialComponent()); } - private void doOpenSettings() { + private void doOpenSettings(UserRequest ureq) { mainVC.put("segmentCmp", settingsCtrl.getInitialComponent()); + addToHistory(ureq, settingsCtrl); } private void doOpenParticipants(UserRequest ureq) { if(participantsCtrl == null) { - participantsCtrl = new ParticipantListRepositoryController(ureq, getWindowControl(), entry, false, true); + OLATResourceable ores = OresHelper.createOLATResourceableType("Participants"); + WindowControl swControl = addToHistory(ureq, ores, null); + participantsCtrl = new ParticipantListRepositoryController(ureq, swControl, entry, false, true); listenTo(participantsCtrl); + } else { + addToHistory(ureq, participantsCtrl); } mainVC.put("segmentCmp", participantsCtrl.getInitialComponent()); } + + private void doExportArchive(UserRequest ureq) { + LecturesBlocksEntryExport archive = new LecturesBlocksEntryExport(entry, getTranslator()); + ureq.getDispatchResult().setResultingMediaResource(archive); + } + + private void doExportLog(UserRequest ureq) { + List<LectureBlockAuditLog> auditLog = lectureService.getAuditLog(entry); + RepositoryEntryAuditLogExport archive = new RepositoryEntryAuditLogExport(entry, auditLog, getTranslator()); + ureq.getDispatchResult().setResultingMediaResource(archive); + } } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/LectureRepositorySettingsController.java b/src/main/java/org/olat/modules/lecture/ui/LectureRepositorySettingsController.java index e7a2c4bc86585cc1ad00c4a18268964952b68a5e..7a421c7e40f38ec867326a65d9785bb4d8ac3e56 100644 --- a/src/main/java/org/olat/modules/lecture/ui/LectureRepositorySettingsController.java +++ b/src/main/java/org/olat/modules/lecture/ui/LectureRepositorySettingsController.java @@ -93,6 +93,8 @@ public class LectureRepositorySettingsController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("lecture.course.admin.title"); + setFormContextHelp("Lectures and absences"); + formLayout.setElementCssClass("o_sel_repo_lecture_settings_form"); if(lectureConfigManaged) { String flags = entry.getManagedFlagsString() == null ? "" : entry.getManagedFlagsString().trim(); String flagsFormatted = null; @@ -118,6 +120,7 @@ public class LectureRepositorySettingsController extends FormBasicController { String[] onValues = new String[] { translate("on") }; enableEl = uifactory.addCheckboxesHorizontal("lecture.admin.enabled", formLayout, onKeys, onValues); enableEl.setEnabled(!lectureConfigManaged); + enableEl.setElementCssClass("o_sel_repo_lecture_enable"); enableEl.addActionListener(FormEvent.ONCHANGE); if(lectureConfig.isLectureEnabled()) { enableEl.select(onKeys[0], true); @@ -126,6 +129,7 @@ public class LectureRepositorySettingsController extends FormBasicController { String[] overrideValues = new String[]{ translate("config.override.yes"), translate("config.override.no") }; overrideEl = uifactory.addRadiosHorizontal("config.override", formLayout, overrideKeys, overrideValues); overrideEl.setEnabled(!lectureConfigManaged); + overrideEl.setElementCssClass("o_sel_repo_lecture_override"); overrideEl.addActionListener(FormEvent.ONCHANGE); if(lectureConfig.isOverrideModuleDefault()) { overrideEl.select(overrideKeys[0], true);//yes diff --git a/src/main/java/org/olat/modules/lecture/ui/LectureSettingsAdminController.java b/src/main/java/org/olat/modules/lecture/ui/LectureSettingsAdminController.java index e5efa12f379bb340f7c7f57f5361af22d31f104d..28f20ddf3b2789616f096d2c8af3929712d656e0 100644 --- a/src/main/java/org/olat/modules/lecture/ui/LectureSettingsAdminController.java +++ b/src/main/java/org/olat/modules/lecture/ui/LectureSettingsAdminController.java @@ -54,12 +54,12 @@ public class LectureSettingsAdminController extends FormBasicController { private TextElement attendanceRateEl, appealPeriodEl, reminderPeriodEl, autoClosePeriodEl; private MultipleSelectionElement enableEl, calculateAttendanceRateEnableEl, - appealAbsenceEnableEl, statusEnabledEl, + appealAbsenceEnableEl, statusEnabledEl, partiallyDoneEnabledEl, authorizedAbsenceEnableEl, absenceDefaultAuthorizedEl, countAuthorizedAbsenceAsAttendantEl, syncTeachersCalendarEnableEl, syncCourseCalendarEnableEl, teacherCanAuthorizeAbsenceEl, reminderEnableEl, rollCallEnableEl; - + private FormLayoutContainer globalCont; @Autowired private LectureModule lectureModule; @@ -69,6 +69,8 @@ public class LectureSettingsAdminController extends FormBasicController { public LectureSettingsAdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl, "admin_settings"); initForm(ureq); + initializeValues(); + updateUI(); } @Override @@ -76,151 +78,192 @@ public class LectureSettingsAdminController extends FormBasicController { // configuration which can be overriden in course FormLayoutContainer courseCont = FormLayoutContainer.createDefaultFormLayout("override_course", getTranslator()); courseCont.setFormTitle(translate("lecture.admin.course.override.title")); + courseCont.setFormContextHelp("Lecture and roll call management"); courseCont.setRootForm(mainForm); formLayout.add("course", courseCont); String[] onValues = new String[] { translate("on") }; enableEl = uifactory.addCheckboxesHorizontal("lecture.admin.enabled", courseCont, onKeys, onValues); enableEl.addActionListener(FormEvent.ONCHANGE); + + String[] yesNoValues = new String[]{ translate("yes"), translate("no") }; + canOverrideStandardConfigEl = uifactory.addRadiosHorizontal("lecture.can.override.standard.configuration", courseCont, yesNoKeys, yesNoValues); + canOverrideStandardConfigEl.addActionListener(FormEvent.ONCHANGE); + + // roll call enabled + rollCallEnableEl = uifactory.addCheckboxesHorizontal("lecture.rollcall.default.enabled", courseCont, onKeys, onValues); + rollCallEnableEl.addActionListener(FormEvent.ONCHANGE); + + // calculate attendance + calculateAttendanceRateEnableEl = uifactory.addCheckboxesHorizontal("lecture.calculate.attendance.rate.default.enabled", courseCont, onKeys, onValues); + + attendanceRateEl = uifactory.addTextElement("lecture.attendance.rate.default", "lecture.attendance.rate.default", 2, "", courseCont); + attendanceRateEl.setMandatory(true); + attendanceRateEl.setDisplaySize(2); + + // sync calendars + syncTeachersCalendarEnableEl = uifactory.addCheckboxesHorizontal("sync.teachers.calendar.enabled", courseCont, onKeys, onValues); + syncCourseCalendarEnableEl = uifactory.addCheckboxesHorizontal("sync.course.calendar.enabled", courseCont, onKeys, onValues); + + //global configuration + globalCont = FormLayoutContainer.createDefaultFormLayout("global", getTranslator()); + globalCont.setFormTitle(translate("lecture.admin.global.title")); + globalCont.setRootForm(mainForm); + formLayout.add("global", globalCont); + + partiallyDoneEnabledEl = uifactory.addCheckboxesVertical("lecture.status.partially.done.enabled", globalCont, onKeys, onValues, 1); + + String[] statusKeys = new String[]{ LectureBlockStatus.cancelled.name() }; + String[] statusValues = new String[]{ translate(LectureBlockStatus.cancelled.name()) }; + statusEnabledEl = uifactory.addCheckboxesVertical("lecture.status.enabled", globalCont, statusKeys, statusValues, 1); + + // reminder enabled + reminderEnableEl = uifactory.addCheckboxesHorizontal("lecture.reminder.enabled", globalCont, onKeys, onValues); + reminderEnableEl.addActionListener(FormEvent.ONCHANGE); + + reminderPeriodEl = uifactory.addTextElement("lecture.reminder.period", "lecture.reminder.period", 16, "", globalCont); + reminderPeriodEl.setMandatory(true); + + // auto close period + autoClosePeriodEl = uifactory.addTextElement("lecture.auto.close.period", "lecture.auto.close.period", 16, "", globalCont); + autoClosePeriodEl.setMandatory(true); + + authorizedAbsenceEnableEl = uifactory.addCheckboxesHorizontal("lecture.authorized.absence.enabled", globalCont, onKeys, onValues); + authorizedAbsenceEnableEl.addActionListener(FormEvent.ONCHANGE); + countAuthorizedAbsenceAsAttendantEl = uifactory.addCheckboxesHorizontal("lecture.count.authorized.absence.attendant", globalCont, onKeys, onValues); + absenceDefaultAuthorizedEl = uifactory.addCheckboxesHorizontal("lecture.absence.default.authorized", globalCont, onKeys, onValues); + teacherCanAuthorizeAbsenceEl = uifactory.addCheckboxesHorizontal("lecture.teacher.can.authorize.absence", globalCont, onKeys, onValues); + + // appeal enabled + appealAbsenceEnableEl = uifactory.addCheckboxesHorizontal("lecture.appeal.absence.enabled", globalCont, onKeys, onValues); + appealAbsenceEnableEl.addActionListener(FormEvent.ONCHANGE); + appealPeriodEl = uifactory.addTextElement("lecture.appeal.absence.period", "lecture.appeal.absence.period", 16, "", globalCont); + appealPeriodEl.setMandatory(true); + + //buttons + FormLayoutContainer buttonsWrapperCont = FormLayoutContainer.createDefaultFormLayout("global", getTranslator()); + buttonsWrapperCont.setRootForm(mainForm); + formLayout.add("buttonsWrapper", buttonsWrapperCont); + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonsWrapperCont.add(buttonsCont); + uifactory.addFormSubmitButton("save", buttonsCont); + } + + private void initializeValues() { if(lectureModule.isEnabled()) { enableEl.select(onKeys[0], true); } - String[] yesNoValues = new String[]{ translate("yes"), translate("no") }; - canOverrideStandardConfigEl = uifactory.addRadiosHorizontal("lecture.can.override.standard.configuration", courseCont, yesNoKeys, yesNoValues); - canOverrideStandardConfigEl.addActionListener(FormEvent.ONCHANGE); if(lectureModule.isCanOverrideStandardConfiguration()) { canOverrideStandardConfigEl.select(yesNoKeys[0], true); } else { canOverrideStandardConfigEl.select(yesNoKeys[1], true); } - // roll call enabled - rollCallEnableEl = uifactory.addCheckboxesHorizontal("lecture.rollcall.default.enabled", courseCont, onKeys, onValues); - rollCallEnableEl.addActionListener(FormEvent.ONCHANGE); if(lectureModule.isRollCallDefaultEnabled()) { rollCallEnableEl.select(onKeys[0], true); + } else { + rollCallEnableEl.uncheckAll(); } - // calculate attendance - calculateAttendanceRateEnableEl = uifactory.addCheckboxesHorizontal("lecture.calculate.attendance.rate.default.enabled", courseCont, onKeys, onValues); if(lectureModule.isRollCallCalculateAttendanceRateDefaultEnabled()) { calculateAttendanceRateEnableEl.select(onKeys[0], true); + } else { + calculateAttendanceRateEnableEl.uncheckAll(); } + long attendanceRate = Math.round(lectureModule.getRequiredAttendanceRateDefault() * 100.0d); - String attendanceRateStr = Long.toString(attendanceRate); - attendanceRateEl = uifactory.addTextElement("lecture.attendance.rate.default", "lecture.attendance.rate.default", 2, attendanceRateStr, courseCont); - attendanceRateEl.setMandatory(true); - attendanceRateEl.setDisplaySize(2); - - // sync calendars - syncTeachersCalendarEnableEl = uifactory.addCheckboxesHorizontal("sync.teachers.calendar.enabled", courseCont, onKeys, onValues); + attendanceRateEl.setValue(Long.toString(attendanceRate)); + if(lectureModule.isTeacherCalendarSyncEnabledDefault()) { syncTeachersCalendarEnableEl.select(onKeys[0], true); + } else { + syncCourseCalendarEnableEl.uncheckAll(); } - syncCourseCalendarEnableEl = uifactory.addCheckboxesHorizontal("sync.course.calendar.enabled", courseCont, onKeys, onValues); if(lectureModule.isCourseCalendarSyncEnabledDefault()) { syncCourseCalendarEnableEl.select(onKeys[0], true); + } else { + syncCourseCalendarEnableEl.uncheckAll(); } - - //global configuration - FormLayoutContainer globalCont = FormLayoutContainer.createDefaultFormLayout("global", getTranslator()); - globalCont.setFormTitle(translate("lecture.admin.global.title")); - globalCont.setRootForm(mainForm); - formLayout.add("global", globalCont); - - String[] statusKeys = new String[]{ - LectureBlockStatus.partiallydone.name(), LectureBlockStatus.cancelled.name() - }; - String[] statusValues = new String[]{ - translate(LectureBlockStatus.partiallydone.name()), translate(LectureBlockStatus.cancelled.name()) - }; - statusEnabledEl = uifactory.addCheckboxesVertical("lecture.status.enabled", globalCont, statusKeys, statusValues, 1); + if(lectureModule.isStatusPartiallyDoneEnabled()) { - statusEnabledEl.select(LectureBlockStatus.partiallydone.name(), true); + partiallyDoneEnabledEl.select(onKeys[0], true); + } else { + partiallyDoneEnabledEl.uncheckAll(); } + if(lectureModule.isStatusCancelledEnabled()) { statusEnabledEl.select(LectureBlockStatus.cancelled.name(), true); + } else { + statusEnabledEl.uncheckAll(); } - - // reminder enabled - reminderEnableEl = uifactory.addCheckboxesHorizontal("lecture.reminder.enabled", globalCont, onKeys, onValues); - reminderEnableEl.addActionListener(FormEvent.ONCHANGE); + if(lectureModule.isRollCallReminderEnabled()) { reminderEnableEl.select(onKeys[0], true); + } else { + reminderEnableEl.uncheckAll(); } + String reminderPeriod = ""; if(lectureModule.getRollCallReminderPeriod() > 0) { reminderPeriod = Integer.toString(lectureModule.getRollCallReminderPeriod()); } - reminderPeriodEl = uifactory.addTextElement("lecture.reminder.period", "lecture.reminder.period", 16, reminderPeriod, globalCont); - reminderPeriodEl.setMandatory(true); - - // auto close period + reminderPeriodEl.setValue(reminderPeriod); + String autoClosePeriod = ""; if(lectureModule.getRollCallAutoClosePeriod() > 0) { autoClosePeriod = Integer.toString(lectureModule.getRollCallAutoClosePeriod()); } - autoClosePeriodEl = uifactory.addTextElement("lecture.auto.close.period", "lecture.auto.close.period", 16, autoClosePeriod, globalCont); - autoClosePeriodEl.setMandatory(true); - - authorizedAbsenceEnableEl = uifactory.addCheckboxesHorizontal("lecture.authorized.absence.enabled", globalCont, onKeys, onValues); - authorizedAbsenceEnableEl.addActionListener(FormEvent.ONCHANGE); + autoClosePeriodEl.setValue(autoClosePeriod); + if(lectureModule.isAuthorizedAbsenceEnabled()) { authorizedAbsenceEnableEl.select(onKeys[0], true); + } else { + authorizedAbsenceEnableEl.uncheckAll(); } - countAuthorizedAbsenceAsAttendantEl = uifactory.addCheckboxesHorizontal("lecture.count.authorized.absence.attendant", globalCont, onKeys, onValues); if(lectureModule.isCountAuthorizedAbsenceAsAttendant()) { countAuthorizedAbsenceAsAttendantEl.select(onKeys[0], true); + } else { + countAuthorizedAbsenceAsAttendantEl.uncheckAll(); } - absenceDefaultAuthorizedEl = uifactory.addCheckboxesHorizontal("lecture.absence.default.authorized", globalCont, onKeys, onValues); if(lectureModule.isAbsenceDefaultAuthorized()) { absenceDefaultAuthorizedEl.select(onKeys[0], true); + } else { + absenceDefaultAuthorizedEl.uncheckAll(); } - teacherCanAuthorizeAbsenceEl = uifactory.addCheckboxesHorizontal("lecture.teacher.can.authorize.absence", globalCont, onKeys, onValues); if(lectureModule.isTeacherCanAuthorizedAbsence()) { teacherCanAuthorizeAbsenceEl.select(onKeys[0], true); + } else { + teacherCanAuthorizeAbsenceEl.uncheckAll(); } - - // appeal enabled - appealAbsenceEnableEl = uifactory.addCheckboxesHorizontal("lecture.appeal.absence.enabled", globalCont, onKeys, onValues); - appealAbsenceEnableEl.addActionListener(FormEvent.ONCHANGE); if(lectureModule.isAbsenceAppealEnabled()) { appealAbsenceEnableEl.select(onKeys[0], true); + } else { + appealAbsenceEnableEl.uncheckAll(); } + String appealPeriod = ""; if(lectureModule.getAbsenceAppealPeriod() > 0) { appealPeriod = Integer.toString(lectureModule.getAbsenceAppealPeriod()); } - appealPeriodEl = uifactory.addTextElement("lecture.appeal.absence.period", "lecture.appeal.absence.period", 16, appealPeriod, globalCont); - appealPeriodEl.setMandatory(true); - - //buttons - FormLayoutContainer buttonsWrapperCont = FormLayoutContainer.createDefaultFormLayout("global", getTranslator()); - buttonsWrapperCont.setRootForm(mainForm); - formLayout.add("buttonsWrapper", buttonsWrapperCont); - FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); - buttonsWrapperCont.add(buttonsCont); - uifactory.addFormSubmitButton("save", buttonsCont); - updateUI(); - } - - @Override - protected void doDispose() { - // + appealPeriodEl.setValue(appealPeriod); } private void updateUI() { boolean enabled = enableEl.isAtLeastSelected(1); + canOverrideStandardConfigEl.setVisible(enabled); authorizedAbsenceEnableEl.setVisible(enabled); attendanceRateEl.setVisible(enabled); appealAbsenceEnableEl.setVisible(enabled); - authorizedAbsenceEnableEl.setVisible(enabled); reminderEnableEl.setVisible(enabled); syncTeachersCalendarEnableEl.setVisible(enabled); syncCourseCalendarEnableEl.setVisible(enabled); + + globalCont.setVisible(enabled); autoClosePeriodEl.setVisible(enabled); statusEnabledEl.setVisible(enabled); + partiallyDoneEnabledEl.setVisible(enabled); + absenceDefaultAuthorizedEl.setVisible(enabled); rollCallEnableEl.setVisible(enabled); calculateAttendanceRateEnableEl.setVisible(enabled); @@ -231,6 +274,12 @@ public class LectureSettingsAdminController extends FormBasicController { teacherCanAuthorizeAbsenceEl.setVisible(authorizedAbsenceEnableEl.isVisible() && authorizedAbsenceEnableEl.isAtLeastSelected(1)); } + @Override + protected void doDispose() { + // + } + + @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; @@ -292,8 +341,12 @@ public class LectureSettingsAdminController extends FormBasicController { @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { - if(enableEl == source || appealAbsenceEnableEl == source || reminderEnableEl == source - || authorizedAbsenceEnableEl == source) { + if(enableEl == source) { + if(enableEl.isAtLeastSelected(1)) { + initializeValues(); + } + updateUI(); + } else if(appealAbsenceEnableEl == source || reminderEnableEl == source || authorizedAbsenceEnableEl == source) { updateUI(); } super.formInnerEvent(ureq, source, event); @@ -301,13 +354,16 @@ public class LectureSettingsAdminController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { - lectureModule.setEnabled(enableEl.isAtLeastSelected(1)); - lectureModule.setCanOverrideStandardConfiguration(canOverrideStandardConfigEl.isSelected(0)); - if(enableEl.isAtLeastSelected(1)) { + boolean enabled = enableEl.isAtLeastSelected(1); + lectureModule.setEnabled(enabled); + + if(enabled) { + lectureModule.setCanOverrideStandardConfiguration(canOverrideStandardConfigEl.isSelected(0)); + //enabled user tool Set<String> availableTools = userToolsModule.getAvailableUserToolSet(); - if(!availableTools.contains("org.olat.home.HomeMainController:org.olat.modules.lecture.ui.ParticipantLecturesOverviewController")) { - availableTools.add("org.olat.home.HomeMainController:org.olat.modules.lecture.ui.ParticipantLecturesOverviewController"); + if(!availableTools.contains("org.olat.home.HomeMainController:org.olat.modules.lecture.ui.LecturesToolController")) { + availableTools.add("org.olat.home.HomeMainController:org.olat.modules.lecture.ui.LecturesToolController"); } StringBuilder aTools = new StringBuilder(); @@ -316,36 +372,43 @@ public class LectureSettingsAdminController extends FormBasicController { aTools.append(selectedKey); } userToolsModule.setAvailableUserTools(aTools.toString()); + + lectureModule.setRollCallDefaultEnabled(rollCallEnableEl.isAtLeastSelected(1)); + + int autoClosePeriod = Integer.parseInt(autoClosePeriodEl.getValue()); + lectureModule.setRollCallAutoClosePeriod(autoClosePeriod); + + lectureModule.setStatusPartiallyDoneEnabled(partiallyDoneEnabledEl.isAtLeastSelected(1)); + lectureModule.setStatusCancelledEnabled(statusEnabledEl.isAtLeastSelected(1)); + + boolean authorizedAbsenceenabled = authorizedAbsenceEnableEl.isAtLeastSelected(1); + lectureModule.setAuthorizedAbsenceEnabled(authorizedAbsenceEnableEl.isAtLeastSelected(1)); + lectureModule.setCountAuthorizedAbsenceAsAttendant(authorizedAbsenceenabled && countAuthorizedAbsenceAsAttendantEl.isAtLeastSelected(1)); + lectureModule.setTeacherCanAuthorizedAbsence(authorizedAbsenceenabled && teacherCanAuthorizeAbsenceEl.isAtLeastSelected(1)); + + lectureModule.setAbsenceAppealEnabled(appealAbsenceEnableEl.isAtLeastSelected(1)); + if(appealAbsenceEnableEl.isAtLeastSelected(1)) { + int period = Integer.parseInt(appealPeriodEl.getValue()); + lectureModule.setAbsenceAppealPeriod(period); + } + lectureModule.setAbsenceDefaultAuthorized(absenceDefaultAuthorizedEl.isAtLeastSelected(1)); + + + lectureModule.setRollCallReminderEnabled(reminderEnableEl.isAtLeastSelected(1)); + if(reminderEnableEl.isAtLeastSelected(1)) { + int period = Integer.parseInt(reminderPeriodEl.getValue()); + lectureModule.setRollCallReminderPeriod(period); + } + + lectureModule.setRollCallCalculateAttendanceRateDefaultEnabled(calculateAttendanceRateEnableEl.isAtLeastSelected(1)); + String attendanceRateInPercent = attendanceRateEl.getValue(); + if(StringHelper.containsNonWhitespace(attendanceRateInPercent)) { + double val = Double.parseDouble(attendanceRateInPercent) / 100.0d; + lectureModule.setRequiredAttendanceRateDefault(val); + } + + lectureModule.setTeacherCalendarSyncEnabledDefault(syncTeachersCalendarEnableEl.isAtLeastSelected(1)); + lectureModule.setCourseCalendarSyncEnabledDefault(syncCourseCalendarEnableEl.isAtLeastSelected(1)); } - - int autoClosePeriod = Integer.parseInt(autoClosePeriodEl.getValue()); - lectureModule.setRollCallAutoClosePeriod(autoClosePeriod); - - boolean authorizedAbsenceenabled = authorizedAbsenceEnableEl.isAtLeastSelected(1); - lectureModule.setAuthorizedAbsenceEnabled(authorizedAbsenceEnableEl.isAtLeastSelected(1)); - lectureModule.setCountAuthorizedAbsenceAsAttendant(authorizedAbsenceenabled && countAuthorizedAbsenceAsAttendantEl.isAtLeastSelected(1)); - lectureModule.setTeacherCanAuthorizedAbsence(authorizedAbsenceenabled && teacherCanAuthorizeAbsenceEl.isAtLeastSelected(1)); - - lectureModule.setAbsenceAppealEnabled(appealAbsenceEnableEl.isAtLeastSelected(1)); - if(appealAbsenceEnableEl.isAtLeastSelected(1)) { - int period = Integer.parseInt(appealPeriodEl.getValue()); - lectureModule.setAbsenceAppealPeriod(period); - } - - lectureModule.setRollCallReminderEnabled(reminderEnableEl.isAtLeastSelected(1)); - if(reminderEnableEl.isAtLeastSelected(1)) { - int period = Integer.parseInt(reminderPeriodEl.getValue()); - lectureModule.setRollCallReminderPeriod(period); - } - - lectureModule.setRollCallCalculateAttendanceRateDefaultEnabled(calculateAttendanceRateEnableEl.isAtLeastSelected(1)); - String attendanceRateInPercent = attendanceRateEl.getValue(); - if(StringHelper.containsNonWhitespace(attendanceRateInPercent)) { - double val = Double.parseDouble(attendanceRateInPercent) / 100.0d; - lectureModule.setRequiredAttendanceRateDefault(val); - } - - lectureModule.setTeacherCalendarSyncEnabledDefault(syncTeachersCalendarEnableEl.isAtLeastSelected(1)); - lectureModule.setCourseCalendarSyncEnabledDefault(syncCourseCalendarEnableEl.isAtLeastSelected(1)); } } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/LecturesToolController.java b/src/main/java/org/olat/modules/lecture/ui/LecturesToolController.java index 192449d87917699a03a2d9fb4e705f283a750219..4d3c785e8e41e1e40f3701fec44ec61c1e70a62c 100644 --- a/src/main/java/org/olat/modules/lecture/ui/LecturesToolController.java +++ b/src/main/java/org/olat/modules/lecture/ui/LecturesToolController.java @@ -19,6 +19,8 @@ */ package org.olat.modules.lecture.ui; +import java.util.List; + import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; @@ -28,10 +30,15 @@ import org.olat.core.gui.components.segmentedview.SegmentViewEvent; import org.olat.core.gui.components.segmentedview.SegmentViewFactory; import org.olat.core.gui.components.stack.BreadcrumbPanel; import org.olat.core.gui.components.stack.BreadcrumbPanelAware; +import org.olat.core.gui.components.stack.PopEvent; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.resource.OresHelper; /** * @@ -39,8 +46,9 @@ import org.olat.core.gui.control.controller.BasicController; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class LecturesToolController extends BasicController implements BreadcrumbPanelAware { +public class LecturesToolController extends BasicController implements BreadcrumbPanelAware, Activateable2 { + private BreadcrumbPanel stackPanel; private final VelocityContainer mainVC; private SegmentViewComponent segmentView; private Link teacherLink, participantLink; @@ -52,11 +60,13 @@ public class LecturesToolController extends BasicController implements Breadcrum super(ureq, wControl); mainVC = createVelocityContainer("user_tool"); - - teacherOverviewCtrl = new TeacherToolOverviewController(ureq, getWindowControl()); + + WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType("coach"), null); + teacherOverviewCtrl = new TeacherToolOverviewController(ureq, swControl); listenTo(teacherOverviewCtrl); boolean withTitle = teacherOverviewCtrl.getRowCount() == 0; - participantOverviewCtrl = new ParticipantLecturesOverviewController(ureq, getWindowControl(), withTitle); + WindowControl twControl = addToHistory(ureq, OresHelper.createOLATResourceableType("attendee"), null); + participantOverviewCtrl = new ParticipantLecturesOverviewController(ureq, twControl, withTitle); listenTo(participantOverviewCtrl); if(teacherOverviewCtrl.getRowCount() > 0 && participantOverviewCtrl.getRowCount() > 0) { @@ -65,21 +75,21 @@ public class LecturesToolController extends BasicController implements Breadcrum segmentView.addSegment(teacherLink, true); participantLink = LinkFactory.createLink("tool.participant", mainVC, this); segmentView.addSegment(participantLink, false); - mainVC.put("segmentCmp", teacherOverviewCtrl.getInitialComponent()); + doOpenTeacherView(ureq); } else if(teacherOverviewCtrl.getRowCount() > 0) { - mainVC.put("teacherView", teacherOverviewCtrl.getInitialComponent()); + doOpenTeacherView(ureq); } else if(participantOverviewCtrl.getRowCount() > 0) { - mainVC.put("participantView", participantOverviewCtrl.getInitialComponent()); - } else { - + doOpenParticipantView(ureq); } putInitialPanel(mainVC); } @Override public void setBreadcrumbPanel(BreadcrumbPanel stackPanel) { + this.stackPanel = stackPanel; participantOverviewCtrl.setBreadcrumbPanel(stackPanel); teacherOverviewCtrl.setBreadcrumbPanel(stackPanel); + stackPanel.addListener(this); } @Override @@ -87,6 +97,27 @@ public class LecturesToolController extends BasicController implements Breadcrum // } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + ContextEntry entry = entries.get(0); + String type = entry.getOLATResourceable().getResourceableTypeName(); + if("coach".equalsIgnoreCase(type)) { + if(segmentView != null) { + segmentView.select(teacherLink); + } + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + doOpenTeacherView(ureq).activate(ureq, subEntries, entry.getTransientState()); + } else if("attendee".equalsIgnoreCase(type)) { + if(segmentView != null) { + segmentView.select(participantLink); + } + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + doOpenParticipantView(ureq).activate(ureq, subEntries, entry.getTransientState()); + } + } + @Override protected void event(UserRequest ureq, Component source, Event event) { if(event instanceof SegmentViewEvent) { @@ -94,18 +125,33 @@ public class LecturesToolController extends BasicController implements Breadcrum String segmentCName = sve.getComponentName(); Component clickedLink = mainVC.getComponent(segmentCName); if (clickedLink == teacherLink) { - doOpenTeacherView(); + doOpenTeacherView(ureq); } else if (clickedLink == participantLink) { - doOpenParticipantView(); + doOpenParticipantView(ureq); + } + } else if(stackPanel == source) { + if(event instanceof PopEvent) { + PopEvent popEvent = (PopEvent)event; + if(popEvent.getController() instanceof TeacherRollCallController) { + addToHistory(ureq, teacherOverviewCtrl); + } else if(popEvent.getController() instanceof ParticipantLectureBlocksController) { + addToHistory(ureq, participantOverviewCtrl); + } } } } - private void doOpenTeacherView() { + private Activateable2 doOpenTeacherView(UserRequest ureq) { mainVC.put("segmentCmp", teacherOverviewCtrl.getInitialComponent()); + mainVC.put("teacherView", teacherOverviewCtrl.getInitialComponent()); + addToHistory(ureq, teacherOverviewCtrl); + return teacherOverviewCtrl; } - private void doOpenParticipantView() { + private Activateable2 doOpenParticipantView(UserRequest ureq) { mainVC.put("segmentCmp", participantOverviewCtrl.getInitialComponent()); + mainVC.put("participantView", participantOverviewCtrl.getInitialComponent()); + addToHistory(ureq, participantOverviewCtrl); + return participantOverviewCtrl; } } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksController.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksController.java index e3a3211b12c894bad3cef587d96687cf9aa42642..76ef2366ac7c8ad67e33ad1f4ac5120b05908320 100644 --- a/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksController.java +++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksController.java @@ -54,16 +54,19 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.creator.ControllerCreator; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.id.Identity; +import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.mail.ContactList; import org.olat.core.util.mail.ContactMessage; import org.olat.modules.co.ContactFormController; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockStatus; import org.olat.modules.lecture.LectureModule; import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.model.LectureBlockAndRollCall; import org.olat.modules.lecture.ui.ParticipantLectureBlocksDataModel.ParticipantCols; import org.olat.modules.lecture.ui.component.LectureBlockRollCallStatusCellRenderer; +import org.olat.modules.lecture.ui.component.LecturesCompulsoryRenderer; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; import org.olat.user.UserManager; @@ -84,11 +87,13 @@ public class ParticipantLectureBlocksController extends FormBasicController { private final RepositoryEntry entry; private final boolean appealEnabled; - private final AppealCallback appealCallback; private CloseableModalController cmc; private ContactFormController appealCtrl; + private int count = 0; + private final int appealOffset; + private final int appealPeriod; private final boolean withPrint; private final boolean withAppeal; private final Identity assessedIdentity; @@ -119,9 +124,8 @@ public class ParticipantLectureBlocksController extends FormBasicController { authorizedAbsenceEnabled = lectureModule.isAuthorizedAbsenceEnabled(); absenceDefaultAuthorized = lectureModule.isAbsenceDefaultAuthorized(); - int appealOffset = lectureModule.getRollCallAutoClosePeriod();//TODO absence or is it reminder period - int appealPeriod = lectureModule.getAbsenceAppealPeriod(); - appealCallback = new AppealCallback(appealEnabled, appealOffset, appealPeriod); + appealOffset = lectureModule.getRollCallAutoClosePeriod();//TODO absence or is it reminder period + appealPeriod = lectureModule.getAbsenceAppealPeriod(); initForm(ureq); loadModel(); } @@ -151,21 +155,24 @@ public class ParticipantLectureBlocksController extends FormBasicController { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.entry)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.lectureBlock)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.coach)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.plannedLectures)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.plannedLectures, new LecturesCompulsoryRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.attendedLectures)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.absentLectures)); if(authorizedAbsenceEnabled) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.unauthorizedAbsentLectures)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.authorizedAbsentLectures)); + } else { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.absentLectures)); } + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantCols.status, - new LectureBlockRollCallStatusCellRenderer(authorizedAbsenceEnabled, absenceDefaultAuthorized))); + new LectureBlockRollCallStatusCellRenderer(authorizedAbsenceEnabled, absenceDefaultAuthorized, getTranslator()))); if(appealEnabled && withAppeal && assessedIdentity.equals(getIdentity())) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("appeal", ParticipantCols.appeal.ordinal(), "appeal", new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("appeal"), "appeal"), null))); } - tableModel = new ParticipantLectureBlocksDataModel(columnsModel, appealCallback, + tableModel = new ParticipantLectureBlocksDataModel(columnsModel, authorizedAbsenceEnabled, absenceDefaultAuthorized, getLocale()); int paging = withPrint ? 20 : -1; tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, paging, false, getTranslator(), formLayout); @@ -174,7 +181,7 @@ public class ParticipantLectureBlocksController extends FormBasicController { options.setDefaultOrderBy(new SortKey(ParticipantCols.date.name(), true)); tableEl.setSortSettings(options); tableEl.setCustomizeColumns(withPrint); - //TODO absence tableEl.setAndLoadPersistedPreferences(ureq, "participant-roll-call-appeal"); + tableEl.setAndLoadPersistedPreferences(ureq, "participant-roll-call-appeal"); tableEl.setEmtpyTableMessageKey("empty.repository.entry.lectures"); List<FlexiTableFilter> filters = new ArrayList<>(); @@ -184,8 +191,54 @@ public class ParticipantLectureBlocksController extends FormBasicController { } private void loadModel() { + Date now = new Date(); + Formatter formatter = Formatter.getInstance(getLocale()); + List<LectureBlockAndRollCall> rollCalls = lectureService.getParticipantLectureBlocks(entry, assessedIdentity); - tableModel.setObjects(rollCalls); + List<LectureBlockAndRollCallRow> rows = new ArrayList<>(rollCalls.size()); + for(LectureBlockAndRollCall rollCall:rollCalls) { + LectureBlockAndRollCallRow row = new LectureBlockAndRollCallRow(rollCall); + if(appealEnabled && !LectureBlockStatus.cancelled.equals(row.getRow().getStatus()) && rollCall.isCompulsory()) { + + int lectures = row.getRow().getEffectiveLecturesNumber(); + if(lectures <= 0) { + lectures = row.getRow().getPlannedLecturesNumber(); + } + int attended = row.getRow().getLecturesAttendedNumber(); + if(attended < lectures) { + Date date = row.getRow().getDate(); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal = CalendarUtils.getEndOfDay(cal); + cal.add(Calendar.DATE, appealOffset); + Date beginAppeal = CalendarUtils.removeTime(cal.getTime()); + cal.add(Calendar.DATE, appealPeriod); + Date endAppeal = CalendarUtils.getEndOfDay(cal).getTime(); + + FormLink appealLink = null; + if(now.compareTo(beginAppeal) >= 0 && now.compareTo(endAppeal) <= 0) { + appealLink = uifactory.addFormLink("appeal_" + count++, "appeal", translate("appeal"), null, flc, Link.LINK | Link.NONTRANSLATED); + appealLink.setTitle(translate("appeal.tooltip", new String[] { formatter.formatDate(beginAppeal), formatter.formatDate(endAppeal) })); + appealLink.setUserObject(row); + //appeal + } else if(now.compareTo(endAppeal) > 0) { + // appeal closed + appealLink = uifactory.addFormLink("appeal_" + count++, "aclosed", "appeal.closed", null, flc, Link.LINK); + appealLink.setEnabled(false); + appealLink.setDomReplacementWrapperRequired(false); + } else if(now.compareTo(date) >= 0) { + // appeal at + String appealFrom = translate("appeal.from", new String[]{ formatter.formatDate(beginAppeal) }); + appealLink = uifactory.addFormLink("appeal_" + count++, "appealat", appealFrom, null, flc, Link.LINK | Link.NONTRANSLATED); + appealLink.setEnabled(false); + appealLink.setDomReplacementWrapperRequired(false); + } + row.setAppealButton(appealLink); + } + } + rows.add(row); + } + tableModel.setObjects(rows); tableEl.reset(true, true, true); } @@ -230,13 +283,19 @@ public class ParticipantLectureBlocksController extends FormBasicController { if(event instanceof SelectionEvent) { SelectionEvent se = (SelectionEvent)event; String cmd = se.getCommand(); - LectureBlockAndRollCall row = tableModel.getObject(se.getIndex()); + LectureBlockAndRollCallRow row = tableModel.getObject(se.getIndex()); if("appeal".equals(cmd)) { - doAppeal(ureq, row); + doAppeal(ureq, row.getRow()); } } } else if(openCourseButton == source) { doOpenCourse(ureq); + } else if(source instanceof FormLink) { + FormLink link = (FormLink)source; + if("appeal".equals(link.getCmd())) { + LectureBlockAndRollCallRow row = (LectureBlockAndRollCallRow)link.getUserObject(); + doAppeal(ureq, row.getRow()); + } } super.formInnerEvent(ureq, source, event); } @@ -257,9 +316,22 @@ public class ParticipantLectureBlocksController extends FormBasicController { contactList.addAllIdentites(teachers); contactList.addAllIdentites(onwers); + StringBuilder teacherNames = new StringBuilder(); + for(Identity teacher:teachers) { + if(teacherNames.length() > 0) teacherNames.append(", "); + teacherNames.append(teacher.getUser().getFirstName()).append(" ").append(teacher.getUser().getLastName()); + } + String date = Formatter.getInstance(getLocale()).formatDate(block.getStartDate()); + String[] args = new String[] { + row.getLectureBlockTitle(), + teacherNames.toString(), + date + }; + ContactMessage cmsg = new ContactMessage(getIdentity()); cmsg.addEmailTo(contactList); - cmsg.setSubject(translate("appeal.subject", new String[]{ row.getLectureBlockTitle() })); + cmsg.setSubject(translate("appeal.subject", args)); + cmsg.setBodyText(translate("appeal.body", args)); appealCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg); appealCtrl.setUserObject(row); appealCtrl.setContactFormTitle(translate("new.appeal.title")); @@ -289,41 +361,4 @@ public class ParticipantLectureBlocksController extends FormBasicController { String businessPath = "[RepositoryEntry:" + entry.getKey() + "]"; NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); } - - public class AppealCallback { - - private final boolean enabled; - private final int appealOffset; - private final int appealPeriod; - private final Date now; - - public AppealCallback(boolean enabled, int appealOffset, int appealPeriod) { - this.enabled = enabled; - this.appealOffset = appealOffset; - this.appealPeriod = appealPeriod; - now = new Date(); - } - - public boolean appealAllowed(LectureBlockAndRollCall row) { - if(enabled) { - int lectures = row.getEffectiveLecturesNumber(); - if(lectures <= 0) { - lectures = row.getPlannedLecturesNumber(); - } - int attended = row.getLecturesAttendedNumber(); - if(attended < lectures) { - Date date = row.getDate(); - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal = CalendarUtils.getEndOfDay(cal); - cal.add(Calendar.DATE, appealOffset); - Date beginAppeal = cal.getTime(); - cal.add(Calendar.DATE, appealPeriod); - Date endAppeal = cal.getTime(); - return now.compareTo(beginAppeal) >= 0 && now.compareTo(endAppeal) <= 0; - } - } - return false; - } - } } diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksDataModel.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksDataModel.java index f035f91a01f58dba77a37842c8989a99f673ac87..04a9e0229d8bf352d53e108c6621081a76096202 100644 --- a/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksDataModel.java +++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksDataModel.java @@ -33,8 +33,8 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; import org.olat.core.util.StringHelper; import org.olat.modules.lecture.LectureBlockStatus; +import org.olat.modules.lecture.LectureRollCallStatus; import org.olat.modules.lecture.model.LectureBlockAndRollCall; -import org.olat.modules.lecture.ui.ParticipantLectureBlocksController.AppealCallback; /** * @@ -42,28 +42,26 @@ import org.olat.modules.lecture.ui.ParticipantLectureBlocksController.AppealCall * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class ParticipantLectureBlocksDataModel extends DefaultFlexiTableDataModel<LectureBlockAndRollCall> -implements SortableFlexiTableDataModel<LectureBlockAndRollCall>, FilterableFlexiTableModel { +public class ParticipantLectureBlocksDataModel extends DefaultFlexiTableDataModel<LectureBlockAndRollCallRow> +implements SortableFlexiTableDataModel<LectureBlockAndRollCallRow>, FilterableFlexiTableModel { private final Locale locale; - private final AppealCallback appealCallback; private final boolean authorizedAbsenceEnabled; private final boolean absenceDefaultAuthorized; - private List<LectureBlockAndRollCall> backups; + private List<LectureBlockAndRollCallRow> backups; - public ParticipantLectureBlocksDataModel(FlexiTableColumnModel columnModel, AppealCallback appealCallback, + public ParticipantLectureBlocksDataModel(FlexiTableColumnModel columnModel, boolean authorizedAbsenceEnabled, boolean absenceDefaultAuthorized, Locale locale) { super(columnModel); this.locale = locale; - this.appealCallback = appealCallback; this.authorizedAbsenceEnabled = authorizedAbsenceEnabled; this.absenceDefaultAuthorized = absenceDefaultAuthorized; } @Override public void sort(SortKey orderBy) { - List<LectureBlockAndRollCall> rows = new ParticipantLectureBlocksSortDelegate(orderBy, this, locale).sort(); + List<LectureBlockAndRollCallRow> rows = new ParticipantLectureBlocksSortDelegate(orderBy, this, locale).sort(); super.setObjects(rows); } @@ -71,10 +69,10 @@ implements SortableFlexiTableDataModel<LectureBlockAndRollCall>, FilterableFlexi public void filter(List<FlexiTableFilter> filters) { String key = filters == null || filters.isEmpty() || filters.get(0) == null ? null : filters.get(0).getFilter(); if(StringHelper.containsNonWhitespace(key)) { - List<LectureBlockAndRollCall> filteredRows; + List<LectureBlockAndRollCallRow> filteredRows; if("mandatory".equals(key)) { filteredRows = backups.stream() - .filter(node -> node.isCompulsory()) + .filter(node -> node.getRow().isCompulsory()) .collect(Collectors.toList()); } else { filteredRows = new ArrayList<>(backups); @@ -87,55 +85,56 @@ implements SortableFlexiTableDataModel<LectureBlockAndRollCall>, FilterableFlexi @Override public Object getValueAt(int row, int col) { - LectureBlockAndRollCall block = getObject(row); + LectureBlockAndRollCallRow block = getObject(row); return getValueAt(block, col); } @Override - public Object getValueAt(LectureBlockAndRollCall row, int col) { + public Object getValueAt(LectureBlockAndRollCallRow row, int col) { switch(ParticipantCols.values()[col]) { - case date: return row.getDate(); - case entry: return row.getEntryDisplayname(); - case lectureBlock: return row.getLectureBlockTitle(); - case coach: return row.getCoach(); + case date: return row.getRow().getDate(); + case entry: return row.getRow().getEntryDisplayname(); + case lectureBlock: return row.getRow().getLectureBlockTitle(); + case coach: return row.getRow().getCoach(); case plannedLectures: { - if(LectureBlockStatus.cancelled.equals(row.getStatus())) { + if(LectureBlockStatus.cancelled.equals(row.getRow().getStatus())) { return null; } - return row.isCompulsory() ? row.getPlannedLecturesNumber() : null; + return row.getRow().getPlannedLecturesNumber(); } case attendedLectures: { - if(LectureBlockStatus.cancelled.equals(row.getStatus())) { + if(!isDataVisible(row.getRow())) { return null; } - if(row.isCompulsory()) { - return row.getLecturesAttendedNumber() < 0 ? 0 : row.getLecturesAttendedNumber(); + if(row.getRow().isCompulsory()) { + return row.getRow().getLecturesAttendedNumber() < 0 ? 0 : row.getRow().getLecturesAttendedNumber(); } return null; } + case unauthorizedAbsentLectures: case absentLectures: { - if(LectureBlockStatus.cancelled.equals(row.getStatus())) { + if(!isDataVisible(row.getRow())) { return null; } - if(row.isCompulsory()) { + if(row.getRow().isCompulsory()) { long value; - if(isAuthorized(row)) { + if(isAuthorized(row.getRow())) { value = 0l; } else { - value = positive(row.getLecturesAbsentNumber()); + value = positive(row.getRow().getLecturesAbsentNumber()); } return value; } return null; } case authorizedAbsentLectures: { - if(LectureBlockStatus.cancelled.equals(row.getStatus())) { + if(!isDataVisible(row.getRow())) { return null; } - if(row.isCompulsory()) { + if(row.getRow().isCompulsory()) { long value; - if(isAuthorized(row)) { - value = positive(row.getLecturesAbsentNumber()); + if(isAuthorized(row.getRow())) { + value = positive(row.getRow().getLecturesAbsentNumber()); } else { value = 0l; } @@ -144,16 +143,21 @@ implements SortableFlexiTableDataModel<LectureBlockAndRollCall>, FilterableFlexi return null; } case status: return row; - case appeal: { - if(LectureBlockStatus.cancelled.equals(row.getStatus())) { - return false; - } - return row.isCompulsory() && appealCallback.appealAllowed(row); - } + case appeal: return row.getAppealButton(); default: return null; } } + private boolean isDataVisible(LectureBlockAndRollCall row) { + LectureBlockStatus status = row.getStatus(); + if(LectureBlockStatus.cancelled.equals(status)) { + return false; + } + LectureRollCallStatus rollCallStatus = row.getRollCallStatus(); + return status == LectureBlockStatus.done + && (rollCallStatus == LectureRollCallStatus.closed || rollCallStatus == LectureRollCallStatus.autoclosed); + } + private boolean isAuthorized(LectureBlockAndRollCall row) { boolean authorized; if(authorizedAbsenceEnabled) { @@ -174,14 +178,14 @@ implements SortableFlexiTableDataModel<LectureBlockAndRollCall>, FilterableFlexi } @Override - public void setObjects(List<LectureBlockAndRollCall> objects) { + public void setObjects(List<LectureBlockAndRollCallRow> objects) { super.setObjects(objects); backups = objects; } @Override - public DefaultFlexiTableDataModel<LectureBlockAndRollCall> createCopyWithEmptyList() { - return new ParticipantLectureBlocksDataModel(getTableColumnModel(), appealCallback, + public DefaultFlexiTableDataModel<LectureBlockAndRollCallRow> createCopyWithEmptyList() { + return new ParticipantLectureBlocksDataModel(getTableColumnModel(), authorizedAbsenceEnabled, absenceDefaultAuthorized, locale); } @@ -193,6 +197,7 @@ implements SortableFlexiTableDataModel<LectureBlockAndRollCall>, FilterableFlexi plannedLectures("table.header.planned.lectures"), attendedLectures("table.header.attended.lectures"), absentLectures("table.header.absent.lectures"), + unauthorizedAbsentLectures("table.header.unauthorized.absence"), authorizedAbsentLectures("table.header.authorized.absence"), status("table.header.status"), appeal("table.header.appeal"); diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksSortDelegate.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksSortDelegate.java index 8698fedfd2db9e1081ce6af65637d8e7d717067e..0d37e49be3845e5f6ae699c1b5a46a5c85f5539c 100644 --- a/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksSortDelegate.java +++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksSortDelegate.java @@ -26,7 +26,6 @@ import java.util.Locale; import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; -import org.olat.modules.lecture.model.LectureBlockAndRollCall; import org.olat.modules.lecture.ui.ParticipantLectureBlocksDataModel.ParticipantCols; /** @@ -35,14 +34,14 @@ import org.olat.modules.lecture.ui.ParticipantLectureBlocksDataModel.Participant * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class ParticipantLectureBlocksSortDelegate extends SortableFlexiTableModelDelegate<LectureBlockAndRollCall> { +public class ParticipantLectureBlocksSortDelegate extends SortableFlexiTableModelDelegate<LectureBlockAndRollCallRow> { public ParticipantLectureBlocksSortDelegate(SortKey orderBy, ParticipantLectureBlocksDataModel tableModel, Locale locale) { super(orderBy, tableModel, locale); } @Override - protected void sort(List<LectureBlockAndRollCall> rows) { + protected void sort(List<LectureBlockAndRollCallRow> rows) { int columnIndex = getColumnIndex(); ParticipantCols column = ParticipantCols.values()[columnIndex]; switch(column) { @@ -53,15 +52,15 @@ public class ParticipantLectureBlocksSortDelegate extends SortableFlexiTableMode } } - private class AttendedLecturesComparator implements Comparator<LectureBlockAndRollCall> { + private class AttendedLecturesComparator implements Comparator<LectureBlockAndRollCallRow> { @Override - public int compare(LectureBlockAndRollCall o1, LectureBlockAndRollCall o2) { - boolean c1 = o1.isRollCalled(); - boolean c2 = o2.isRollCalled(); + public int compare(LectureBlockAndRollCallRow o1, LectureBlockAndRollCallRow o2) { + boolean c1 = o1.getRow().isRollCalled(); + boolean c2 = o2.getRow().isRollCalled(); int c = compareBooleans(c1, c2); if(c == 0) { - int l1 = o1.getLecturesAttendedNumber(); - int l2 = o2.getLecturesAttendedNumber(); + int l1 = o1.getRow().getLecturesAttendedNumber(); + int l2 = o2.getRow().getLecturesAttendedNumber(); c = compareInts(l1, l2); } return c; diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantLecturesDataModel.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantLecturesDataModel.java index 76e53f0c997b9262fe8da6bbb5a6379824d7703d..a07a62dd6bbd28e7d0918a72394d0d1a89fea0b4 100644 --- a/src/main/java/org/olat/modules/lecture/ui/ParticipantLecturesDataModel.java +++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantLecturesDataModel.java @@ -74,13 +74,13 @@ implements SortableFlexiTableDataModel<LectureBlockStatistics>, FlexiTableFooter case absentLectures: return positive(row.getTotalAbsentLectures()); case progress: return row; case rateWarning: { - if(row.getTotalEffectiveLectures() <= 0) { + if(!row.isCalculateRate() || row.getTotalEffectiveLectures() <= 0) { return null; } return row; } case rate: { - if(row.getTotalEffectiveLectures() <= 0) { + if(!row.isCalculateRate() || row.getTotalEffectiveLectures() <= 0) { return null; } return row.getAttendanceRate(); diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantLecturesOverviewController.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantLecturesOverviewController.java index f11449483caa7551f32934082d5b1d0a0ff32b11..73dd71dce8835384b8c77de164500fb7747bbffa 100644 --- a/src/main/java/org/olat/modules/lecture/ui/ParticipantLecturesOverviewController.java +++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantLecturesOverviewController.java @@ -28,6 +28,7 @@ import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; @@ -35,14 +36,20 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFle import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; +import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.stack.BreadcrumbPanel; import org.olat.core.gui.components.stack.BreadcrumbPanelAware; 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.creator.ControllerCreator; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.id.Identity; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; import org.olat.core.util.StringHelper; +import org.olat.core.util.resource.OresHelper; +import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureModule; import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.model.AggregatedLectureBlocksStatistics; @@ -51,6 +58,7 @@ import org.olat.modules.lecture.ui.ParticipantLecturesDataModel.LecturesCols; import org.olat.modules.lecture.ui.component.LectureStatisticsCellRenderer; import org.olat.modules.lecture.ui.component.PercentCellRenderer; import org.olat.modules.lecture.ui.component.RateWarningCellRenderer; +import org.olat.modules.lecture.ui.export.IdentityAuditLogExport; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; import org.olat.user.UserManager; @@ -63,12 +71,14 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class ParticipantLecturesOverviewController extends FormBasicController implements BreadcrumbPanelAware { +public class ParticipantLecturesOverviewController extends FormBasicController implements BreadcrumbPanelAware, Activateable2 { + private FormLink logButton; private FlexiTableElement tableEl; private BreadcrumbPanel stackPanel; private ParticipantLecturesDataModel tableModel; + private final boolean withLog; private final boolean withPrint; private final boolean withTitle; private final boolean withSelect; @@ -85,12 +95,13 @@ public class ParticipantLecturesOverviewController extends FormBasicController i private RepositoryService repositoryService; public ParticipantLecturesOverviewController(UserRequest ureq, WindowControl wControl, boolean withTitle) { - this(ureq, wControl, ureq.getIdentity(), true, true, withTitle); + this(ureq, wControl, ureq.getIdentity(), true, true, false, withTitle); } public ParticipantLecturesOverviewController(UserRequest ureq, WindowControl wControl, - Identity assessedIdentity, boolean withPrint, boolean withSelect, boolean withTitle) { + Identity assessedIdentity, boolean withPrint, boolean withSelect, boolean withLog, boolean withTitle) { super(ureq, wControl, "participant_overview"); + this.withLog = withLog; this.withPrint = withPrint; this.withTitle = withTitle; this.withSelect = withSelect; @@ -128,10 +139,15 @@ public class ParticipantLecturesOverviewController extends FormBasicController i StringHelper.escapeHtml(userManager.getUserDisplayName(assessedIdentity)) }); } + + if(withLog) { + logButton = uifactory.addFormLink("log", formLayout, Link.BUTTON); + logButton.setIconLeftCSS("o_icon o_icon_log"); + } FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.externalRef, "open.course")); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.entry, "open.course")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.externalRef, "details")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.entry, "details")); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.plannedLectures)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.attendedLectures)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.absentLectures)); @@ -139,18 +155,18 @@ public class ParticipantLecturesOverviewController extends FormBasicController i columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.authorizedAbsentLectures)); } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.progress, new LectureStatisticsCellRenderer())); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.rateWarning, new RateWarningCellRenderer())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LecturesCols.rateWarning, new RateWarningCellRenderer(getTranslator()))); DefaultFlexiColumnModel rateColumn = new DefaultFlexiColumnModel(LecturesCols.rate, new PercentCellRenderer()); rateColumn.setFooterCellRenderer(new PercentCellRenderer()); columnsModel.addFlexiColumnModel(rateColumn); if(withSelect) { - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("details", translate("details"), "details")); } tableModel = new ParticipantLecturesDataModel(columnsModel, getTranslator(), getLocale()); int paging = withPrint ? 20 : -1; tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, paging, false, getTranslator(), formLayout); - tableEl.setAndLoadPersistedPreferences(ureq, "participant-lectures"); + tableEl.setAndLoadPersistedPreferences(ureq, "participant-lectures-overview"); tableEl.setCustomizeColumns(false); tableEl.setEmtpyTableMessageKey("empty.lectures.list"); tableEl.setFooter(true); @@ -167,6 +183,22 @@ public class ParticipantLecturesOverviewController extends FormBasicController i return tableModel.getRowCount() > 0; } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + String type = entries.get(0).getOLATResourceable().getResourceableTypeName(); + if("RepositoryEntry".equalsIgnoreCase(type)) { + Long repoEntryKey = entries.get(0).getOLATResourceable().getResourceableId(); + for(LectureBlockStatistics row: tableModel.getObjects()) { + if(row.getRepoKey().equals(repoEntryKey)) { + doSelect(ureq, row); + break; + } + } + } + } + @Override public void event(UserRequest ureq, Component source, Event event) { if(flc.getFormItemComponent() == source && "print".equals(event.getCommand())) { @@ -182,12 +214,14 @@ public class ParticipantLecturesOverviewController extends FormBasicController i SelectionEvent se = (SelectionEvent)event; String cmd = se.getCommand(); LectureBlockStatistics row = tableModel.getObject(se.getIndex()); - if("select".equals(cmd)) { + if("details".equals(cmd)) { doSelect(ureq, row); } else if("open.course".equals(cmd)) { doOpenCourse(ureq, row); } } + } else if(logButton == source) { + doExportLog(ureq); } super.formInnerEvent(ureq, source, event); } @@ -201,7 +235,8 @@ public class ParticipantLecturesOverviewController extends FormBasicController i removeAsListenerAndDispose(lectureBlocksCtrl); RepositoryEntry entry = repositoryService.loadByKey(statistics.getRepoKey()); - lectureBlocksCtrl = new ParticipantLectureBlocksController(ureq, getWindowControl(), entry, assessedIdentity); + WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableInstance("RepositoryEntry", entry.getKey()), null); + lectureBlocksCtrl = new ParticipantLectureBlocksController(ureq, swControl, entry, assessedIdentity); listenTo(lectureBlocksCtrl); stackPanel.pushController(entry.getDisplayname(), lectureBlocksCtrl); } @@ -211,7 +246,7 @@ public class ParticipantLecturesOverviewController extends FormBasicController i @Override public Controller createController(UserRequest lureq, WindowControl lwControl) { lwControl.getWindowBackOffice().getChiefController().addBodyCssClass("o_lectures_print"); - Controller printCtrl = new ParticipantLecturesOverviewController(lureq, lwControl, assessedIdentity, false, false, true); + Controller printCtrl = new ParticipantLecturesOverviewController(lureq, lwControl, assessedIdentity, false, false, false, true); listenTo(printCtrl); return printCtrl; } @@ -224,4 +259,10 @@ public class ParticipantLecturesOverviewController extends FormBasicController i String businessPath = "[RepositoryEntry:" + row.getRepoKey() + "]"; NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); } + + private void doExportLog(UserRequest ureq) { + List<LectureBlockAuditLog> auditLog = lectureService.getAuditLog(assessedIdentity); + IdentityAuditLogExport export = new IdentityAuditLogExport(assessedIdentity, auditLog, getTranslator()); + ureq.getDispatchResult().setResultingMediaResource(export); + } } diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantListDataModel.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantListDataModel.java index a41efe91f70bbffadf73fc207f07df098442df8d..f772637aa1c91161b398aef337fe160dd0653dcb 100644 --- a/src/main/java/org/olat/modules/lecture/ui/ParticipantListDataModel.java +++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantListDataModel.java @@ -19,13 +19,20 @@ */ package org.olat.modules.lecture.ui; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.ExportableFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.gui.translator.Translator; /** * @@ -34,20 +41,36 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFl * */ public class ParticipantListDataModel extends DefaultFlexiTableDataModel<ParticipantRow> -implements SortableFlexiTableDataModel<ParticipantRow> { +implements SortableFlexiTableDataModel<ParticipantRow>, ExportableFlexiTableDataModel { private final Locale locale; + private final Translator translator; - public ParticipantListDataModel(FlexiTableColumnModel columnModel, Locale locale) { + public ParticipantListDataModel(FlexiTableColumnModel columnModel, Translator translator, Locale locale) { super(columnModel); this.locale = locale; + this.translator = translator; } @Override public void sort(SortKey sortKey) { // } - + + @Override + public MediaResource export(FlexiTableComponent ftC) { + FlexiTableColumnModel columnModel = getTableColumnModel(); + int numOfColumns = columnModel.getColumnCount(); + List<FlexiColumnModel> columns = new ArrayList<>(); + for(int i=0; i<numOfColumns; i++) { + FlexiColumnModel column = columnModel.getColumnModel(i); + if(column.isExportable()) { + columns.add(column); + } + } + return new ParticipantListExport().export(ftC, columns, translator); + } + @Override public Object getValueAt(int row, int col) { ParticipantRow participant = getObject(row); @@ -62,10 +85,12 @@ implements SortableFlexiTableDataModel<ParticipantRow> { case progress: return row.getStatistics(); case plannedLectures: return positive(row.getStatistics().getTotalPersonalPlannedLectures()); case attendedLectures: return positive(row.getStatistics().getTotalAttendedLectures()); + case unauthorizedAbsenceLectures: case absentLectures: return positive(row.getStatistics().getTotalAbsentLectures()); case authorizedAbsenceLectures: return positive(row.getStatistics().getTotalAuthorizedAbsentLectures()); case rateWarning: return row.getStatistics(); case rate: return row.getStatistics().getAttendanceRate(); + case infos: return row; default: return null; } } @@ -79,7 +104,7 @@ implements SortableFlexiTableDataModel<ParticipantRow> { @Override public DefaultFlexiTableDataModel<ParticipantRow> createCopyWithEmptyList() { - return new ParticipantListDataModel(getTableColumnModel(), locale); + return new ParticipantListDataModel(getTableColumnModel(), translator, locale); } public enum ParticipantsCols implements FlexiSortableColumnDef { @@ -87,10 +112,12 @@ implements SortableFlexiTableDataModel<ParticipantRow> { plannedLectures("table.header.planned.lectures"), attendedLectures("table.header.attended.lectures"), absentLectures("table.header.absent.lectures"), + unauthorizedAbsenceLectures("table.header.unauthorized.absence"), authorizedAbsenceLectures("table.header.authorized.absence"), progress("table.header.progress"), rateWarning("table.header.rate.warning"), - rate("table.header.rate"); + rate("table.header.rate"), + infos("table.header.infos"); private final String i18nKey; diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantListExport.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantListExport.java new file mode 100644 index 0000000000000000000000000000000000000000..cd4e5ec0dab2082d4373fad99204e4b2e257164e --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantListExport.java @@ -0,0 +1,69 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.XlsFlexiTableExporter; +import org.olat.core.gui.translator.Translator; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.openxml.OpenXMLWorkbook; +import org.olat.core.util.openxml.OpenXMLWorksheet.Row; +import org.olat.modules.lecture.ui.ParticipantListDataModel.ParticipantsCols; + +/** + * + * + * Initial date: 10 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ParticipantListExport extends XlsFlexiTableExporter { + + private static final OLog log = Tracing.createLoggerFor(ParticipantListExport.class); + + @Override + protected void createCell(FlexiTableComponent ftC, FlexiColumnModel cd, Row dataRow, int row, int col, + Translator translator, OpenXMLWorkbook workbook) { + try { + int colIndex = cd.getColumnIndex(); + if(colIndex < ParticipantListRepositoryController.USER_PROPS_OFFSET) { + switch(ParticipantsCols.values()[colIndex]) { + case rate: + FlexiTableDataModel<?> dataModel = ftC.getFlexiTableElement().getTableDataModel(); + Object rate = dataModel.getValueAt(row, colIndex); + if(rate instanceof Number) { + dataRow.addCell(col, (Number)rate, workbook.getStyles().getPercentStyle()); + } + break; + default: + super.createCell(ftC, cd, dataRow, row, col, translator, workbook); + break; + } + } else { + super.createCell(ftC, cd, dataRow, row, col, translator, workbook); + } + } catch (Exception e) { + log.error("", e); + } + } +} diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantListRepositoryController.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantListRepositoryController.java index 89c890cd8e6538bdbd74027c17c1f359184ff94b..84aaa7fceeefea8c90eeee780ad837e9682590a4 100644 --- a/src/main/java/org/olat/modules/lecture/ui/ParticipantListRepositoryController.java +++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantListRepositoryController.java @@ -1,4 +1,6 @@ /** + + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -54,6 +56,7 @@ import org.olat.modules.lecture.RepositoryEntryLectureConfiguration; import org.olat.modules.lecture.model.LectureBlockStatistics; import org.olat.modules.lecture.ui.ParticipantListDataModel.ParticipantsCols; import org.olat.modules.lecture.ui.component.LectureStatisticsCellRenderer; +import org.olat.modules.lecture.ui.component.ParticipantInfosRenderer; import org.olat.modules.lecture.ui.component.PercentCellRenderer; import org.olat.modules.lecture.ui.component.RateWarningCellRenderer; import org.olat.repository.RepositoryEntry; @@ -69,7 +72,7 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class ParticipantListRepositoryController extends FormBasicController { - protected static final String USER_PROPS_ID = ParticipantListRepositoryController.class.getCanonicalName(); + public static final String USER_PROPS_ID = ParticipantListRepositoryController.class.getCanonicalName(); public static final int USER_PROPS_OFFSET = 500; @@ -163,17 +166,27 @@ public class ParticipantListRepositoryController extends FormBasicController { if(rollCallEnabled) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantsCols.attendedLectures)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantsCols.absentLectures)); if(authorizedAbsenceEnabled) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantsCols.unauthorizedAbsenceLectures)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantsCols.authorizedAbsenceLectures)); + } else { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantsCols.absentLectures)); } - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantsCols.progress, new LectureStatisticsCellRenderer())); + FlexiColumnModel progressCol = new DefaultFlexiColumnModel(ParticipantsCols.progress, new LectureStatisticsCellRenderer()); + progressCol.setExportable(false); + columnsModel.addFlexiColumnModel(progressCol); } if(rateEnabled) { - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantsCols.rateWarning, new RateWarningCellRenderer())); + FlexiColumnModel warningCol = new DefaultFlexiColumnModel(ParticipantsCols.rateWarning, new RateWarningCellRenderer(getTranslator())); + warningCol.setExportable(false); + columnsModel.addFlexiColumnModel(warningCol); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ParticipantsCols.rate, new PercentCellRenderer())); } + FlexiColumnModel infoCol = new DefaultFlexiColumnModel(ParticipantsCols.infos, new ParticipantInfosRenderer(getTranslator(), defaultRate)); + infoCol.setExportable(false); + columnsModel.addFlexiColumnModel(infoCol); + if(!printView) { DefaultFlexiColumnModel editColumn = new DefaultFlexiColumnModel("table.header.edit", -1, "edit", new StaticFlexiCellRenderer("", "edit", "o_icon o_icon-lg o_icon_edit", translate("edit"), null)); @@ -182,12 +195,11 @@ public class ParticipantListRepositoryController extends FormBasicController { columnsModel.addFlexiColumnModel(editColumn); } - tableModel = new ParticipantListDataModel(columnsModel, getLocale()); + tableModel = new ParticipantListDataModel(columnsModel, getTranslator(), getLocale()); tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout); tableEl.setExportEnabled(!printView); - tableEl.setMultiSelect(!printView); - tableEl.setSelectAllEnable(!printView); - //TODO absence tableEl.setAndLoadPersistedPreferences(ureq, "participant-list-repo-entry"); + tableEl.setEmtpyTableMessageKey("empty.table.participant.list"); + tableEl.setAndLoadPersistedPreferences(ureq, "participant-list-repo-entry"); } private void loadModel() { diff --git a/src/main/java/org/olat/modules/lecture/ui/RollCallInterceptorController.java b/src/main/java/org/olat/modules/lecture/ui/RollCallInterceptorController.java index be44cf2d2026be8157c91399c8f9885640b8e940..7d2298bc74d7598f2c89d19caf7ff16f727ac5a2 100644 --- a/src/main/java/org/olat/modules/lecture/ui/RollCallInterceptorController.java +++ b/src/main/java/org/olat/modules/lecture/ui/RollCallInterceptorController.java @@ -72,7 +72,7 @@ public class RollCallInterceptorController extends FormBasicController implement lectureBlockToStart = lectureBlocks.get(0); String[] args = new String[] { lectureBlockToStart.getEntry().getDisplayname(), - lectureBlockToStart.getEntry().getExternalRef(), + lectureBlockToStart.getEntry().getExternalRef() == null ? "" : lectureBlockToStart.getEntry().getExternalRef(), lectureBlockToStart.getTitle(), (lectureBlockToStart.getStartDate() == null ? "" : format.formatDate(lectureBlockToStart.getStartDate())), (lectureBlockToStart.getStartDate() == null ? "" : format.formatTimeShort(lectureBlockToStart.getStartDate())), @@ -89,6 +89,7 @@ public class RollCallInterceptorController extends FormBasicController implement uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl()); uifactory.addFormSubmitButton("start", formLayout); startWizardButton = uifactory.addFormLink("start.wizard", formLayout, Link.BUTTON); + startWizardButton.setElementCssClass("o_sel_lecture_start_wizard"); } @Override diff --git a/src/main/java/org/olat/modules/lecture/ui/SingleParticipantCallController.java b/src/main/java/org/olat/modules/lecture/ui/SingleParticipantCallController.java index c0eabc44f31f4bf57e2c68cd80d4a9d50b8e2d3b..d5a71799ed9ea00a71829101783887c8fca86d94 100644 --- a/src/main/java/org/olat/modules/lecture/ui/SingleParticipantCallController.java +++ b/src/main/java/org/olat/modules/lecture/ui/SingleParticipantCallController.java @@ -38,6 +38,7 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.id.Identity; import org.olat.core.util.StringHelper; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureBlockRollCall; import org.olat.modules.lecture.LectureModule; import org.olat.modules.lecture.LectureService; @@ -64,6 +65,7 @@ public class SingleParticipantCallController extends FormBasicController { private LectureBlockRollCall rollCall; private final LectureBlock lectureBlock; private final boolean autorizedAbsenceEnabled; + private final boolean absenceDefaultAuthorized; @Autowired private LectureModule lectureModule; @@ -77,6 +79,7 @@ public class SingleParticipantCallController extends FormBasicController { this.lectureBlock = lectureBlock; autorizedAbsenceEnabled = lectureModule.isAuthorizedAbsenceEnabled(); + absenceDefaultAuthorized = lectureModule.isAbsenceDefaultAuthorized(); rollCall = lectureService.getOrCreateRollCall(calledIdentity, lectureBlock, null, null); initForm(ureq); @@ -123,7 +126,7 @@ public class SingleParticipantCallController extends FormBasicController { absenceReasonEl.setDomReplacementWrapperRequired(false); absenceReasonEl.setPlaceholderKey("authorized.absence.reason", null); absenceReasonEl.setVisible(authorizedAbsencedEl.isAtLeastSelected(1)); - absenceReasonEl.setMandatory(true); + absenceReasonEl.setMandatory(!absenceDefaultAuthorized); } String comment = rollCall.getComment(); @@ -147,7 +150,7 @@ public class SingleParticipantCallController extends FormBasicController { if(absenceReasonEl != null) { absenceReasonEl.clearError(); } - if(authorizedAbsencedEl != null && authorizedAbsencedEl.isAtLeastSelected(1)) { + if(!absenceDefaultAuthorized && authorizedAbsencedEl != null && authorizedAbsencedEl.isAtLeastSelected(1)) { if(!StringHelper.containsNonWhitespace(absenceReasonEl.getValue())) { absenceReasonEl.setErrorKey("error.reason.mandatory", null); allOk &= false; @@ -161,6 +164,9 @@ public class SingleParticipantCallController extends FormBasicController { protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(selectAllLink == source) { doSelectAll(); + doCheckAuthorized(); + } else if(checks.contains(source)) { + doCheckAuthorized(); } else if(authorizedAbsencedEl == source) { absenceReasonEl.setVisible(authorizedAbsencedEl.isAtLeastSelected(1)); } @@ -178,12 +184,15 @@ public class SingleParticipantCallController extends FormBasicController { } String comment = commentEl.getValue(); + String before = lectureService.toAuditXml(rollCall); rollCall = lectureService.addRollCall(calledIdentity, lectureBlock, rollCall, comment, absenceList); - if(authorizedAbsencedEl != null && authorizedAbsencedEl.isAtLeastSelected(1)) { - rollCall.setAbsenceAuthorized(true); + if(authorizedAbsencedEl != null) { + rollCall.setAbsenceAuthorized(authorizedAbsencedEl.isAtLeastSelected(1)); rollCall.setAbsenceReason(absenceReasonEl.getValue()); rollCall = lectureService.updateRollCall(rollCall); } + lectureService.auditLog(LectureBlockAuditLog.Action.updateRollCall, before, lectureService.toAuditXml(rollCall), + Integer.toString(rollCall.getLecturesAttendedNumber()), lectureBlock, rollCall, lectureBlock.getEntry(), calledIdentity, getIdentity()); fireEvent(ureq, Event.DONE_EVENT); } @@ -198,4 +207,21 @@ public class SingleParticipantCallController extends FormBasicController { check.select(onKeys[0], true); } } + + private void doCheckAuthorized() { + if(autorizedAbsenceEnabled) { + int absences = 0; + for(MultipleSelectionElement check:checks) { + if(check.isAtLeastSelected(1)) { + ++absences; + } + } + + if(absences == 0) { + authorizedAbsencedEl.uncheckAll(); + } else if(absenceDefaultAuthorized && (rollCall == null || rollCall.getAbsenceAuthorized() == null)) { + authorizedAbsencedEl.select(onKeys[0], true); + } + } + } } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/TeacherLecturesTableController.java b/src/main/java/org/olat/modules/lecture/ui/TeacherLecturesTableController.java index 56cd8d25316703f8407de326882392a99909df26..99aee667ce6285abc7f47f5704a4ad5a700da48c 100644 --- a/src/main/java/org/olat/modules/lecture/ui/TeacherLecturesTableController.java +++ b/src/main/java/org/olat/modules/lecture/ui/TeacherLecturesTableController.java @@ -56,9 +56,12 @@ import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController; import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.id.Identity; +import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; +import org.olat.core.util.resource.OresHelper; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockRollCall; import org.olat.modules.lecture.LectureModule; import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.RollCallSecurityCallback; @@ -66,6 +69,9 @@ import org.olat.modules.lecture.model.LectureBlockRow; import org.olat.modules.lecture.model.RollCallSecurityCallbackImpl; import org.olat.modules.lecture.ui.TeacherOverviewDataModel.TeachCols; import org.olat.modules.lecture.ui.component.LectureBlockStatusCellRenderer; +import org.olat.modules.lecture.ui.export.LectureBlockExport; +import org.olat.modules.lecture.ui.export.LecturesBlockPDFExport; +import org.olat.modules.lecture.ui.export.LecturesBlockSignaturePDFExport; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; @@ -86,7 +92,9 @@ public class TeacherLecturesTableController extends FormBasicController implemen private TeacherRollCallController rollCallCtrl; private int counter; + private final String id; private final boolean admin; + private final boolean sortAsc; private final String emptyI18nKey; private final boolean withRepositoryEntry, withTeachers; @@ -98,10 +106,12 @@ public class TeacherLecturesTableController extends FormBasicController implemen private LectureService lectureService; public TeacherLecturesTableController(UserRequest ureq, WindowControl wControl, - boolean admin, String emptyI18nKey, + boolean admin, String emptyI18nKey, boolean sortAsc, String id, boolean withRepositoryEntry, boolean withTeachers) { super(ureq, wControl, "teacher_view_table"); + this.id = id; this.admin = admin; + this.sortAsc = sortAsc; this.emptyI18nKey = emptyI18nKey; this.withTeachers = withTeachers; this.withRepositoryEntry = withRepositoryEntry; @@ -117,8 +127,8 @@ public class TeacherLecturesTableController extends FormBasicController implemen protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); if(withRepositoryEntry) { - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.externalRef, "open.course")); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.entry, "open.course")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.externalRef, "details")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.entry, "details")); } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.date, new DateFlexiCellRenderer(getLocale()))); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.startTime, new TimeFlexiCellRenderer(getLocale()))); @@ -129,20 +139,25 @@ public class TeacherLecturesTableController extends FormBasicController implemen columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.teachers)); } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.status, new LectureBlockStatusCellRenderer(getTranslator()))); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.details.i18nHeaderKey(), TeachCols.details.ordinal(), "details", - new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("table.header.details"), "details"), null))); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TeachCols.tools)); + DefaultFlexiColumnModel detailsCol = new DefaultFlexiColumnModel(TeachCols.details.i18nHeaderKey(), TeachCols.details.ordinal(), "details", + new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("table.header.details"), "details"), null)); + // set sort key even though we do not sort - added as css classes to column headers for styling + detailsCol.setSortKey(TeachCols.details.name()); + columnsModel.addFlexiColumnModel(detailsCol); + DefaultFlexiColumnModel toolsCol = new DefaultFlexiColumnModel(TeachCols.tools); + toolsCol.setSortable(false); + columnsModel.addFlexiColumnModel(toolsCol); tableModel = new TeacherOverviewDataModel(columnsModel, getLocale()); tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout); FlexiTableSortOptions sortOptions = new FlexiTableSortOptions(); - sortOptions.setDefaultOrderBy(new SortKey(TeachCols.date.name(), false)); + sortOptions.setDefaultOrderBy(new SortKey(TeachCols.date.name(), sortAsc)); tableEl.setSortSettings(sortOptions); tableEl.setCustomizeColumns(false); tableEl.setNumOfRowsEnabled(false); tableEl.setEmtpyTableMessageKey(emptyI18nKey); - tableEl.setAndLoadPersistedPreferences(ureq, "lecture-teacher-overview"); + tableEl.setAndLoadPersistedPreferences(ureq, "lecture-teacher-overview-".concat(id)); } public int getRowCount() { @@ -265,21 +280,37 @@ public class TeacherLecturesTableController extends FormBasicController implemen private void doExportAttendanceList(UserRequest ureq, LectureBlock row) { LectureBlock lectureBlock = lectureService.getLectureBlock(row); List<Identity> participants = lectureService.getParticipants(lectureBlock); + List<LectureBlockRollCall> rollCalls = lectureService.getRollCalls(row); try { - LecturesBlockPDFExport export = new LecturesBlockPDFExport(lectureBlock, getTranslator()); + boolean authorizedAbsenceEnabled = lectureModule.isAuthorizedAbsenceEnabled(); + LecturesBlockPDFExport export = new LecturesBlockPDFExport(lectureBlock, authorizedAbsenceEnabled, getTranslator()); + export.setTeacher(userManager.getUserDisplayName(getIdentity())); + export.create(participants, rollCalls); + ureq.getDispatchResult().setResultingMediaResource(export); + } catch (COSVisitorException | IOException | TransformerException e) { + logError("", e); + } + } + + private void doExportAttendanceListForSignature(UserRequest ureq, LectureBlock row) { + LectureBlock lectureBlock = lectureService.getLectureBlock(row); + List<Identity> participants = lectureService.getParticipants(lectureBlock); + try { + LecturesBlockSignaturePDFExport export = new LecturesBlockSignaturePDFExport(lectureBlock, getTranslator()); export.setTeacher(userManager.getUserDisplayName(getIdentity())); - export.setResourceTitle(lectureBlock.getEntry().getDisplayname()); export.create(participants); ureq.getDispatchResult().setResultingMediaResource(export); } catch (COSVisitorException | IOException | TransformerException e) { - e.printStackTrace(); + logError("", e); } } private void doSelectLectureBlock(UserRequest ureq, LectureBlock block) { LectureBlock reloadedBlock = lectureService.getLectureBlock(block); List<Identity> participants = lectureService.startLectureBlock(getIdentity(), reloadedBlock); - rollCallCtrl = new TeacherRollCallController(ureq, getWindowControl(), reloadedBlock, participants, getRollCallSecurityCallback(reloadedBlock)); + OLATResourceable ores = OresHelper.createOLATResourceableInstance("LectureBlock", block.getKey()); + WindowControl swControl = addToHistory(ureq, ores, null); + rollCallCtrl = new TeacherRollCallController(ureq, swControl, reloadedBlock, participants, getRollCallSecurityCallback(reloadedBlock)); listenTo(rollCallCtrl); toolbarPanel.pushController(reloadedBlock.getTitle(), rollCallCtrl); } @@ -326,6 +357,7 @@ public class TeacherLecturesTableController extends FormBasicController implemen VelocityContainer mainVC = createVelocityContainer("tools"); addLink("export", "export", "o_icon o_filetype_xlsx", mainVC); addLink("attendance.list", "attendance.list", "o_icon o_filetype_pdf", mainVC); + addLink("attendance.list.to.sign", "attendance.list.to.sign", "o_icon o_filetype_pdf", mainVC); putInitialPanel(mainVC); } @@ -346,6 +378,9 @@ public class TeacherLecturesTableController extends FormBasicController implemen if("export".equals(cmd)) { LectureBlock block = lectureService.getLectureBlock(row); doExportLectureBlock(ureq, block); + } else if("attendance.list.to.sign".equals(cmd)) { + LectureBlock block = lectureService.getLectureBlock(row); + doExportAttendanceListForSignature(ureq, block); } else if("attendance.list".equals(cmd)) { LectureBlock block = lectureService.getLectureBlock(row); doExportAttendanceList(ureq, block); diff --git a/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewController.java b/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewController.java index 8a5dcfe5dbd33e5e22d34927d4c61661a8862bc5..c9878ae05e5a468d7399cf1ca82ddddeb6cc04ca 100644 --- a/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewController.java +++ b/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewController.java @@ -26,6 +26,8 @@ import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.stack.TooledController; import org.olat.core.gui.components.stack.TooledStackedPanel; import org.olat.core.gui.components.stack.TooledStackedPanel.Align; +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.id.Identity; import org.olat.modules.lecture.LectureBlock; @@ -100,4 +102,16 @@ public class TeacherOverviewController extends AbstractTeacherOverviewController } return rows; } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + //reload table... first + super.event(ureq, source, event); + + if(source instanceof TeacherRollCallController) { + if(event == Event.DONE_EVENT || event == Event.CANCELLED_EVENT) { + stackPanel.popUpToController(this); + } + } + } } diff --git a/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewDataModel.java b/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewDataModel.java index 2cf64196b9f18334756adeecee374af1fe465c34..6ecbfd902c7237aaec441b35338901c4fbb18c86 100644 --- a/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewDataModel.java +++ b/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewDataModel.java @@ -72,7 +72,9 @@ public class TeacherOverviewDataModel extends DefaultFlexiTableDataModel<Lecture case status: return row.getLectureBlock(); case details: { Date end = row.getLectureBlock().getEndDate(); - return end.before(new Date()) || row.isIamTeacher(); + Date start = row.getLectureBlock().getStartDate(); + Date now = new Date(); + return end.before(new Date()) || (row.isIamTeacher() && start.compareTo(now) <= 0); } case tools: return row.getToolsLink(); default: return null; diff --git a/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewSearchController.java b/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewSearchController.java index f9fa40a2e3c36bb964b8fbfac26d0cf320f7a1db..6d183a4f0587269d80c1db928bc0380bbab23400 100644 --- a/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewSearchController.java +++ b/src/main/java/org/olat/modules/lecture/ui/TeacherOverviewSearchController.java @@ -47,7 +47,7 @@ public class TeacherOverviewSearchController extends FormBasicController { private final boolean withSearchString; public TeacherOverviewSearchController(UserRequest ureq, WindowControl wControl, boolean withSearchString) { - super(ureq, wControl); + super(ureq, wControl, FormBasicController.LAYOUT_VERTICAL); this.withSearchString = withSearchString; initForm(ureq); } @@ -57,8 +57,10 @@ public class TeacherOverviewSearchController extends FormBasicController { searchEl = uifactory.addTextElement("search.text", "search.form.string", 128, "", formLayout); searchEl.setHelpText(translate("search.form.string.hint")); searchEl.setVisible(withSearchString); - startEl = uifactory.addDateChooser("start", "search.form.start", null, formLayout); - endEl = uifactory.addDateChooser("end", "search.form.end", null, formLayout); + FormLayoutContainer dateLayout = FormLayoutContainer.createHorizontalFormLayout("dateLayout", getTranslator()); + formLayout.add(dateLayout); + startEl = uifactory.addDateChooser("start", "search.form.start", null, dateLayout); + endEl = uifactory.addDateChooser("end", "search.form.end", null, dateLayout); FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonsCont.setRootForm(mainForm); diff --git a/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallController.java b/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallController.java index b85e22decc9f67126dd15207362f90af92a4223f..717ae27b2f31b1fc336390d9a849615a3a643169 100644 --- a/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallController.java +++ b/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallController.java @@ -19,16 +19,12 @@ */ package org.olat.modules.lecture.ui; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.xml.transform.TransformerException; - -import org.apache.pdfbox.exceptions.COSVisitorException; import org.olat.basesecurity.BaseSecurityModule; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; @@ -63,6 +59,7 @@ import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; import org.olat.modules.lecture.LectureBlockRollCall; import org.olat.modules.lecture.LectureBlockStatus; import org.olat.modules.lecture.LectureModule; @@ -94,8 +91,7 @@ public class TeacherRollCallController extends FormBasicController { private FlexiTableElement tableEl; private TeacherRollCallDataModel tableModel; private FormSubmit quickSaveButton; - private FormLink exportAttendanceListButton, reopenButton, - cancelLectureBlockButton, closeLectureBlocksButton; + private FormLink reopenButton, cancelLectureBlockButton, closeLectureBlocksButton; private ReasonController reasonCtrl; private CloseableModalController cmc; @@ -176,13 +172,19 @@ public class TeacherRollCallController extends FormBasicController { layoutCont.contextPut("date", date); layoutCont.contextPut("startTime", startTime); layoutCont.contextPut("endTime", endTime); + layoutCont.contextPut("dateAndTime", translate("lecture.block.dateAndTime", args)); layoutCont.contextPut("teachers", sb.toString()); - layoutCont.contextPut("lectureBlockTitle", StringHelper.escapeJavaScript(lectureBlock.getTitle())); - layoutCont.contextPut("lectureBlockExternaalId", StringHelper.escapeJavaScript(lectureBlock.getExternalId())); + layoutCont.contextPut("lectureBlockTitle", StringHelper.escapeHtml(lectureBlock.getTitle())); + layoutCont.contextPut("lectureBlockExternalId", StringHelper.escapeHtml(lectureBlock.getExternalId())); + StringBuilder description = Formatter.stripTabsAndReturns(Formatter.formatURLsAsLinks(lectureBlock.getDescription())); + layoutCont.contextPut("lectureBlockDescription", StringHelper.xssScan(description)); + StringBuilder preparation = Formatter.stripTabsAndReturns(Formatter.formatURLsAsLinks(lectureBlock.getPreparation())); + layoutCont.contextPut("lectureBlockPreparation", StringHelper.xssScan(preparation)); + layoutCont.contextPut("lectureBlockLocation", StringHelper.escapeHtml(lectureBlock.getLocation())); layoutCont.contextPut("lectureBlock",lectureBlock); layoutCont.contextPut("lectureBlockOptional", !lectureBlock.isCompulsory()); layoutCont.setFormTitle(translate("lecture.block", args)); - layoutCont.setFormDescription(translate("lecture.block.infos", args)); + layoutCont.setFormDescription(StringHelper.escapeJavaScript(lectureBlock.getDescription())); } // table @@ -214,7 +216,7 @@ public class TeacherRollCallController extends FormBasicController { //all button columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("all", RollCols.all.ordinal(), "all", - new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("all"), "all"), null))); + new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("all"), "all", null, null, translate("all.desc")), null))); if(secCallback.canViewAuthorizedAbsences() || secCallback.canEditAuthorizedAbsences()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RollCols.authorizedAbsence)); } @@ -227,16 +229,16 @@ public class TeacherRollCallController extends FormBasicController { tableEl.setCustomizeColumns(true); //buttons - exportAttendanceListButton = uifactory.addFormLink("attendance.list", formLayout, Link.BUTTON); - exportAttendanceListButton.setIconLeftCSS("o_icon o_icon_download"); - uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl()); quickSaveButton = uifactory.addFormSubmitButton("save", "save.temporary", formLayout); + quickSaveButton.setElementCssClass("o_sel_lecture_quick_save"); closeLectureBlocksButton = uifactory.addFormLink("close.lecture.blocks", formLayout, Link.BUTTON); + closeLectureBlocksButton.setElementCssClass("o_sel_lecture_close"); if(lectureModule.isStatusCancelledEnabled()) { cancelLectureBlockButton = uifactory.addFormLink("cancel.lecture.blocks", formLayout, Link.BUTTON); } reopenButton = uifactory.addFormLink("reopen.lecture.blocks", formLayout, Link.BUTTON); + reopenButton.setElementCssClass("o_sel_lecture_reopen"); updateUI(); } @@ -330,7 +332,8 @@ public class TeacherRollCallController extends FormBasicController { flc.add(authorizedAbsencedEl); String reasonId = "abs_reason_".concat(Integer.toString(++counter)); - FormLink reasonLink = uifactory.addFormLink(reasonId, "reason", null, absenceCont, Link.BUTTON_XSMALL); + FormLink reasonLink = uifactory.addFormLink(reasonId, "", null, absenceCont, Link.BUTTON_XSMALL | Link.NONTRANSLATED); + reasonLink.setTitle(translate("reason")); reasonLink.setDomReplacementWrapperRequired(false); reasonLink.setIconLeftCSS("o_icon o_icon_notes"); reasonLink.setVisible(hasAuthorization); @@ -416,7 +419,7 @@ public class TeacherRollCallController extends FormBasicController { if(row.getRollCall() == null) { //??? stop? - } else { + } else if(!absenceDefaultAuthorized) { String reason = row.getRollCall().getAbsenceReason(); if(row.getAuthorizedAbsence().isAtLeastSelected(1) && !StringHelper.containsNonWhitespace(reason)) { row.getAuthorizedAbsence().setErrorKey("error.reason.mandatory", null); @@ -444,6 +447,9 @@ public class TeacherRollCallController extends FormBasicController { TeacherRollCallRow row = (TeacherRollCallRow)check.getUserObject(); if(row.getAuthorizedAbsence() == check) { doAuthorizedAbsence(row, check); + if(check.isAtLeastSelected(1)) { + doCalloutReasonAbsence(ureq, check.getFormDispatchId() + "_C_0", row); + } } else { doCheckRow(row, check); } @@ -452,21 +458,17 @@ public class TeacherRollCallController extends FormBasicController { } else if(closeLectureBlocksButton == source) { if(validateFormLogic(ureq)) { saveLectureBlocks(); - lectureService.appendToLectureBlockLog(lectureBlock, getIdentity(), null, "Save for closing rollcall (not confirmed)"); doConfirmCloseLectureBlock(ureq); } } else if(cancelLectureBlockButton == source) { saveLectureBlocks(); - lectureService.appendToLectureBlockLog(lectureBlock, getIdentity(), null, "Save for cancelling rollcall (not confirmed)"); doConfirmCancelLectureBlock(ureq); - } else if(this.exportAttendanceListButton == source) { - doExportAttendanceList(ureq); } else if(source instanceof FormLink) { FormLink link = (FormLink)source; String cmd = link.getCmd(); if(cmd != null && cmd.startsWith("abs_reason_")) { TeacherRollCallRow row = (TeacherRollCallRow)link.getUserObject(); - doCalloutReasonAbsence(ureq, link, row); + doCalloutReasonAbsence(ureq, link.getFormDispatchId(), row); } } super.formInnerEvent(ureq, source, event); @@ -475,11 +477,12 @@ public class TeacherRollCallController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { saveLectureBlocks(); - lectureService.appendToLectureBlockLog(lectureBlock, getIdentity(), null, "Quick save rollcall"); fireEvent(ureq, Event.CHANGED_EVENT); } private void saveLectureBlocks() { + String before = lectureService.toAuditXml(lectureBlock); + for(int i=tableModel.getRowCount(); i-->0; ) { TeacherRollCallRow row = tableModel.getObject(i); @@ -503,14 +506,14 @@ public class TeacherRollCallController extends FormBasicController { lectureBlock.setRollCallStatus(LectureRollCallStatus.open); } if(lectureBlock.getStatus() == null || lectureBlock.getStatus() == LectureBlockStatus.active) { - if(lectureModule.isStatusPartiallyDoneEnabled()) { - lectureBlock.setStatus(LectureBlockStatus.partiallydone); - } else { - lectureBlock.setStatus(LectureBlockStatus.active); - } + lectureBlock.setStatus(LectureBlockStatus.active); } lectureBlock = lectureService.save(lectureBlock, null); lectureService.recalculateSummary(lectureBlock.getEntry()); + + String after = lectureService.toAuditXml(lectureBlock); + lectureService.auditLog(LectureBlockAuditLog.Action.saveLectureBlock, before, after, null, lectureBlock, null, lectureBlock.getEntry(), null, getIdentity()); + } @Override @@ -519,15 +522,23 @@ public class TeacherRollCallController extends FormBasicController { } private void doCheckAllRow(TeacherRollCallRow row) { - List<Integer> allIndex = new ArrayList<>(numOfLectures); + List<Integer> allAbsences = new ArrayList<>(numOfLectures); for(int i=0; i<numOfLectures; i++) { - allIndex.add(i); + allAbsences.add(i); } - LectureBlockRollCall rollCall = lectureService.addRollCall(row.getIdentity(), lectureBlock, row.getRollCall(), null, allIndex); + LectureBlockRollCall rollCall = lectureService.addRollCall(row.getIdentity(), lectureBlock, row.getRollCall(), null, allAbsences); for(MultipleSelectionElement check:row.getChecks()) { check.select(onKeys[0], true); } row.setRollCall(rollCall); + if(authorizedAbsenceEnabled) { + if(rollCall.getAbsenceAuthorized() != null && rollCall.getAbsenceAuthorized().booleanValue()) { + row.getAuthorizedAbsence().select(onKeys[0], true); + } else { + row.getAuthorizedAbsence().uncheckAll(); + } + row.getAuthorizedAbsenceCont().setDirty(true); + } row.getRollCallStatusEl().getComponent().setDirty(true); tableEl.reloadData(); flc.setDirty(true); @@ -538,12 +549,25 @@ public class TeacherRollCallController extends FormBasicController { List<Integer> indexList = Collections.singletonList(index); LectureBlockRollCall rollCall; + String before = lectureService.toAuditXml(row.getRollCall()); if(check.isAtLeastSelected(1)) { rollCall = lectureService.addRollCall(row.getIdentity(), lectureBlock, row.getRollCall(), indexList); + lectureService.auditLog(LectureBlockAuditLog.Action.addToRollCall, before, lectureService.toAuditXml(rollCall), + Integer.toString(index), lectureBlock, rollCall, lectureBlock.getEntry(), row.getIdentity(), getIdentity()); } else { rollCall = lectureService.removeRollCall(row.getIdentity(), lectureBlock, row.getRollCall(), indexList); + lectureService.auditLog(LectureBlockAuditLog.Action.removeFromRollCall, before, lectureService.toAuditXml(rollCall), + Integer.toString(index), lectureBlock, rollCall, lectureBlock.getEntry(), row.getIdentity(), getIdentity()); + } + row.setRollCall(rollCall); + if(authorizedAbsenceEnabled) { + if(rollCall.getAbsenceAuthorized() != null && rollCall.getAbsenceAuthorized().booleanValue()) { + row.getAuthorizedAbsence().select(onKeys[0], true); + } else { + row.getAuthorizedAbsence().uncheckAll(); + } + row.getAuthorizedAbsenceCont().setDirty(true); } - row.setRollCall(rollCall); row.getRollCallStatusEl().getComponent().setDirty(true); } @@ -551,11 +575,17 @@ public class TeacherRollCallController extends FormBasicController { LectureBlockRollCall rollCall = row.getRollCall(); boolean authorized = check.isAtLeastSelected(1); if(rollCall == null) { - rollCall = lectureService.getOrCreateRollCall(row.getIdentity(), lectureBlock, authorized, null); + rollCall = lectureService.getOrCreateRollCall(row.getIdentity(), lectureBlock, authorized, null); + lectureService.auditLog(LectureBlockAuditLog.Action.createRollCall, null, lectureService.toAuditXml(rollCall), + authorized ? "true" : "false", lectureBlock, rollCall, lectureBlock.getEntry(), row.getIdentity(), getIdentity()); } else { + String before = lectureService.toAuditXml(rollCall); rollCall.setAbsenceAuthorized(authorized); rollCall = lectureService.updateRollCall(rollCall); + lectureService.auditLog(LectureBlockAuditLog.Action.updateAuthorizedAbsence, before, lectureService.toAuditXml(rollCall), + authorized ? "true" : "false", lectureBlock, rollCall, lectureBlock.getEntry(), row.getIdentity(), getIdentity()); } + row.getReasonLink().setVisible(authorized); row.getAuthorizedAbsenceCont().setDirty(true); row.getAuthorizedAbsence().clearError(); @@ -563,26 +593,32 @@ public class TeacherRollCallController extends FormBasicController { row.getRollCallStatusEl().getComponent().setDirty(true); } - private void doCalloutReasonAbsence(UserRequest ureq, FormLink link, TeacherRollCallRow row) { + private void doCalloutReasonAbsence(UserRequest ureq, String elementId, TeacherRollCallRow row) { boolean canEdit = secCallback.canEdit() && secCallback.canEditAuthorizedAbsences(); reasonCtrl = new ReasonController(ureq, getWindowControl(), row, canEdit); listenTo(reasonCtrl); reasonCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(), - reasonCtrl.getInitialComponent(), link.getFormDispatchId(), "", true, ""); + reasonCtrl.getInitialComponent(), elementId, "", true, ""); listenTo(reasonCalloutCtrl); reasonCalloutCtrl.activate(); } private void doReason(TeacherRollCallRow row, String reason) { LectureBlockRollCall rollCall = row.getRollCall(); + String before = lectureService.toAuditXml(rollCall); if(rollCall == null) { row.getAuthorizedAbsence().select(onKeys[0], true); - rollCall = lectureService.getOrCreateRollCall(row.getIdentity(), lectureBlock, true, reason); + rollCall = lectureService.getOrCreateRollCall(row.getIdentity(), lectureBlock, true, reason); + lectureService.auditLog(LectureBlockAuditLog.Action.createRollCall, before, lectureService.toAuditXml(rollCall), + reason, lectureBlock, rollCall, lectureBlock.getEntry(), row.getIdentity(), getIdentity()); } else { rollCall.setAbsenceReason(reason); rollCall = lectureService.updateRollCall(rollCall); + lectureService.auditLog(LectureBlockAuditLog.Action.updateRollCall, before, lectureService.toAuditXml(rollCall), + reason, lectureBlock, rollCall, lectureBlock.getEntry(), row.getIdentity(), getIdentity()); } + row.setRollCall(rollCall); } @@ -609,26 +645,16 @@ public class TeacherRollCallController extends FormBasicController { } private void doReopen(UserRequest ureq) { + String before = lectureService.toAuditXml(lectureBlock); lectureBlock.setRollCallStatus(LectureRollCallStatus.reopen); lectureBlock = lectureService.save(lectureBlock, null); secCallback.updateLectureBlock(lectureBlock); updateUI(); fireEvent(ureq, Event.CHANGED_EVENT); - lectureService.appendToLectureBlockLog(lectureBlock, getIdentity(), null, "Reopen"); + String after = lectureService.toAuditXml(lectureBlock); + lectureService.auditLog(LectureBlockAuditLog.Action.reopenLectureBlock, before, after, null, lectureBlock, null, lectureBlock.getEntry(), null, getIdentity()); ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LECTURE_BLOCK_ROLL_CALL_REOPENED, getClass(), CoreLoggingResourceable.wrap(lectureBlock, OlatResourceableType.lectureBlock, lectureBlock.getTitle())); } - - private void doExportAttendanceList(UserRequest ureq) { - try { - LecturesBlockPDFExport export = new LecturesBlockPDFExport(lectureBlock, getTranslator()); - export.setTeacher(userManager.getUserDisplayName(getIdentity())); - export.setResourceTitle(lectureBlock.getEntry().getDisplayname()); - export.create(participants); - ureq.getDispatchResult().setResultingMediaResource(export); - } catch (COSVisitorException | IOException | TransformerException e) { - logError("", e); - } - } } diff --git a/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallWizardController.java b/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallWizardController.java index 92bc3b4308e2171c8af635e26d5b9bd28b7d78b4..dcd76e66ab20d56fd20484d84cc9291e07469b27 100644 --- a/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallWizardController.java +++ b/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallWizardController.java @@ -78,7 +78,12 @@ public class TeacherRollCallWizardController extends BasicController { listenTo(nextPreviousCtrl); mainVC.put("nextPrevious", nextPreviousCtrl.getInitialComponent()); putInitialPanel(mainVC); - doSelect(ureq, calledIdentity); + + if(calledIdentity == null) { + doClosseRollCall(ureq); + } else { + doSelect(ureq, calledIdentity); + } } @Override @@ -100,7 +105,7 @@ public class TeacherRollCallWizardController extends BasicController { doClose(ureq); } } else if(closeRollCallCtrl == source) { - if(event == Event.DONE_EVENT) { + if(event == Event.DONE_EVENT || event == Event.CANCELLED_EVENT) { doClose(ureq); } } @@ -113,18 +118,22 @@ public class TeacherRollCallWizardController extends BasicController { calledIdentity = participants.get(index + 1); doSelect(ureq, calledIdentity); } else if(index + 1 >= participants.size() || index == -1) { - removeAsListenerAndDispose(participantCtrl); - removeAsListenerAndDispose(closeRollCallCtrl); - - closeRollCallCtrl = new CloseRollCallConfirmationController(ureq, getWindowControl(), lectureBlock, secCallback); - listenTo(closeRollCallCtrl); - calledIdentity = null; - - mainVC.put("call", closeRollCallCtrl.getInitialComponent()); - nextPreviousCtrl.updateNextPrevious(null); + doClosseRollCall(ureq); } } + private void doClosseRollCall(UserRequest ureq) { + removeAsListenerAndDispose(participantCtrl); + removeAsListenerAndDispose(closeRollCallCtrl); + + closeRollCallCtrl = new CloseRollCallConfirmationController(ureq, getWindowControl(), lectureBlock, secCallback); + listenTo(closeRollCallCtrl); + calledIdentity = null; + + mainVC.put("call", closeRollCallCtrl.getInitialComponent()); + nextPreviousCtrl.updateNextPrevious(null); + } + private void doPrevious(UserRequest ureq) { int index; if(closeRollCallCtrl != null) { @@ -144,6 +153,7 @@ public class TeacherRollCallWizardController extends BasicController { private void doSelect(UserRequest ureq, Long callIdentityKey) { for(Identity participant:participants) { if(participant.getKey().equals(callIdentityKey)) { + calledIdentity = participant; doSelect(ureq, participant); } } @@ -207,13 +217,15 @@ public class TeacherRollCallWizardController extends BasicController { protected void updateNextPrevious(Identity callIdentity) { if(callIdentity == null) { //last step - nextLink.setEnabled(false); - previousLink.setEnabled(true); + nextLink.setVisible(false); + participantsEl.setVisible(false); + previousLink.setEnabled(participants.size() > 0); } else { int index = participants.indexOf(callIdentity); + nextLink.setVisible(true); nextLink.setEnabled(index >= 0 && index + 1 <= participants.size()); previousLink.setEnabled(index > 0); - + participantsEl.setVisible(true); String calledIdentityKey = callIdentity.getKey().toString(); for(String participantKey:participantKeys) { if(participantKey.equals(calledIdentityKey)) { diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository.html b/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository.html index 5da6ca9b6520104df5d5d858cdd144db9c980766..0a782289e5c9785e80f723dbd0acf07a060b2fb0 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository.html @@ -1,4 +1,4 @@ -<div class="clearfix"> +<div class="clearfix o_sel_repo_lectures_admin"> $r.render("segments")<br/> #if($r.available("segmentCmp")) diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository_lectures.html b/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository_lectures.html index 49b54ccc7aba49ef50f533aee8ab67017d1f471a..0d70ba3886d58e745302263ebd464df68206cc91 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository_lectures.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository_lectures.html @@ -1,12 +1,16 @@ -#if($r.available("add.lecture")) +<div class="o_sel_repo_lectures_list"> <div class="o_button_group o_button_group_right"> - $r.render("add.lecture") + #if($r.available("add.lecture")) + $r.render("add.lecture") + #end + $r.contextHelpWithWrapper("Lectures and absences") </div> -#end $r.render("table") - +#if($r.available("delete")) <div class="o_button_group"> #if($r.available("delete")) $r.render("delete") #end +</div> +#end </div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/date_end.html b/src/main/java/org/olat/modules/lecture/ui/_content/date_end.html new file mode 100644 index 0000000000000000000000000000000000000000..f154680ba123c9adcc1d8f7a38eb17414cb5cc15 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/_content/date_end.html @@ -0,0 +1,7 @@ +<div class="o_date_ms form-inline">$r.render("lecture.end.hour"):$r.render("lecture.end.minute")</div> +#if($f.hasError("lecture.end.hour")) + <div>$r.render("lecture.end.hour_ERROR")</div> +#end +#if($f.hasError("lecture.end.minute")) + <div>$r.render("lecture.end.minute_ERROR")</div> +#end \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/date_start_end.html b/src/main/java/org/olat/modules/lecture/ui/_content/date_start_end.html index f154680ba123c9adcc1d8f7a38eb17414cb5cc15..eaebee6434338e3793162cdf945ebc7331d8b871 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/date_start_end.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/date_start_end.html @@ -1,4 +1,12 @@ -<div class="o_date_ms form-inline">$r.render("lecture.end.hour"):$r.render("lecture.end.minute")</div> +<div class="o_date_ms form-inline"> + $r.translate("lecture.time.from") $r.render("lecture.start.hour"):$r.render("lecture.start.minute") +$r.translate("lecture.time.until") $r.render("lecture.end.hour"):$r.render("lecture.end.minute")</div> +#if($f.hasError("lecture.start.hour")) + <div>$r.render("lecture.start.hour_ERROR")</div> +#end +#if($f.hasError("lecture.start.minute")) + <div>$r.render("lecture.start.minute_ERROR")</div> +#end #if($f.hasError("lecture.end.hour")) <div>$r.render("lecture.end.hour_ERROR")</div> #end diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/lectures_tools.html b/src/main/java/org/olat/modules/lecture/ui/_content/lectures_tools.html index 799eaccb19e3a85a6a894a11a5b84629f051d018..7e09620dc541269be003ee8887604963ee2b4c6a 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/lectures_tools.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/lectures_tools.html @@ -5,4 +5,7 @@ #if($r.available("delete")) <li>$r.render("delete")</li> #end +#if($r.available("log")) + <li>$r.render("log")</li> +#end </ul> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/participant_blocks.html b/src/main/java/org/olat/modules/lecture/ui/_content/participant_blocks.html index 8677a75ec5691e26e73801b327da97bd1e9a22d5..1838d2b2cc4d6d45f77a52d6554b53f3bed0eaf6 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/participant_blocks.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/participant_blocks.html @@ -1,4 +1,4 @@ -<div class="o_header_with_buttons"> +<div class="o_sel_lecture_participant_blocks"><div class="o_header_with_buttons"> <h3><i class="o_icon o_CourseModule_icon"> </i> $title</h3> #if($r.isNotNull($withPrint) && $withPrint) <div class="o_button_group o_button_group_right"> @@ -16,8 +16,18 @@ function print() { /* ]]> */ </script> <a class="btn btn-default" href="javascript:print()" title="$r.translate("print")"><i class="o_icon o_icon_print"> </i> $r.translate("print")</a> + $r.contextHelpWithWrapper("Lectures - User view") </div> #end </div> - -$r.render("table") \ No newline at end of file +$r.render("table") +<ul class="list-unstyled"> + <li><i class="o_icon o_lectures_rollcall_ok"> </i> $r.translate("table.legend.attended")</li> + <li><i class="o_icon o_lectures_rollcall_warning"> </i> $r.translate("table.legend.authorized")</li> + <li><i class="o_icon o_lectures_rollcall_danger"> </i> $r.translate("table.legend.absent")</li> + <li><i class="o_icon o_icon_cancelled"> </i> $r.translate("cancelled")</li> + <li><i class="o_icon o_icon_status_in_review"> </i> $r.translate("in.progress")</li> + <li><i class="o_icon o_lectures_rollcall_free"> </i> $r.translate("table.legend.free")</li> + <li>(*) $r.translate("table.legend.free")</li> +</ul> +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/participant_list_overview.html b/src/main/java/org/olat/modules/lecture/ui/_content/participant_list_overview.html index 08e5db8c2ae699f227561b011cdc733c6bd379ed..f6667d070f56bc7d932bd933c797d7c3e526f74c 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/participant_list_overview.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/participant_list_overview.html @@ -1,6 +1,6 @@ +<div class="o_button_group o_button_group_right"> #if($r.isNotNull($withPrint) && $withPrint) - <div class="o_button_group o_button_group_right"> - <script type="text/javascript"> +<script type="text/javascript"> /* <![CDATA[ */ function print() { try { @@ -11,8 +11,9 @@ function print() { } } /* ]]> */ - </script> - <a class="btn btn-default" href="javascript:print()" title="$r.translate("print")"><i class="o_icon o_icon_print"> </i> $r.translate("print")</a> - </div> +</script> + <a class="btn btn-default" href="javascript:print()" title="$r.translate("print")"><i class="o_icon o_icon_print"> </i> $r.translate("print")</a> + $r.contextHelpWithWrapper("Lectures and absences") #end +</div> $r.render("table") \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/participant_overview.html b/src/main/java/org/olat/modules/lecture/ui/_content/participant_overview.html index 943411312d900190e7237b89b245ed67546b3331..ef28bcfed5833999214988dacd620ca54f47cbc1 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/participant_overview.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/participant_overview.html @@ -1,9 +1,10 @@ -<fieldset> +<fieldset class="o_sel_lecture_participant_overview"> #if($r.isNotEmpty($off_title)) <legend><i class="o_icon o_icon-fw o_icon_lecture"> </i> $off_title</legend> #end -#if($r.isNotNull($withPrint) && $withPrint) +#if(($r.isNotNull($withPrint) && $withPrint) || $r.available("log")) <div class="o_button_group o_button_group_right"> + #if($r.isNotNull($withPrint) && $withPrint) <script type="text/javascript"> /* <![CDATA[ */ function print() { @@ -17,7 +18,17 @@ function print() { /* ]]> */ </script> <a class="btn btn-default" href="javascript:print()" title="$r.translate("print")"><i class="o_icon o_icon_print"> </i> $r.translate("print")</a> + #end + #if($r.available("log")) + $r.render("log") + #end + $r.contextHelpWithWrapper("Lectures - User view") </div> #end $r.render("table") +<ul class="list-unstyled"> + <li><i class="o_icon o_lectures_attended"> </i> $r.translate("table.legend.attended")</li> + <li><i class="o_icon o_lectures_authorized"> </i> $r.translate("table.legend.authorized")</li> + <li><i class="o_icon o_lectures_absent"> </i> $r.translate("table.legend.absent")</li> +</ul> </fieldset> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/reason.html b/src/main/java/org/olat/modules/lecture/ui/_content/reason.html index 1e2ffff33e291bf79085828a5301b6f3619ac0e6..35bf945528d0d54ef9748c5c20fc7c2edc4499af 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/reason.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/reason.html @@ -1,4 +1,7 @@ $r.render("reason") <div class="o_button_group small"> - $r.render("cancel") $r.render("save") + $r.render("cancel") + #if($r.available("save")) + $r.render("save") + #end </div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/rollcall.html b/src/main/java/org/olat/modules/lecture/ui/_content/rollcall.html index 53fb1a81bdcf75d8eb0839796c3f7ca0c1bdba28..8c11c3a25edc4a1fde3c9e03da5b1964ab667195 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/rollcall.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/rollcall.html @@ -1,15 +1,57 @@ +<div class="o_lectures_rollcall"> <fieldset> - <legend>$off_title</legend> - #if($lectureBlockOptional) - <div class="o_warning">$r.translate("info.lecture.block.optional")</div> - #end + <legend> + $off_title "$lectureBlockTitle" + #if($r.isNotEmpty(lectureBlockExternalId)) + <small class="text-muted"> + $lectureBlockExternalId + </small> + #end + </legend> + #if($r.available("attendance.list")) - <div class="o_button_group o_button_group_right"> + <div class=" pull-right"> $r.render("attendance.list") </div> #end - <div class="o_desc">$off_desc</div> - $r.render("table") + <div class="o_lectures_rollcall_meta o_block_bottom"> + <div class="o_teachers text-muted"> + <i class="o_icon o_icon-fw o_icon_graduate"> </i> + $teachers + </div> + <div class="o_date text-muted"> + <i class="o_icon o_icon-fw o_icon_calendar"> </i> + $dateAndTime + </div> + #if($lectureBlockLocation && $lectureBlockLocation != "") + <div class="o_date text-muted"> + <i class="o_icon o_icon-fw o_icon_home"> </i> + $lectureBlockLocation + </div> + #end + #if($lectureBlockOptional) + <div class="o_optional text-warning"> + <i class="o_icon o_icon-fw o_icon_warn"> </i> + $r.translate("info.lecture.block.optional") + </div> + #end + </div> + + #if($r.isNotEmpty($lectureBlockDescription)) + <div class="o_desc o_info"> + <h5>$r.translate("lecture.descr")</h5> + $lectureBlockDescription + </div> + #end + #if($r.isNotEmpty($lectureBlockPreparation)) + <div class="o_preparation o_note"> + <h5>$r.translate("lecture.preparation")</h5> + $lectureBlockPreparation + </div> + #end + <div class="o_rollcall_table o_block_top"> + $r.render("table") + </div> <div class="o_button_group"> $r.render("cancel") #if($r.available("save")) @@ -25,4 +67,5 @@ $r.render("reopen.lecture.blocks") #end </div> -</fieldset> \ No newline at end of file +</fieldset> +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/rollcall_interceptor.html b/src/main/java/org/olat/modules/lecture/ui/_content/rollcall_interceptor.html index d06de1735cea51499a4036b623844707394a2540..0ad120894fd86cd10eadb04071779aba33bcd42a 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/rollcall_interceptor.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/rollcall_interceptor.html @@ -1,6 +1,8 @@ -<div class="o_warning"><i class="o_icon o_icon-lg o_icon_lectures"> </i> $message</div> -<div class="o_button_group"> - $r.render("cancel") - $r.render("start") - $r.render("start.wizard") +<div class="o_sel_lecture_start_wizard"> + <div class="o_warning"><i class="o_icon o_icon-lg o_icon_lectures"> </i> $message</div> + <div class="o_button_group"> + $r.render("cancel") + $r.render("start") + $r.render("start.wizard") + </div> </div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/teacher_view.html b/src/main/java/org/olat/modules/lecture/ui/_content/teacher_view.html index f05d7c5bf305efd0f70c3a8941ae4e321f22c40f..681b6840308eedffb0738ec1dbf563b401d82e0a 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/teacher_view.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/teacher_view.html @@ -1,37 +1,58 @@ <div class="o_lectures_teacher_overview"> - <div class="clearfix"> + <div class="o_lectures_teacher_search clearfix" style="position:relative;"> $r.render("search") + $r.contextHelpWithWrapper("Lectures - Teacher view") </div> - <fieldset> - <legend><i class="o_icon o_lectures_current"> </i> $r.translate("lectures.table.current")</legend> - $r.render("currentLectures") - #if($r.visible("start") || $r.visible("start.wizard")) - <div class="o_button_group"> - #if($r.visible("start")) - $r.render("start") - #end - #if($r.visible("start.wizard")) - $r.render("start.wizard") + #if($r.isNotNull($totalBlockSize) && $totalBlockSize > 0) + #if($r.isNotNull($currentBlockSize) && $currentBlockSize > 0) + <div class="o_lectures_current_wrapper"> + <fieldset class="o_sel_lecture_table_current"> + <legend><i class="o_icon o_lectures_current"> </i> $r.translate("lectures.table.current")</legend> + $r.render("currentLectures") + #if($r.visible("start.mobile") || $r.visible("start.desktop")) + <div class="o_button_group"> + <span class="o_lecture_start">$r.translate("start.label")</span> + #if($r.visible("start.desktop")) + $r.render("start.desktop") + #end + #if($r.visible("start.mobile")) + $r.render("start.mobile") + #end + </div> #end + </fieldset> </div> #end - </fieldset> - #if($r.isNotNull($pendingBlockSize) && $pendingBlockSize > 0) - <fieldset> - <legend><i class="o_icon o_lectures_pending"> </i> $r.translate("lectures.table.pending")</legend> - $r.render("pendingLectures") - </fieldset> - #end - #if($r.isNotNull($nextBlockSize) && $nextBlockSize > 0) - <fieldset> - <legend><i class="o_icon o_lectures_next"> </i> $r.translate("lectures.table.next")</legend> - $r.render("nextLectures") - </fieldset> - #end - #if($r.isNotNull($closedBlockSize) && $closedBlockSize > 0) - <fieldset> - <legend><i class="o_icon o_icon-sm o_lectures_closed"> </i> $r.translate("lectures.table.closed")</legend> - $r.render("closedLectures") - </fieldset> + #if($r.isNotNull($pendingBlockSize) && $pendingBlockSize > 0) + <fieldset class="o_block_large"> + <legend><i class="o_icon o_lectures_pending o_sel_lecture_table_pending"> </i> $r.translate("lectures.table.pending")</legend> + $r.render("pendingLectures") + </fieldset> + #end + #if($r.isNotNull($nextBlockSize) && $nextBlockSize > 0) + <fieldset class="o_block_large o_sel_lecture_table_next"> + <legend><i class="o_icon o_lectures_next"> </i> $r.translate("lectures.table.next")</legend> + $r.render("nextLectures") + </fieldset> + #end + #if($r.isNotNull($closedBlockSize) && $closedBlockSize > 0) + <fieldset class="o_block_large o_sel_lecture_table_closed"> + <legend><i class="o_icon o_icon-sm o_lectures_closed"> </i> $r.translate("lectures.table.closed")</legend> + $r.render("closedLectures") + </fieldset> + #end + #else + <div class="o_info"> + $r.translate("empty.table.lectures.blocks") + </div> #end -</div> \ No newline at end of file +</div> + +<script type="text/javascript"> +/* <![CDATA[ */ +jQuery(function() { + var tables = jQuery('.o_lectures_teacher_overview table'); + BFormatter.alignTableColumns(tables); +}); +/* ]]> */ +</script> diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/tools.html b/src/main/java/org/olat/modules/lecture/ui/_content/tools.html index 66936ec9fe97188df3faf4f4699106142ee8cccd..a4fb3d101e3ca023b157a0920ec4aac8963bad68 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_content/tools.html +++ b/src/main/java/org/olat/modules/lecture/ui/_content/tools.html @@ -5,4 +5,7 @@ #if($r.available("attendance.list")) <li>$r.render("attendance.list")</li> #end + #if($r.available("attendance.list.to.sign")) + <li>$r.render("attendance.list.to.sign")</li> + #end </ul> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties index 1429ce09414cbb2c554e5a29bf64b8cf03fab975..b3491cc52c206a61ed136f222066fc399951fff4 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties @@ -1,4 +1,4 @@ -#Tue Jul 04 10:07:57 CEST 2017 +#Mon Jul 17 21:17:43 CEST 2017 active=Aktiv add.lecture=Neuer Lektionenblock erstellen add.reason=Begr\u00FCndung erstellen @@ -6,18 +6,29 @@ admin.menu.title=Lektionen admin.menu.title.alt=Lektionen und Absenzmanagement aggregated.list=Aggregierte Liste all=Alle +all.desc=Alle Lektionen als abwesend markieren all.teachers.switch=Alle Dozenten +all.teachers.switch.tooltip.off=Alle Lektionenbl\u00F6cke anzeigen +all.teachers.switch.tooltip.on=Nur meine Lektionenbl\u00F6cke anzeigen appeal=Rekurs -appeal.contact.list=Lehrer +appeal.body=<p>Liebe / Lieber {1}</p><p>Ich melde mich bezüglich meiner Absenz vom {2}, welche aus meiner Sicht nicht korrekt erfasst wurde.</p><p>Begründung:</p><p><span style="color: #ff0000;">(Bitte Grund eintragen)</span></p><p>Vielen Dank im Voraus für die Prüfung und für eine allfällige Korrektur.</p><p>Liebe Grüsse</p> +appeal.closed=Geschlossen +appeal.contact.list=Dozent +appeal.from=Ab {0} appeal.subject=Rekurs Lektionenblock "{0}" appeal.title=Rekurs f\u00FCr\: "{0}" -attendance.list=Anwesenheitsliste +appeal.tooltip=Rekurs m\u00F6glich von {0} bis {1} +archive.entry=Archivierung +attendance.list=Absenzenliste +attendance.list.title=Absenzenliste: {0} +attendance.list.to.sign=Pr\u00E4senzliste +attendance.list.to.sign.title=Pr\u00E4senzliste: {0} authorized.absence=Entschuldigt authorized.absence.reason=Begr\u00FCndung autoclosed=Autoerledigt bulk=Benutzername, $org.olat.user.propertyhandlers\:table.name.email oder $org.olat.user.propertyhandlers\:table.name.institutionalUserIdentifier bulk.example=test01<br>author02<br>test@openolat.org -bulk.hint=Sie k\u00F6nenn eine Liste von Benutzername oder Email Adresse von Benutzer geben. +bulk.hint=Im Suchfeld k\u00F6nenn Sie eine Liste von Benutzernamen oder E-Mailadressen der Benutzer eintragen. cancel.lecture.blocks=Lektionen absagen cancelled=Abgesagt close.lecture.blocks=Lektionen abschliessen @@ -29,7 +40,7 @@ config.override.yes=Ja config.rollcall.enabled=Anwesenheitskontrolle einschalten config.sync.course.calendar=Kurs Kalender synchronisieren config.sync.participant.calendar=Teilnehmer Kalender synchronisieren -config.sync.teacher.calendar=Lehrer Kalender synchronisieren +config.sync.teacher.calendar=Dozentenkalender synchronisieren confirm.delete.lectures=Wollen Sie wirklich diese Lektionenblock "{0}" l\u00F6schen? confirm.delete.reason=Wollen Sie wirklich diese Begr\u00FCndung "{0}" l\u00F6schen? copy=Kopieren @@ -49,9 +60,11 @@ edit.participant.rate=Teilnehmerschwellwert bearbeiten edit.reason=Begr\u00FCndung bearbeiten effective.lectures=Effektive Lektionen empty.lectures.list=Die Tabelle ist leer -empty.repository.entry.lectures=Sie m\u00FCssten noch keinen Lektionen in diesem Kurs besuchen -empty.table.current.lectures.blocks=Sie haben zur Zeit keinen Lektionenblock. -empty.table.lectures.blocks=Es gibt keine Lektioneblock. +empty.repository.entry.lectures=Sie mussten in diesem Kurs noch keine Lektionen besuchen. +empty.table.current.lectures.blocks=Sie haben zum aktuellen Zeitpunkt keine Lektionen. +empty.table.lectures.blocks=Es wurden keine Lektionen gefunden. +empty.table.lectures.blocks.admin=Es wurde bisher keinen Lektionenbl\u00F6cken f\u00FCr diesen Kurs erstellt. +empty.table.participant.list=Es wurde noch keine Anwesenheitskontrolle f\u00FCr diesen Kurs durchgef\u00FChrt. entry.rate=Kursschwellwert error.atleastone.lecture=Bitte w\u00E4hlen Sie mindestens ein Lektionenblock. error.integer.between=Der Eingabe muss ein Zahl zwischen {0} und {1} @@ -59,19 +72,22 @@ error.integer.positive=Der Eingabe muss ein positives Zahl sein. error.reason.mandatory=Begr\u00FCndung ist erforderlich error.search.form.notempty=$org.olat.admin.user\:error.search.form.notempty export.footer.lectures.hint=x \= Lektion abwesend +export.header.entry=Kurs\: {0} export.header.lectureblocks=Lektionenblock\: {0} vom {1} von {2} bis {3} -export.header.lectures=Lectures +export.header.lectures=Lektionen export.header.location=Raum\: {0} export.header.teachers=Dozenten\: {0} -filter.mandatory=Zwingend +filter.mandatory=Anwesehnheit obligatorisch filter.showAll=Alle anzeigen first.admission=Erstzulassung form.managedflags.intro=Dieser Lektionblock wurde von einem externen Werkzeug erstellt. Einige Einstellungen und Module k\u00F6nnen daher in OpenOLAT nicht ver\u00E4ndert und benutzt werden. Folgende Elemente sind in OpenOLAT gesperrt\: {0} form.managedflags.intro.short=Dieser Lektionblock wurde von einem externen Werkzeug erstellt. Einige Einstellungen k\u00F6nnen daher in OpenOLAT nicht ver\u00E4ndert werden. +in.progress=In Bearbeitung info.lecture.block.optional=Dieser Lektionenblock ist <strong>nicht</strong> obligatorisch. -info.no.lectures=Sie folgen zur Zeit kein Lektionen +info.no.lectures=Sie folgen zur Zeit keinen Lektionen +infos.participant.attendance.rate=Pers\u00F6nlicher Schwellwert: {0}% interceptor.start=Sie haben jetzt einen Lektionenblock f\u00FCr den Kurs "{0}" {1} von {4} bis {5}. -lecture.absence.default.authorized=Absenzen per default entschuldigt +lecture.absence.default.authorized=Absenzen standardm\u00E4ssig als entschuldigt z\u00E4hlen lecture.admin.course.override.title=Konfiguration - Auf Kursebene \u00FCbersteuerbar lecture.admin.enabled=Lektionen- und Absenzenmanagement einschalten lecture.admin.global.title=Globale Konfiguration @@ -84,13 +100,13 @@ lecture.block=Lektionenblock lecture.block.comment=Bemerkung lecture.block.copied=Lektionenblock wurde erfolgreich kopiert. lecture.block.copy={0} (Kopie) +lecture.block.dateAndTime={2} von {3} bis {4} Uhr lecture.block.effective.end=Effektives Ende lecture.block.effective.reason=Begr\u00FCndung -lecture.block.infos=Lehrer\: {1} von {2} {3} bis {4} lecture.block.status=Status lecture.calculate.attendance.rate.default.enabled=Berechnung der Anwesenheitsrate -lecture.can.override.standard.configuration=Standard Konfiguration \u00FCberschreiben zulassen -lecture.compulsory=Zwingend +lecture.can.override.standard.configuration=\u00DCberschreiben der Standard-Konfiguration zulassen +lecture.compulsory=Anwesehnheit obligatorisch lecture.count.authorized.absence.attendant=Entschuldigte Absenzen als anwesend z\u00E4hlen lecture.course.admin.title=Konfiguration Lektionen- und Absenzenmanagement im Kurs lecture.date=Datum @@ -107,10 +123,14 @@ lecture.reminder.period=Erinnerungsfrist lecture.rollcall.default.enabled=Anwesenheitskontrolle einschalten lecture.start=Beginn lecture.status.enabled=Lektionen Status -lecture.teacher=Lehrer +lecture.status.partially.done.enabled=Lektionen partiel durchgef\u00FChrt zulassen +lecture.teacher=Dozenten lecture.teacher.can.authorize.absence=Dozenten d\u00FCrfen Absenzen entschuldigen lecture.teacher.reminder.body=<p>Liebe Dozentin<br>Lieber Dozent</p><p>Wir m\u00F6chten Sie h\u00F6flich darin errinern, dass Sie die Absenzen f\u00FCr den im Betreff genannten Lektionenblock umgehend erfassen. Mit nachfolgendem Link gelangen Sie direkt zum entsprechenden Lektionenblock\:<br><a href\='{3}'>{3}</a></p><p>Besten Dank\!</p><p>Ihre Kursadministration</p> lecture.teacher.reminder.subject=Erinnerung Lektionenblock "{0}" +lecture.time=Zeit +lecture.time.from=von +lecture.time.until=bis lecture.title=Titel lectures.admin.reasons=Begr\u00FCndungen lectures.admin.settings=Konfiguration Lektionen- und Absenzenmanagement @@ -120,6 +140,7 @@ lectures.table.closed=Abgeschlossene Lektionenbl\u00F6cke lectures.table.current=Aktueller Lektionenblock lectures.table.next=N\u00E4chste Lektionenbl\u00F6cke lectures.table.pending=Pendente Lektionenbl\u00F6cke +log=Log managed.flags.lecture.block.all=Vollst\u00E4ndige externe Verwaltung managed.flags.lecture.block.compulsory=Zwingend managed.flags.lecture.block.dates=Datum @@ -131,23 +152,31 @@ managed.flags.lecture.block.location=Ort managed.flags.lecture.block.plannedLectures=Geplante Lektionen managed.flags.lecture.block.preparation=Vorbereitung/Nachbereitung managed.flags.lecture.block.settings=Konfiguration -managed.flags.lecture.block.teachers=Lehrer +managed.flags.lecture.block.teachers=Dozenten managed.flags.lecture.block.title=Title menu.my.lectures=Absenzen menu.my.lectures.alt=Lektionen und Absenzen new.appeal.title=Neue Rekursmeldung -next.participant=Weiter zu n\u00E4chste Teilnehmer +next.participant=Weiter zum n\u00E4chsten Teilnehmer +no.teachers=Noch kein Dozent vorhanden open=Offen open.course=Kurs \u00F6ffnen partiallydone=Teilweise erledigt participant.rate=Schwellwert +participant.rate.edit=Pers\u00F6nlicher Schwellwert pdf.table.dates={0} von {1} bis {2} -pdf.table.header.participants=Teilnehmer +pdf.table.header.all=Alle +pdf.table.header.authorised=Ent. +pdf.table.header.comment=Kommentar +pdf.table.header.participants=Vorname / Nachname +pdf.table.header.lectures=Lektionen pdf.table.header.signature=Unterschrift planned.lectures=Geplante Lektionen previous.participant=Zur\u00FCck zum letzten Teilnehmer private.dates=$org.olat.repository\:cif.private.dates public.dates=$org.olat.repository\:cif.public.dates +rate.error.title=Die Anwesenheitsquote liegt unter dem erforderlichen Limit. +rate.warning.title=Die Anwesenheitsquote ist nah am erforderlichen Limit. reason=Begr\u00FCndung reason.copied=Begr\u00FCndung wurde erfolgreich kopiert. reason.copy={0} (Kopie) @@ -156,7 +185,7 @@ reason.description=Beschreibung reason.id=ID reason.in.use=Diese Begr\u00FCndung wird noch von Lektionenblock verwendet und kann nich gel\u00F6scht werden. reason.title=Begr\u00FCndung -remove.custom.rate=Pers\u00F6nliches Schwellwert entfernen +remove.custom.rate=Pers\u00F6nlicher Schwellwert entfernen reopen=Wiederge\u00F6ffnet reopen.lecture.blocks=Lektionen wieder\u00F6ffnen repo.lectures=Lektionen @@ -172,21 +201,26 @@ rollcall.tooltip.authorized.absence=Entschuldigte Abwesenheit rollcall.tooltip.free=Freiwillig rollcall.tooltip.ok=Anwesend save.next=Speichern und weiter -save.temporary=Zwischen speichern +save.temporary=Zwischenspeichern search.form.end=Bis search.form.login=Benutzername search.form.start=Von search.form.string=Suche -search.form.string.hint=Sie k\u00F6nnen Title von Lektionbl\u00F6cke oder Title und Kennzeichen von kurse suchen. Kennzeichen ist ein exact Match. +search.form.string.hint=In der Suche können Sie nach Titeln eines Lektionenblockes oder nach der Externen Referenz suchen. Bei der Suche mit der Externen Referenz werden nur exakte Treffer angezeigt. +start.desktop=Desktop +start.label=Absenzen erfassen +start.mobile=Mobile start.wizard=Wizard starten sync.course.calendar.enabled=Kurs Kalender synchronisieren sync.participants.calendar.enabled=Teilnehmer Kalender synchronisieren -sync.teachers.calendar.enabled=Lehrer Kalender synchronisieren +sync.teachers.calendar.enabled=Dozentenkalender synchronisieren table.header.absence=Anwesenheit table.header.absent.lectures=Abwesend table.header.actions=<i class\='o_icon o_icon_actions o_icon-lg'> </i> table.header.attended.lectures=Anwesend table.header.authorized.absence=Entschuldigt +table.header.unauthorized.absence=Unentschuldigt +table.header.auto.close.date=Auto closed am table.header.comment=Kommentar table.header.compulsory=<i class\='o_icon o_icon_compulsory o_icon-lg'> </i> table.header.date=Datum @@ -196,8 +230,9 @@ table.header.effective.lectures=Lektionen table.header.end.time=Bis table.header.entry=Kurs table.header.export=Export -table.header.external.ref=Ext. Ref. +table.header.external.ref=Kennzeichen table.header.id=ID +table.header.infos=<i class='o_icon o_icon-lg o_icon_info'> </i> table.header.lecture.1=1 table.header.lecture.10=10 table.header.lecture.11=11 @@ -214,9 +249,15 @@ table.header.lecture.8=8 table.header.lecture.9=9 table.header.lecture.block=Lektionenblock table.header.location=Ort +table.header.log.action=Aktion +table.header.log.author=Autor \u00C4nderung +table.header.log.effective.end.date=Effektives Enddatum +table.header.log.effective.lectures=Effektive Lektionen +table.header.log.planned.lectures=Geplante Lektionen +table.header.log.user=Benutzer table.header.planned.lectures=Lektionen table.header.presence=Abwesenheit -table.header.progress=Forschritt +table.header.progress=Fortschritt table.header.rate=Anwesenheit table.header.rate.warning=<i class\="o_icon o_midwarn"> </i> table.header.start.time=Von @@ -224,7 +265,12 @@ table.header.status=Status table.header.teachers=Dozenten table.header.tools=<i class\='o_icon o_icon_actions o_icon-lg'> </i> table.header.username=Benutzername +table.legend.absent=Abwesend +table.legend.attended=Anwesend +table.legend.authorized=Entschuldigte Abwesenheit +table.legend.free=Freiwillige Veranstalltung tool.participant=Als Teilnehmer tool.teacher=Als Dozent tools=Aktion total=Total +warning.edit.lecture=Absenzenerfassung ist deaktiviert. diff --git a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_en.properties index 1634a2e8fcf1d4fbea416723d6b9fb747da373d0..a647c3e80ab66e336dfe076c21e46e10969a1e91 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_en.properties @@ -1,17 +1,28 @@ -#Tue Jul 04 10:07:47 CEST 2017 +#Thu Aug 03 10:50:01 CEST 2017 active=Active -add.lecture=New lectures block +add.lecture=New lecture block add.reason=Add reason admin.menu.title=Lectures admin.menu.title.alt=Lectures and absence management aggregated.list=Aggregated list all=All +all.desc=Mark all lectures as absent all.teachers.switch=All teachers +all.teachers.switch.tooltip.off=Show all lecture blocks +all.teachers.switch.tooltip.on=Show only my lecture blocks appeal=Appeal +appeal.body=<p>Dear {1}</p> +appeal.closed=Closed appeal.contact.list=Teacher +appeal.from=From {0} appeal.subject=Appeal lecture block "{0}" appeal.title=Appeal for\: "{0}" -attendance.list=Attendance list +appeal.tooltip=Appeal possible from {0} until {1} +archive.entry=Archive +attendance.list=Absence list +attendance.list.title=Absence list: {0} +attendance.list.to.sign=Attendance list +attendance.list.to.sign.title=Attendance list: {0} authorized.absence=Authorized authorized.absence.reason=Reason autoclosed=Auto-closed @@ -50,45 +61,51 @@ edit.reason=Edit reason effective.lectures=Effective lectures empty.lectures.list=The tabel is empty empty.repository.entry.lectures=You haven't need to follow a lecture in the course. -empty.table.current.lectures.blocks=There is any lectures blocks to start at the moment. -empty.table.lectures.blocks=There isn't any lectures blocks. +empty.table.current.lectures.blocks=There are not lectures to start at the moment. +empty.table.lectures.blocks=There are no lectures to display. +empty.table.lectures.blocks.admin=No lecture blocks have been created for this course so far. +empty.table.participant.list=No roll calls have been made for this course so far. entry.rate=Course's rate -error.atleastone.lecture=Please, choose at least one lectures block. +error.atleastone.lecture=Please choose at least one lecture block. error.integer.between=The input must be a number between {0} and {1} error.integer.positive=The number must be positive. error.reason.mandatory=Reason is mandatory error.search.form.notempty=$org.olat.admin.user\:error.search.form.notempty export.footer.lectures.hint=x \= lecture absent +export.header.entry=Course\: {0} export.header.lectureblocks=Lectures block\: {0} the {1} at {2} until {3} -export.header.lectures=Lektionen +export.header.lectures=Lectures export.header.location=Room\: {0} export.header.teachers=Teachers\: {0} -filter.mandatory=Mandatory\t +filter.mandatory=Compulsory filter.showAll=Show all first.admission=First admission form.managedflags.intro=This lecture block has been created by an external tool. Therefore some settings and modules can not be modified and used within OpenOLAT. The following elements are blocked within OpenOLAT\: {0} form.managedflags.intro.short=This lecture block has been created by an external tool. Therefore some settings can not be modified and used within OpenOLAT. +in.progress=In process info.lecture.block.optional=This lecture block is optional. info.no.lectures=You don't follow any lectures for the moment. +infos.participant.attendance.rate=Personal attendance rate\: {0}% interceptor.start=You have now a roll call for the course "{0}" {1} from {4} until {5}. lecture.absence.default.authorized=Absence per default authorized -lecture.admin.course.override.title=Configuration - can be override at course level +lecture.admin.course.override.title=Configuration - can be overridden at course level lecture.admin.enabled=Enable lectures and absence management lecture.admin.global.title=Global configuration lecture.appeal.absence.enabled=Appeal absence enabled -lecture.appeal.absence.period=Appeal absence period -lecture.attendance.rate.default=Absence quota global in % +lecture.appeal.absence.period=Appeal absence period in days +lecture.attendance.rate.default=Attendance quota global in % lecture.authorized.absence.enabled=Authorized absences -lecture.auto.close.period=Auto close period +lecture.auto.close.period=Auto close period in days lecture.block=Lectures block lecture.block.comment=Comment lecture.block.copied=The lectures block was successfully copied. lecture.block.copy={0} (Copy) +lecture.block.dateAndTime={2} from {3} to {4} lecture.block.effective.end=Effective end lecture.block.effective.reason=Reason -lecture.block.infos=Teachers\: {1} from {2} {3} until {4} lecture.block.status=Status lecture.calculate.attendance.rate.default.enabled=Calculate attendance rate (default) +lecture.can.override.standard.configuration=Allow override of configuration lecture.compulsory=Compulsory lecture.count.authorized.absence.attendant=Count authorized absence as attendant lecture.course.admin.title=Configuration of lectures and absence management in course @@ -102,23 +119,28 @@ lecture.groups=Course / groups lecture.location=Location lecture.preparation=Preparation lecture.reminder.enabled=Reminder enabled -lecture.reminder.period=Reminder period +lecture.reminder.period=Reminder period in days lecture.rollcall.default.enabled=Roll call enabled (default) lecture.start=Begin lecture.status.enabled=Lectures status +lecture.status.partially.done.enabled=Allow holding partial lectures lecture.teacher=Teacher -lecture.teacher.can.authorize.absence=Teachers can authorize absences +lecture.teacher.can.authorize.absence=Coaches can authorize absences lecture.teacher.reminder.body=Reminder lectures block "{0}" in course {3} lecture.teacher.reminder.subject=Reminder lectures block "{0}" +lecture.time=Time +lecture.time.from=from +lecture.time.until=until lecture.title=Title lectures.admin.reasons=Reasons -lectures.admin.settings=Seetings lectures and absence management +lectures.admin.settings=Settings lectures and absence management lectures.print.title=Lectures and absences of {0} lectures.repository.print.title=Lectures and absences of {1} in course {0} -lectures.table.closed=Closed lectures blocks -lectures.table.current=Current lectures block -lectures.table.next=Next lectures blocks -lectures.table.pending=Pending lectures blocks +lectures.table.closed=Closed lecture blocks +lectures.table.current=Current lecture block +lectures.table.next=Next lecture blocks +lectures.table.pending=Pending lecture blocks +log=Log managed.flags.lecture.block.all=Fully externally managed managed.flags.lecture.block.compulsory=Compulsory managed.flags.lecture.block.dates=Dates @@ -136,17 +158,25 @@ menu.my.lectures=Absences menu.my.lectures.alt=Lectures and absences new.appeal.title=New appeal next.participant=To the next participant +no.teachers=No coaches yet open=Open open.course=Open course partiallydone=Partially done participant.rate=Rate +participant.rate.edit=Personal rate pdf.table.dates={0} from {1} to {2} -pdf.table.header.participants=Participants +pdf.table.header.authorised=Auth. +pdf.table.header.all=All +pdf.table.header.comment=Comment +pdf.table.header.participants=First name / last name +pdf.table.header.lectures=Lectures pdf.table.header.signature=Signature planned.lectures=Planned lectures previous.participant=Back to previous participant private.dates=$org.olat.repository\:cif.private.dates public.dates=$org.olat.repository\:cif.public.dates +rate.error.title=The attendance rate is under the mandatory limit. +rate.warning.title=The attendance rate is close to the mandatory limit. reason=Reason reason.copied=Reason was successsfully copied. reason.copy={0} (Copy) @@ -159,7 +189,7 @@ remove.custom.rate=Remove custom rate reopen=Reopen reopen.lecture.blocks=Reopen lectures repo.lectures=Lectures -repo.lectures.block=Lectures blocs +repo.lectures.block=Lecture blocks repo.participants=Participants repo.settings=Configuration results=Results @@ -177,6 +207,9 @@ search.form.login=Username search.form.start=Start search.form.string=Search search.form.string.hint=You can search title of lecture blocks and title or external reference of courses. External reference is an exact match. +start.desktop=Desktop +start.label=Roll call +start.mobile=Mobile start.wizard=Start wizard sync.course.calendar.enabled=Synchronize courses calendars sync.participants.calendar.enabled=Synchronize participants calendars @@ -186,6 +219,8 @@ table.header.absent.lectures=Absent table.header.actions=<i class\='o_icon o_icon_actions o_icon-lg'> </i> table.header.attended.lectures=Attended table.header.authorized.absence=Excused +table.header.unauthorized.absence=Not excused +table.header.auto.close.date=Auto closed at table.header.comment=Comment table.header.compulsory=<i class\='o_icon o_icon_compulsory o_icon-lg'> </i> table.header.date=Date @@ -197,6 +232,7 @@ table.header.entry=Course table.header.export=Export table.header.external.ref=Ext. ref. table.header.id=ID +table.header.infos=<i class\='o_icon o_icon-lg o_icon_info'> </i> table.header.lecture.1=1 table.header.lecture.10=10 table.header.lecture.11=11 @@ -213,6 +249,12 @@ table.header.lecture.8=8 table.header.lecture.9=9 table.header.lecture.block=Lecture block table.header.location=Location +table.header.log.action=Action +table.header.log.author=Changed by +table.header.log.effective.end.date=Effective end date +table.header.log.effective.lectures=Effective lectures +table.header.log.planned.lectures=Planned lectures +table.header.log.user=User table.header.planned.lectures=Lectures table.header.presence=Present table.header.progress=Grafik @@ -223,7 +265,12 @@ table.header.status=Status table.header.teachers=Coaches table.header.tools=<i class\='o_icon o_icon_actions o_icon-lg'> </i> table.header.username=Username +table.legend.absent=Absent +table.legend.attended=Attended +table.legend.authorized=Authorized absence +table.legend.free=Free lecture tool.participant=As participant tool.teacher=As teacher tools=Action total=Total +warning.edit.lecture=Roll call ist deactivated. diff --git a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_fr.properties index 9ffa3d118dc51902d87cb55f0f427320bf46c7fc..fb187bd581f866d95c198e2b15a6f4287a416166 100644 --- a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_fr.properties @@ -1,4 +1,268 @@ -error.search.form.notempty=$org.olat.admin.user:error.search.form.notempty -form.managedflags.intro=Ce bloc de leçons a \u00E9t\u00E9 cr\u00E9\u00E9 par un outil externe. Certains r\u00E9glages et modules ne peuvent pas \u00EAtre modifi\u00E9s et utilis\u00E9s dans OpenOLAT. Les \u00E9l\u00E9ments suivants sont bloqu\u00E9s dans OpenOLAT\: {0} +#Sun Aug 27 19:27:16 CEST 2017 +active=Actif +add.lecture=Cr\u00E9er un nouveau cours bloc +add.reason=Cr\u00E9er une justification +admin.menu.title=Cours blocs +admin.menu.title.alt=Administration des cours blocs et absences +aggregated.list=Liste consolid\u00E9e +all=Tous +all.desc=Marqu\u00E9 toutes les le\u00E7ons comme absence +all.teachers.switch=Tous les charg\u00E9s de cours +all.teachers.switch.tooltip.off=Montrer tous les cours blocs +all.teachers.switch.tooltip.on=Montrer seulement mes cours blocs +appeal=Recours +appeal.closed=Termin\u00E9 +appeal.contact.list=Charg\u00E9 de cours +appeal.from=Depuis le {0} +appeal.subject=Recours cours bloc "{0}" +appeal.title=Recours pour\: "{0}" +appeal.tooltip=Recours possible du {0} au {1} +archive.entry=Archivage +attendance.list=Liste d'absences +attendance.list.to.sign=Liste de pr\u00E9sence +authorized.absence=Excus\u00E9 +authorized.absence.reason=Justification +autoclosed=Termin\u00E9 automatiquement +bulk=Nom d'utilisateur, $org.olat.user.propertyhandlers\:table.name.email ou $org.olat.user.propertyhandlers\:table.name.institutionalUserIdentifier +bulk.example=test01<br>author02<br>test@openolat.org +bulk.hint=Vous pouvez entrer une liste de noms d'utilisateurs ou d'adresses courriels dans ce champ de recherche. +cancel.lecture.blocks=Annuler le cours bloc +cancelled=Annul\u00E9 +close.lecture.blocks=Termin\u00E9 le cours bloc +closed=Termin\u00E9 +config.calculate.attendance.rate=Calculer le taux de pr\u00E9sence +config.override=Permettre de modifier la configuration standard +config.override.no=Non +config.override.yes=Oui +config.rollcall.enabled=Activer le contr\u00F4le du taux de pr\u00E9sence +config.sync.course.calendar=Synchroniser le calendrier du cours +config.sync.participant.calendar=Synchroniser le calendrier des participants +config.sync.teacher.calendar=Synchroniser le calendrier des charg\u00E9s de cours +confirm.delete.lectures=Voulez-vous vraiment effacer ce cours block "{0}"? +confirm.delete.reason=Voulez-vous vraiment effacer cette justification "{0}"? +copy=Copier +current.lecture=Cours bloc actuel +date.end=$org.olat.repository\:cif.date.end +date.start=$org.olat.repository\:cif.date.start +dates=$org.olat.repository\:cif.dates +dates.none=$org.olat.repository\:cif.dates.none +dates.private=$org.olat.repository\:cif.dates.private +dates.public=$org.olat.repository\:cif.dates.public +delete.lectures.title=Effacer un cours bloc +delete.title=Effacer une justification +detailled.list=Liste d\u00E9taill\u00E9e +details=D\u00E9tails +done=Termin\u00E9 +edit.participant.rate=Editer la valeur seuil personalis\u00E9e +edit.reason=Editer la justification +effective.lectures=Le\u00E7ons effectives +empty.lectures.list=La liste est vide +empty.repository.entry.lectures=Vous n'avez pas encore de le\u00E7ons dans ce cours. +empty.table.current.lectures.blocks=Vous n'avez aucun cours bloc actuellement. +empty.table.lectures.blocks=Aucun cours bloc n'a \u00E9t\u00E9 trouv\u00E9. +empty.table.lectures.blocks.admin=Aucun cours bloc n'a \u00E9t\u00E9 cr\u00E9\u00E9 pour ce cours. +empty.table.participant.list=Aucun contr\u00F4le de pr\u00E9sence n'a \u00E9t\u00E9 effectu\u00E9 pour ce cours jusqu'\u00E0 maintenant. +entry.rate=Valeur seuil pour le cours +error.atleastone.lecture=Choisissez au moins un cours bloc s'il vous pla\u00EEt. +error.integer.between=La valeur doit \u00EAtre un nombre entre {0} et {1} +error.integer.positive=La valeur doit \u00EAtre un nombre positif. +error.reason.mandatory=La justification est requis. +error.search.form.notempty=$org.olat.admin.user\:error.search.form.notempty +export.footer.lectures.hint=x \= Absence +export.header.entry=Cours\: {0} +export.header.lectureblocks=Cours bloc\: {0} de {1} de {2} \u00E0 {3} +export.header.lectures=Cours blocs +export.header.location=Salle\: {0} +export.header.teachers=Charg\u00E9s de cours\: {0} +filter.mandatory=Pr\u00E9sence obligatoire +filter.showAll=Tout montrer +first.admission=Premi\u00E8re admission +form.managedflags.intro=Ce bloc de le\u00E7ons a \u00E9t\u00E9 cr\u00E9\u00E9 par un outil externe. Certains r\u00E9glages et modules ne peuvent pas \u00EAtre modifi\u00E9s et utilis\u00E9s dans OpenOLAT. Les \u00E9l\u00E9ments suivants sont bloqu\u00E9s dans OpenOLAT\: {0} +form.managedflags.intro.short=Ce cours bloc a \u00E9t\u00E9 cr\u00E9\u00E9 par un outil externe. Ses param\u00E8tres ne peuvent donc pas \u00EAtre chang\u00E9s dans OpenOLAT. +in.progress=En cours +info.lecture.block.optional=Ce cours bloc n'est <strong>pas</strong> obligatoire. +info.no.lectures=Vous ne suivez pour l'instant aucun cours bloc. +infos.participant.attendance.rate=Valeur seuil personelle\: {0}% +interceptor.start=Vous avez un cours bloc pour le cours "{0}" {1} de {4} \u00E0 {5}. +lecture.absence.default.authorized=Compter les absences par d\u00E9faut comme excus\u00E9es +lecture.admin.course.override.title=Configuration - modifiable au niveau du cours +lecture.admin.enabled=Activer l'administration des cours blocs et des absences +lecture.admin.global.title=Configuration globale +lecture.appeal.absence.enabled=Activer la possibilit\u00E9 de recours +lecture.appeal.absence.period=D\u00E9lai de recours +lecture.attendance.rate.default=Taux de pr\u00E9sence global en % +lecture.authorized.absence.enabled=Absences excus\u00E9es +lecture.auto.close.period=D\u00E9lai pour bloquer le cours bloc +lecture.block=Cours blocs +lecture.block.comment=Remarques +lecture.block.copied=Le cours bloc a \u00E9t\u00E9 copi\u00E9 avec succ\u00E8s. +lecture.block.copy={0} (copie) +lecture.block.dateAndTime={2} de {3} jusqu'\u00E0 {4} heure +lecture.block.effective.end=Fin effective +lecture.block.effective.reason=Justification +lecture.block.status=Status +lecture.calculate.attendance.rate.default.enabled=Calcul du taux de pr\u00E9sence +lecture.can.override.standard.configuration=Permettre de modifier la configuration standard +lecture.compulsory=Pr\u00E9sence obligatoire +lecture.count.authorized.absence.attendant=Compter les absences excus\u00E9es comme pr\u00E9sent +lecture.course.admin.title=Configuration des cours blocs et absences du cours +lecture.date=Date +lecture.deleted=Cours bloc a \u00E9t\u00E9 effac\u00E9 avec succ\u00E8s. +lecture.descr=Description +lecture.end=Fin +lecture.from.to=Depuis +lecture.from.to.format={0} jusqu'\u00E0 {1} +lecture.groups=Cours / groupes +lecture.location=Lieu +lecture.preparation=Pr\u00E9paration/suivi +lecture.reminder.enabled=Activ\u00E9 la fonction de rappel +lecture.reminder.period=D\u00E9lai de rappel +lecture.rollcall.default.enabled=Activer le contr\u00F4le de pr\u00E9sence +lecture.start=D\u00E9but +lecture.status.enabled=Status +lecture.status.partially.done.enabled=Activer la possibilit\u00E9 de le\u00E7ons partielles +lecture.teacher=Charg\u00E9s de cours +lecture.teacher.can.authorize.absence=Les charg\u00E9s de cours peuvent excuser les absences +lecture.teacher.reminder.body=<p>Ch\u00E8re charg\u00E9e de cours<br>Cher charg\u00E9 de cours</p><p>Nous aimerions vous rappeler que vous devez encore noter les absences pour un cours bloc. Avec le lien ci-dessous vous m\u00E8nera directement au cours bloc en question\:<br><a href\='{3}'>{3}</a></p><p>Merci beaucoup\!</p><p>Votre administrateur de cours</p> +lecture.teacher.reminder.subject=Rappel cours bloc "{0}" +lecture.time=Temps +lecture.time.from=de +lecture.time.until=jusqu'\u00E0 +lecture.title=Titre +lectures.admin.reasons=Justifications +lectures.admin.settings=Configuration de l'administration des cours blocs et des absences +lectures.print.title=Cours blocs et absences de {0} +lectures.repository.print.title=Cours blocs et absences de {1} pour le cours\: {0} +lectures.table.closed=Cours blocs termin\u00E9s +lectures.table.current=Cours blocs en cours +lectures.table.next=Prochains cours blocs +lectures.table.pending=Cours blocs en attente +log=Log +managed.flags.lecture.block.all=Gestion externe compl\u00E8te +managed.flags.lecture.block.compulsory=Obligatoire +managed.flags.lecture.block.dates=Date +managed.flags.lecture.block.delete=Effacer le cours bloc +managed.flags.lecture.block.description=Description +managed.flags.lecture.block.details=Titre, description... +managed.flags.lecture.block.groups=Cours / groupes +managed.flags.lecture.block.location=Lieu +managed.flags.lecture.block.plannedLectures=Cours blocs pr\u00E9vus +managed.flags.lecture.block.preparation=Pr\u00E9paration/suivi +managed.flags.lecture.block.settings=Configuration +managed.flags.lecture.block.teachers=Charg\u00E9s de cours +managed.flags.lecture.block.title=Titre +menu.my.lectures=Absences +menu.my.lectures.alt=Cours blocs et absences +new.appeal.title=Nouvelle notification de recours +next.participant=Participant suivant +no.teachers=Pas encore de charg\u00E9 de cours disponible +open=Ouvert +open.course=Cours ouvert +partiallydone=En partie termin\u00E9 +participant.rate=Valeur seuil +participant.rate.edit=Valeur seuil personelle +pdf.table.dates={0} de {1} jusqu'\u00E0 {2} +pdf.table.header.participants=Pr\u00E9nom / nom de famille +pdf.table.header.signature=Signature +planned.lectures=Cours blocs pr\u00E9vus +previous.participant=Participant pr\u00E9c\u00E9dent +private.dates=$org.olat.repository\:cif.private.dates +public.dates=$org.olat.repository\:cif.public.dates +rate.error.title=Le taux de pr\u00E9sence se situe sous la limite obligatoire. +rate.warning.title=Le taux de pr\u00E9sence est proche de la limite obligatoire. +reason=Justification +reason.copied=La justification a \u00E9t\u00E9 copi\u00E9e avec succ\u00E8s. +reason.copy={0} (copie) +reason.deleted=La justification a \u00E9t\u00E9 effac\u00E9e avec succ\u00E8s. +reason.description=Description +reason.id=ID +reason.in.use=Cette justification est encore utilis\u00E9e par un ou plusieurs cours blocs et ne peut pas \u00EAtre effac\u00E9e. +reason.title=Justification +remove.custom.rate=Enlever la valeur seuil personnelle +reopen=R\u00E9ouvert +reopen.lecture.blocks=R\u00E9ouvrir un cours bloc +repo.lectures=Cours blocs +repo.lectures.block=Cours blocs +repo.participants=Participants +repo.settings=Configuration +results=R\u00E9sultats +rollcall=Contr\u00F4le de pr\u00E9sence +rollcall.comment=Remarque +rollcall.status=Status du cours bloc +rollcall.tooltip.absence=Absence +rollcall.tooltip.authorized.absence=Absence excus\u00E9e +rollcall.tooltip.free=Facultatif +rollcall.tooltip.ok=Pr\u00E9sent +save.next=Sauver et continuer +save.temporary=Sauver temporairement +search.form.end=Jusqu'\u00E0 +search.form.login=Nom d'utilisateur +search.form.start=De +search.form.string=Recherche +search.form.string.hint=Vous pouvez chercher les titres d'un bloc de cours ou sa r\u00E9f\u00E9rence externe. Lors de la recherche avec la r\u00E9f\u00E9rence externe, seuls les r\u00E9sultats exacts sont affich\u00E9s. +start.desktop=Bureau +start.label=Noter les absences +start.mobile=Mobile +start.wizard=D\u00E9marrer l'assistant +sync.course.calendar.enabled=Synchroniser le calendrier du cours +sync.participants.calendar.enabled=Synchroniser le calendrier des participants +sync.teachers.calendar.enabled=Synchroniser le calendrier des charg\u00E9s de cours +table.header.absence=Pr\u00E9sences +table.header.absent.lectures=Absences table.header.actions=<i class\='o_icon o_icon_actions o_icon-lg'> </i> +table.header.attended.lectures=Pr\u00E9sent +table.header.authorized.absence=Excus\u00E9 +table.header.auto.close.date=Termin\u00E9 automatiquement le +table.header.comment=Commentaire +table.header.compulsory=<i class\='o_icon o_icon_compulsory o_icon-lg'> </i> +table.header.date=Date +table.header.details=<i class\='o_icon o_icon_lecture o_icon-lg'> </i> table.header.edit=<i class\='o_icon o_icon_edit o_icon-lg'> </i> +table.header.effective.lectures=Le\u00E7ons +table.header.end.time=Jusqu'\u00E0 +table.header.entry=Cours +table.header.export=Exporter +table.header.external.ref=R\u00E9f. ext. +table.header.id=ID +table.header.infos=<i class\='o_icon o_icon-lg o_icon_info'> </i> +table.header.lecture.1=1 +table.header.lecture.10=10 +table.header.lecture.11=11 +table.header.lecture.12=12 +table.header.lecture.13=13 +table.header.lecture.14=14 +table.header.lecture.2=2 +table.header.lecture.3=3 +table.header.lecture.4=4 +table.header.lecture.5=5 +table.header.lecture.6=6 +table.header.lecture.7=7 +table.header.lecture.8=8 +table.header.lecture.9=9 +table.header.lecture.block=Cours bloc +table.header.location=Lieu +table.header.log.action=Action +table.header.log.author=Changements +table.header.log.effective.end.date=Date effective de fin +table.header.log.effective.lectures=Le\u00E7ons effectives +table.header.log.planned.lectures=Le\u00E7ons pr\u00E9vues +table.header.log.user=Utilisateur +table.header.planned.lectures=Le\u00E7ons +table.header.presence=Pr\u00E9sence +table.header.progress=Graphe +table.header.rate=Pr\u00E9sence +table.header.rate.warning=<i class\="o_icon o_midwarn"> </i> +table.header.start.time=De +table.header.status=Status +table.header.teachers=Charg\u00E9s de cours +table.header.tools=<i class\='o_icon o_icon_actions o_icon-lg'> </i> +table.header.username=Nom d'utilisateur +table.legend.absent=Absent +table.legend.attended=Pr\u00E9sent +table.legend.authorized=Absence autoris\u00E9e +table.legend.free=Le\u00E7on facultative +tool.participant=Comme participant +tool.teacher=Comme charg\u00E9 de cours +tools=Action +total=Total +warning.edit.lecture=Le contr\u00F4le d'absence est d\u00E9sactiv\u00E9. diff --git a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_pt_BR.properties new file mode 100644 index 0000000000000000000000000000000000000000..43eb7c004ae3eea0ea26640a3dbdf42fea978b4b --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_pt_BR.properties @@ -0,0 +1,266 @@ +#Tue Sep 05 22:43:52 CEST 2017 +active=Ativo +add.lecture=Novo bloco de aulas +add.reason=Adicionar motivo +admin.menu.title=Palestras +admin.menu.title.alt=Gest\u00E3o de aulas e faltas (aus\u00EAncias) +aggregated.list=Lista agregada +all=Todos +all.desc=Marcar faltas em todas as aulas +all.teachers.switch=Todos professores +all.teachers.switch.tooltip.off=Mostrar todos os blocos de aulas +all.teachers.switch.tooltip.on=Mostre apenas os meus blocos de aulas +appeal=Recurso +appeal.closed=Fechado +appeal.contact.list=Professor +appeal.from=De {0} +appeal.subject=Apelar pelo bloco de aula "{0}" +appeal.title=Recurso para\: {0} +appeal.tooltip=Recurso poss\u00EDvel de {0} at\u00E9 {1} +archive.entry=Arquivo +authorized.absence=Autorizado +authorized.absence.reason=Motivo +autoclosed=Auto-Fechado +bulk=Usu\u00E1rios, $org.olat.user.propertyhandlers\:table.name.email ou $org.olat.user.propertyhandlers\:table.name.institutionalUserIdentifier +bulk.example=test01<br>author02<br>test@openolat.org +bulk.hint=Voc\u00EA pode fornecer uma lista de nomes de usu\u00E1rios ou endere\u00E7os de e-mail separados por uma quebra de linha [enter]. +cancel.lecture.blocks=Cancelar aulas (li\u00E7\u00F5es) +cancelled=Cancelado +close.lecture.blocks=Encerrar aulas +closed=Fechado +config.calculate.attendance.rate=Calcular a taxa de presen\u00E7a +config.override=Substituir a configura\u00E7\u00E3o padr\u00E3o +config.override.no=N\u00E3o +config.override.yes=Sim +config.rollcall.enabled=Roll call ativado +config.sync.course.calendar=Sincronizar o calend\u00E1rio do curso +config.sync.participant.calendar=Sincronizar calend\u00E1rio de participantes +config.sync.teacher.calendar=Sincronizar o calend\u00E1rio do professor +confirm.delete.lectures=Voc\u00EA realmente deseja excluir essas aulas "{0}"? +confirm.delete.reason=Voc\u00EA realmente deseja excluir esse motivo "{0}"? +copy=Copiar +current.lecture=Aulas atuais +date.end=$org.olat.repository\:cif.date.end +date.start=$org.olat.repository\:cif.date.start +dates=$org.olat.repository\:cif.dates +dates.none=$org.olat.repository\:cif.dates.none +dates.private=$org.olat.repository\:cif.dates.private +dates.public=$org.olat.repository\:cif.dates.public +delete.lectures.title=Excluir aulas (li\u00E7\u00F5es) +delete.title=Excluir motivo +detailled.list=Lista detalhada +details=Detalhes +done=Pronto +edit.participant.rate=Editar avalia\u00E7\u00E3o do participante +edit.reason=Editar motivo +effective.lectures=Aulas efetivas +empty.lectures.list=A tabela est\u00E1 vazia +empty.repository.entry.lectures=Voc\u00EA n\u00E3o precisa seguir uma aula no curso. +empty.table.current.lectures.blocks=N\u00E3o h\u00E1 aulas para come\u00E7ar no momento. +empty.table.lectures.blocks=N\u00E3o h\u00E1 aulas para exibir. +empty.table.lectures.blocks.admin=N\u00E3o foram criados blocos de aulas (li\u00E7\u00F5es) neste curso at\u00E9 agora. +empty.table.participant.list=N\u00E3o foram feitas chamadas (roll calls) neste curso at\u00E9 agora. +entry.rate=Avalia\u00E7\u00E3o dos cursos +error.atleastone.lecture=Escolha pelo menos um bloco de aulas. +error.integer.between=A inser\u00E7\u00E3o precisa ser um n\u00FAmero entre {0} e {1} +error.integer.positive=O n\u00FAmero precisa ser positivo +error.reason.mandatory=O motivo \u00E9 obrigat\u00F3rio +error.search.form.notempty=$org.olat.admin.user\:error.search.form.notempty +export.footer.lectures.hint=x \= aula ausente +export.header.entry=Curso\: {0} +export.header.lectureblocks=Bloco de aulas\: {0} o {1} em {2} at\u00E9 {3} +export.header.lectures=Aulas +export.header.location=Sala\: {0} +export.header.teachers=Professores\: {0} +filter.mandatory=Compuls\u00F3rio +filter.showAll=Mostrar tudo +first.admission=Primeira admiss\u00E3o +form.managedflags.intro=Este bloco de aula foi criado por uma ferramenta externa. Portanto, algumas configura\u00E7\u00F5es e m\u00F3dulos n\u00E3o podem ser modificados e usados \u200B\u200Bno OpenOLAT. Os seguintes elementos s\u00E3o bloqueados no OpenOLAT\: {0} +form.managedflags.intro.short=Este bloco de aulas foi criado por uma ferramenta externa. Portanto, algumas configura\u00E7\u00F5es n\u00E3o podem ser modificadas e usadas no OpenOLAT. +in.progress=Processando +info.lecture.block.optional=Este bloco de aula \u00E9 opcional. +info.no.lectures=Voc\u00EA n\u00E3o segue nenhuma aula neste momento. +infos.participant.attendance.rate=Taxa de presen\u00E7a pessoal\: {0}% +interceptor.start=Voc\u00EA j\u00E1 tem uma chamada para o curso "{0}" {1} de {4} at\u00E9 {5}. +lecture.absence.default.authorized=Aus\u00EAncia por padr\u00E3o autorizada +lecture.admin.course.override.title=Configura\u00E7\u00E3o - pode ser substitu\u00EDda no n\u00EDvel do curso +lecture.admin.enabled=Ativar aulas e gerenciamento de aus\u00EAncias +lecture.admin.global.title=Configura\u00E7\u00E3o global +lecture.appeal.absence.enabled=Ativar recurso / apelo por aus\u00EAncia +lecture.appeal.absence.period=Prazo para recurso de aus\u00EAncias (em dias) +lecture.attendance.rate.default=Quota global de presen\u00E7a em % +lecture.authorized.absence.enabled=Aus\u00EAncias autorizadas +lecture.auto.close.period=Encerramento autom\u00E1tico em dias +lecture.block=Bloco de aulas +lecture.block.comment=Coment\u00E1rio +lecture.block.copied=O bloco de aulas foi copiado com sucesso. +lecture.block.copy={0} (C\u00F3pia) +lecture.block.dateAndTime={2} de {3} at\u00E9 {4} Horas +lecture.block.effective.end=Final efetivo +lecture.block.effective.reason=Motivo +lecture.block.status=Status +lecture.calculate.attendance.rate.default.enabled=Calcular a taxa de presen\u00E7a (padr\u00E3o) +lecture.can.override.standard.configuration=Permitir substitui\u00E7\u00E3o da configura\u00E7\u00E3o +lecture.compulsory=Compuls\u00F3rio +lecture.count.authorized.absence.attendant=Contar a aus\u00EAncia autorizada como atendente +lecture.course.admin.title=Configura\u00E7\u00E3o de aulas e gerenciamento de aus\u00EAncias em curso +lecture.date=Data +lecture.deleted=Aulas foram exclu\u00EDdas com sucesso +lecture.descr=Descri\u00E7\u00E3o +lecture.end=Fim +lecture.from.to=Tempo de\: +lecture.from.to.format={0} at\u00E9 {1} +lecture.groups=Curso / grupos +lecture.location=Localiza\u00E7\u00E3o +lecture.preparation=Prepara\u00E7\u00E3o +lecture.reminder.enabled=Lembrete ativo +lecture.reminder.period=Per\u00EDodo de lembrete em dias +lecture.rollcall.default.enabled=Chamada (Roll Call) ativa (padr\u00E3o) +lecture.start=In\u00EDcio +lecture.status.enabled=Status da aula +lecture.status.partially.done.enabled=Permitir realiza\u00E7\u00E3o de aulas parciais +lecture.teacher=Professor +lecture.teacher.can.authorize.absence=Treinadores (coa\u00E7\u00F5es) podem autorizar aus\u00EAncias (faltas) +lecture.teacher.reminder.body=Lembre de blocos de aula "{0}" no curso {3} +lecture.teacher.reminder.subject=Lembrete de blocos de aula \u201C{0}\u201D +lecture.time=Tempo +lecture.time.from=de +lecture.time.until=at\u00E9 +lecture.title=T\u00EDtulo +lectures.admin.reasons=Motivos +lectures.admin.settings=Configura\u00E7\u00F5es de gerenciamento de aulas e aus\u00EAncias +lectures.print.title=Aulas e aus\u00EAncias de {0} +lectures.repository.print.title=Aulas e aus\u00EAncias de {1} no curso {0} +lectures.table.closed=Blocos de aulas encerrados +lectures.table.current=Bloco de aulas atuais +lectures.table.next=Pr\u00F3ximo bloco de aulas +lectures.table.pending=Bloco de aulas pendentes +log=Log +managed.flags.lecture.block.all=Totalmente gerenciado externamente +managed.flags.lecture.block.compulsory=Compuls\u00F3rio +managed.flags.lecture.block.dates=Datas +managed.flags.lecture.block.delete=Excluir bloco de aulas +managed.flags.lecture.block.description=Descri\u00E7\u00E3o +managed.flags.lecture.block.details=T\u00EDtulo, descri\u00E7\u00E3o... +managed.flags.lecture.block.groups=Curso / grupos +managed.flags.lecture.block.location=Localiza\u00E7\u00E3o +managed.flags.lecture.block.plannedLectures=Aulas planejadas +managed.flags.lecture.block.preparation=Prepara\u00E7\u00E3o +managed.flags.lecture.block.settings=Configura\u00E7\u00E3o +managed.flags.lecture.block.teachers=Professor +managed.flags.lecture.block.title=T\u00EDtulo +menu.my.lectures=Aus\u00EAncias (faltas) +menu.my.lectures.alt=Aulas e aus\u00EAncias (faltas) +new.appeal.title=Novo recurso (apela\u00E7\u00E3o) +next.participant=Para o pr\u00F3ximo participante +no.teachers=Nenhum treinador ainda +open=Abrir +open.course=Abrir curso +partiallydone=Parcialmente feito +participant.rate=Avalia\u00E7\u00E3o +participant.rate.edit=Avalia\u00E7\u00E3o pessoal +pdf.table.dates={0} de {1} at\u00E9 {2} +pdf.table.header.participants=Participantes +pdf.table.header.signature=Assinatura +planned.lectures=Aulas planejadas +previous.participant=Voltar ao participante anterior +private.dates=$org.olat.repository\:cif.private.dates +public.dates=$org.olat.repository\:cif.public.dates +rate.error.title=A taxa de presen\u00E7a est\u00E1 abaixo do limite obrigat\u00F3rio. +rate.warning.title=A taxa de presen\u00E7a est\u00E1 pr\u00F3xima do limite obrigat\u00F3rio. +reason=Motivo +reason.copied=O motivo foi copiado com sucesso. +reason.copy={0} (C\u00F3pia) +reason.deleted=O motivo foi exclu\u00EDdo com sucesso. +reason.description=Descri\u00E7\u00E3o +reason.id=ID +reason.in.use=Este motivo ainda \u00E9 usado por algumas aulas e n\u00E3o pode ser exclu\u00EDdo. +reason.title=Motivo +remove.custom.rate=Excluir avalia\u00E7\u00E3o customizada +reopen=Reabrir +reopen.lecture.blocks=Reabrir aulas +repo.lectures=Aulas +repo.lectures.block=Bloco de aulas +repo.participants=Participantes +repo.settings=Configura\u00E7\u00E3o +results=Resultados +rollcall=Chamada (Roll Call) +rollcall.comment=Comente +rollcall.status=Status da chamada +rollcall.tooltip.absence=Ausente +rollcall.tooltip.authorized.absence=Aus\u00EAncia autorizada +rollcall.tooltip.free=Livre +rollcall.tooltip.ok=Presente +save.next=Salvar e pr\u00F3ximo +save.temporary=Salvamento r\u00E1pido +search.form.end=At\u00E9 +search.form.login=Usu\u00E1rio +search.form.start=Come\u00E7ar +search.form.string=Buscar +search.form.string.hint=Voc\u00EA pode pesquisar o t\u00EDtulo de blocos de aulas e t\u00EDtulo ou refer\u00EAncia externa de cursos. A refer\u00EAncia externa precisa ser uma correspond\u00EAncia exata. +start.desktop=Desktop +start.label=Chamada (Roll Call) +start.mobile=Mobile +start.wizard=Iniciar Assistente +sync.course.calendar.enabled=Sincronizar calend\u00E1rios de cursos +sync.participants.calendar.enabled=Sincronizar calend\u00E1rios de participantes +sync.teachers.calendar.enabled=Sincronizar calend\u00E1rios de professores +table.header.absence=Aus\u00EAncias (faltas) +table.header.absent.lectures=Aus\u00EAnte +table.header.actions=<i class\='o_icon o_icon_actions o_icon-lg'> </i> +table.header.attended.lectures=Participaram +table.header.authorized.absence=Justificado +table.header.auto.close.date=Encerrado automaticamente em +table.header.comment=Comente +table.header.compulsory=<i class\='o_icon o_icon_compulsory o_icon-lg'> </i> +table.header.date=Data +table.header.details=<i class\='o_icon o_icon_lecture o_icon-lg'> </i> +table.header.edit=<i class\='o_icon o_icon_edit o_icon-lg'> </i> +table.header.effective.lectures=Aulas +table.header.end.time=Para +table.header.entry=Curso +table.header.export=Exportar +table.header.external.ref=Ref. ext. +table.header.id=ID +table.header.infos=<i class\='o_icon o_icon-lg o_icon_info'> </i> +table.header.lecture.1=1 +table.header.lecture.10=10 +table.header.lecture.11=11 +table.header.lecture.12=12 +table.header.lecture.13=13 +table.header.lecture.14=14 +table.header.lecture.2=2 +table.header.lecture.3=3 +table.header.lecture.4=4 +table.header.lecture.5=5 +table.header.lecture.6=6 +table.header.lecture.7=7 +table.header.lecture.8=8 +table.header.lecture.9=9 +table.header.lecture.block=Bloco de aulas +table.header.location=Localiza\u00E7\u00E3o +table.header.log.action=A\u00E7\u00E3o +table.header.log.author=Modificado por +table.header.log.effective.end.date=Data efetiva de t\u00E9rmino +table.header.log.effective.lectures=Aulas efetivas +table.header.log.planned.lectures=Aulas planejadas +table.header.log.user=Usu\u00E1rio +table.header.planned.lectures=Aulas +table.header.presence=Presente +table.header.progress=Gr\u00E1fico +table.header.rate=Presen\u00E7a +table.header.rate.warning=<i class\="o_icon o_midwarn"> </i> +table.header.start.time=De +table.header.status=Status +table.header.teachers=Treinadores +table.header.tools=<i class\='o_icon o_icon_actions o_icon-lg'> </i> +table.header.username=Usu\u00E1rio +table.legend.absent=Ausente +table.legend.attended=Participaram +table.legend.authorized=Falta autorizada +table.legend.free=Aula livre +tool.participant=Como participante +tool.teacher=Como professor +tools=A\u00E7\u00E3o +total=Total +warning.edit.lecture=Chamada (Roll Call) est\u00E1 inativa diff --git a/src/main/java/org/olat/modules/lecture/ui/component/LectureBlockRollCallStatusCellRenderer.java b/src/main/java/org/olat/modules/lecture/ui/component/LectureBlockRollCallStatusCellRenderer.java index da171eca63dd8d3956c63b8f33ae76ae0cba7d49..e5986014265ea3e3d1a09a343be368d857ed39c7 100644 --- a/src/main/java/org/olat/modules/lecture/ui/component/LectureBlockRollCallStatusCellRenderer.java +++ b/src/main/java/org/olat/modules/lecture/ui/component/LectureBlockRollCallStatusCellRenderer.java @@ -25,7 +25,10 @@ import org.olat.core.gui.render.Renderer; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; +import org.olat.modules.lecture.LectureBlockStatus; +import org.olat.modules.lecture.LectureRollCallStatus; import org.olat.modules.lecture.model.LectureBlockAndRollCall; +import org.olat.modules.lecture.ui.LectureBlockAndRollCallRow; /** * @@ -35,52 +38,79 @@ import org.olat.modules.lecture.model.LectureBlockAndRollCall; */ public class LectureBlockRollCallStatusCellRenderer implements FlexiCellRenderer { + private final Translator translator; private final boolean authorizedAbsenceEnabled; private final boolean absenceDefaultAuthorized; - public LectureBlockRollCallStatusCellRenderer(boolean authorizedAbsenceEnabled, boolean absenceDefaultAuthorized) { + public LectureBlockRollCallStatusCellRenderer(boolean authorizedAbsenceEnabled, boolean absenceDefaultAuthorized, + Translator translator) { this.authorizedAbsenceEnabled = authorizedAbsenceEnabled; this.absenceDefaultAuthorized = absenceDefaultAuthorized; + this.translator = translator; } @Override public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, - URLBuilder ubu, Translator translator) { - if(cellValue instanceof LectureBlockAndRollCall) { - LectureBlockAndRollCall rollCall = (LectureBlockAndRollCall)cellValue; - if(rollCall.isRollCalled()) { - int numOfLectures = rollCall.getEffectiveLecturesNumber(); - if(numOfLectures < 0) { - numOfLectures = rollCall.getPlannedLecturesNumber(); - } - - String title; - String iconCssClass; - if(rollCall.isCompulsory()) { - if(rollCall.getLecturesAttendedNumber() >= numOfLectures) { - iconCssClass = "o_lectures_rollcall_ok"; - title = translator.translate("rollcall.tooltip.ok"); - } else if(authorizedAbsenceEnabled) { - if(absenceDefaultAuthorized && rollCall.getLecturesAuthorizedAbsent() == null) { - iconCssClass = "o_lectures_rollcall_ok"; - title = translator.translate("rollcall.tooltip.ok"); - } else if(rollCall.getLecturesAuthorizedAbsent() != null && rollCall.getLecturesAuthorizedAbsent().booleanValue()) { - iconCssClass = "o_lectures_rollcall_warning"; - title = translator.translate("rollcall.tooltip.authorized.absence"); - } else { - iconCssClass = "o_lectures_rollcall_danger"; - title = translator.translate("rollcall.tooltip.absence"); - } - } else { - iconCssClass = "o_lectures_rollcall_danger"; - title = translator.translate("rollcall.tooltip.absence"); - } + URLBuilder ubu, Translator trans) { + if(cellValue instanceof LectureBlockAndRollCallRow) { + LectureBlockAndRollCallRow rollCallRow = (LectureBlockAndRollCallRow)cellValue; + render(target, rollCallRow.getRow()); + } else if(cellValue instanceof LectureBlockAndRollCall) { + render(target, (LectureBlockAndRollCall)cellValue); + } + } + + private void render(StringOutput target, LectureBlockAndRollCall rollCall) { + if(rollCall.isRollCalled()) { + LectureBlockStatus status = rollCall.getStatus(); + LectureRollCallStatus rollCallStatus = rollCall.getRollCallStatus(); + if(status == LectureBlockStatus.cancelled) { + String title = translator.translate("cancelled"); + target.append("<span title='").append(title).append("'><i class='o_icon o_icon-lg o_icon_cancelled'> </i></span>"); + } else if(status == LectureBlockStatus.done + && (rollCallStatus == LectureRollCallStatus.closed || rollCallStatus == LectureRollCallStatus.autoclosed)) { + renderClosed(target, rollCall); + } else { + String title = translator.translate("in.progress"); + target.append("<span title='").append(title).append("'><i class='o_icon o_icon-lg o_icon_status_in_review'> </i></span>"); + } + } else if(!rollCall.isCompulsory()) { + String title = translator.translate("rollcall.tooltip.free"); + target.append("<span title='").append(title).append("'><i class='o_icon o_icon-lg o_lectures_rollcall_free'> </i></span>"); + } + } + + private void renderClosed(StringOutput target, LectureBlockAndRollCall rollCall) { + int numOfLectures = rollCall.getEffectiveLecturesNumber(); + if(numOfLectures < 0) { + numOfLectures = rollCall.getPlannedLecturesNumber(); + } + + String title; + String iconCssClass; + if(rollCall.isCompulsory()) { + if(rollCall.getLecturesAttendedNumber() >= numOfLectures) { + iconCssClass = "o_lectures_rollcall_ok"; + title = translator.translate("rollcall.tooltip.ok"); + } else if(authorizedAbsenceEnabled) { + if(absenceDefaultAuthorized && rollCall.getLecturesAuthorizedAbsent() == null) { + iconCssClass = "o_lectures_rollcall_ok"; + title = translator.translate("rollcall.tooltip.ok"); + } else if(rollCall.getLecturesAuthorizedAbsent() != null && rollCall.getLecturesAuthorizedAbsent().booleanValue()) { + iconCssClass = "o_lectures_rollcall_warning"; + title = translator.translate("rollcall.tooltip.authorized.absence"); } else { - iconCssClass = "o_lectures_rollcall_free"; - title = translator.translate("rollcall.tooltip.free"); + iconCssClass = "o_lectures_rollcall_danger"; + title = translator.translate("rollcall.tooltip.absence"); } - target.append("<span title='").append(title).append("'><i class='o_icon o_icon-lg ").append(iconCssClass).append("'> </i></span>"); + } else { + iconCssClass = "o_lectures_rollcall_danger"; + title = translator.translate("rollcall.tooltip.absence"); } + } else { + iconCssClass = "o_lectures_rollcall_free"; + title = translator.translate("rollcall.tooltip.free"); } + target.append("<span title='").append(title).append("'><i class='o_icon o_icon-lg ").append(iconCssClass).append("'> </i></span>"); } } diff --git a/src/main/java/org/olat/modules/lecture/ui/component/LectureBlockRollCallStatusComponentRenderer.java b/src/main/java/org/olat/modules/lecture/ui/component/LectureBlockRollCallStatusComponentRenderer.java index 41b6e45f79ce4ee34152d577c032739b38ca857c..cca367d8b860c1ff5b629154dddb3539f2e21d0a 100644 --- a/src/main/java/org/olat/modules/lecture/ui/component/LectureBlockRollCallStatusComponentRenderer.java +++ b/src/main/java/org/olat/modules/lecture/ui/component/LectureBlockRollCallStatusComponentRenderer.java @@ -49,9 +49,14 @@ public class LectureBlockRollCallStatusComponentRenderer extends DefaultComponen iconCssClass = "o_lectures_rollcall_ok"; title = cmp.getTranslator().translate("rollcall.tooltip.ok"); } else if(cmp.isAuthorizedAbsenceEnabled()) { - if(cmp.isAbsenceDefaultAuthorized() && !cmp.isLecturesAuthorizedAbsent()) { - iconCssClass = "o_lectures_rollcall_ok"; - title = cmp.getTranslator().translate("rollcall.tooltip.ok"); + if(cmp.isAbsenceDefaultAuthorized()) { + if(cmp.isLecturesAuthorizedAbsent() || cmp.getRollCall().getRollCall().getAbsenceAuthorized() == null) { + iconCssClass = "o_lectures_rollcall_warning"; + title = cmp.getTranslator().translate("rollcall.tooltip.authorized.absence"); + } else { + iconCssClass = "o_lectures_rollcall_danger"; + title = cmp.getTranslator().translate("rollcall.tooltip.absence"); + } } else if(cmp.isLecturesAuthorizedAbsent()) { iconCssClass = "o_lectures_rollcall_warning"; title = cmp.getTranslator().translate("rollcall.tooltip.authorized.absence"); diff --git a/src/main/java/org/olat/modules/lecture/ui/component/LecturesCompulsoryRenderer.java b/src/main/java/org/olat/modules/lecture/ui/component/LecturesCompulsoryRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..b3ce392cc02c7897669ea890080ad25a286370d0 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/component/LecturesCompulsoryRenderer.java @@ -0,0 +1,57 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.component; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.modules.lecture.ui.LectureBlockAndRollCallRow; + +/** + * + * Initial date: 17 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LecturesCompulsoryRenderer implements FlexiCellRenderer { + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, + URLBuilder ubu, Translator translator) { + if(cellValue != null) { + Object obj = source.getFlexiTableElement().getTableDataModel().getObject(row); + if(obj instanceof LectureBlockAndRollCallRow) { + LectureBlockAndRollCallRow rollCallRow = (LectureBlockAndRollCallRow)obj; + if(!rollCallRow.getRow().isCompulsory()) { + target.append("<span class='o_lecture_free'>") + .append(cellValue.toString()) + .append(" *</span>"); + } else { + target.append(cellValue.toString()); + } + } else { + target.append(cellValue.toString()); + } + } + } +} diff --git a/src/main/java/org/olat/modules/lecture/ui/component/ParticipantInfosRenderer.java b/src/main/java/org/olat/modules/lecture/ui/component/ParticipantInfosRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..083ad071111ce9bfa5e4cb9014c0ba6913d37e3a --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/component/ParticipantInfosRenderer.java @@ -0,0 +1,69 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.component; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.core.util.StringHelper; +import org.olat.modules.lecture.ui.ParticipantRow; + +/** + * + * Initial date: 18 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ParticipantInfosRenderer implements FlexiCellRenderer { + + private int count = 0; + private final Translator translator; + private final double defaultAttendanceRate; + + public ParticipantInfosRenderer(Translator translator, double defaultAttendanceRate) { + this.translator = translator; + this.defaultAttendanceRate = defaultAttendanceRate; + } + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, + URLBuilder ubu, Translator trans) { + if(cellValue instanceof ParticipantRow) { + ParticipantRow participantRow = (ParticipantRow)cellValue; + double requiredRate = participantRow.getStatistics().getRequiredRate(); + if(requiredRate >= 0.0d && Math.abs(defaultAttendanceRate - requiredRate) > 0.0001) { + String id = "p_infos_" + ++count; + target.append("<span id='").append(id).append("'><i class='o_icon o_icon-lg o_icon_info'> </i></span>"); + + // Attach bootstrap tooltip handler to help icon + double percent = requiredRate * 100.0d; + long rounded = Math.round(percent); + String rateInfos = translator.translate("infos.participant.attendance.rate", new String[] { Long.toString(rounded) }); + + target.append("<script>jQuery(function () {jQuery('#").append(id).append("').tooltip({placement:\"top\",container: \"body\",html:true,title:\"") + .append(StringHelper.escapeJavaScript(rateInfos)) + .append("\"});})</script>"); + } + } + } +} diff --git a/src/main/java/org/olat/modules/lecture/ui/component/RateWarningCellRenderer.java b/src/main/java/org/olat/modules/lecture/ui/component/RateWarningCellRenderer.java index 61fd6745dcaa81613f960a44ed3000aafb62b3b9..ba2184eca262423f48042308d6dd107903218707 100644 --- a/src/main/java/org/olat/modules/lecture/ui/component/RateWarningCellRenderer.java +++ b/src/main/java/org/olat/modules/lecture/ui/component/RateWarningCellRenderer.java @@ -34,10 +34,16 @@ import org.olat.modules.lecture.model.LectureBlockStatistics; * */ public class RateWarningCellRenderer implements FlexiCellRenderer { + + private final Translator translator; + + public RateWarningCellRenderer(Translator translator) { + this.translator = translator; + } @Override public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, - URLBuilder ubu, Translator translator) { + URLBuilder ubu, Translator trans) { if(cellValue instanceof LectureBlockStatistics) { LectureBlockStatistics stats = (LectureBlockStatistics)cellValue; @@ -47,9 +53,11 @@ public class RateWarningCellRenderer implements FlexiCellRenderer { double requiredRate = stats.getRequiredRate(); if(requiredRate > attendanceRate) { - target.append("<i class='o_icon o_icon-lg o_icon_error'> </i>"); + String title = translator.translate("rate.error.title"); + target.append("<i class='o_icon o_icon-lg o_icon_error' title='").append(title).append("'> </i>"); } else if(attendanceRate - requiredRate < 0.05) {// less than 5% - target.append("<i class='o_icon o_icon-lg o_icon_warning'> </i>"); + String title = translator.translate("rate.warning.title"); + target.append("<i class='o_icon o_icon-lg o_icon_warning' title='").append(title).append("'> </i>"); } } } diff --git a/src/main/java/org/olat/modules/lecture/ui/export/AbstractLectureBlockAuditLogExport.java b/src/main/java/org/olat/modules/lecture/ui/export/AbstractLectureBlockAuditLogExport.java new file mode 100644 index 0000000000000000000000000000000000000000..d35a43ad974c5f718539f6592ae12da65c4fd8de --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/export/AbstractLectureBlockAuditLogExport.java @@ -0,0 +1,256 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.export; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.translator.Translator; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.openxml.OpenXMLWorkbook; +import org.olat.core.util.openxml.OpenXMLWorkbookResource; +import org.olat.core.util.openxml.OpenXMLWorksheet; +import org.olat.core.util.openxml.OpenXMLWorksheet.Row; +import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; +import org.olat.modules.lecture.LectureBlockRef; +import org.olat.modules.lecture.LectureBlockRollCall; +import org.olat.modules.lecture.LectureService; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; +import org.olat.user.UserManager; + +import edu.emory.mathcs.backport.java.util.Collections; + +/** + * + * + * + * Initial date: 12 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public abstract class AbstractLectureBlockAuditLogExport extends OpenXMLWorkbookResource { + + private static final OLog log = Tracing.createLoggerFor(LectureBlockAuditLogExport.class); + + protected final Translator translator; + + private final List<LectureBlockAuditLog> auditLog; + private Map<Long,String> displayNames = new HashMap<>(); + private Map<Long,String> lectureBlockTitles = new HashMap<>(); + + protected final UserManager userManager; + protected final LectureService lectureService; + protected final RepositoryManager repositoryManager; + + public AbstractLectureBlockAuditLogExport(String name, List<LectureBlockAuditLog> auditLog, Translator translator) { + super(name); + this.auditLog = auditLog; + this.translator = translator; + userManager = CoreSpringFactory.getImpl(UserManager.class); + lectureService = CoreSpringFactory.getImpl(LectureService.class); + repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class); + } + + @Override + protected void generate(OutputStream out) { + Collections.sort(auditLog, new LectureBlockAuditLogComparator()); + try(OpenXMLWorkbook workbook = new OpenXMLWorkbook(out, 1)) { + OpenXMLWorksheet exportSheet = workbook.nextWorksheet(); + addSheetSettings(exportSheet); + addHeaders(exportSheet); + addHeader(exportSheet); + addContent(exportSheet, workbook); + } catch (IOException e) { + log.error("", e); + } catch (Exception e) { + log.error("", e); + } + } + + protected void addSheetSettings(OpenXMLWorksheet exportSheet) { + exportSheet.setColumnWidth(1, 16);//width date time + exportSheet.setColumnWidth(8, 16);//width date time + } + + protected abstract void addHeaders(OpenXMLWorksheet exportSheet); + + private void addHeader(OpenXMLWorksheet exportSheet) { + exportSheet.setHeaderRows(2); + + Row headerRow = exportSheet.newRow(); + + int pos = 0; + headerRow.addCell(pos++, translator.translate("table.header.date"));//creationDate + headerRow.addCell(pos++, translator.translate("table.header.log.action"));//action + + headerRow.addCell(pos++, translator.translate("table.header.entry"));//repository entry title + headerRow.addCell(pos++, translator.translate("table.header.lecture.block"));//lecture block title + + //audit block + headerRow.addCell(pos++, translator.translate("table.header.status"));//lecture block status + headerRow.addCell(pos++, translator.translate("table.header.log.planned.lectures"));//lecture block planned lectures + headerRow.addCell(pos++, translator.translate("table.header.log.effective.lectures"));//lecture block effective lectures + headerRow.addCell(pos++, translator.translate("table.header.log.effective.end.date"));//lecture block effective end date + + //audit roll call + headerRow.addCell(pos++, translator.translate("table.header.log.user"));//roll call user + headerRow.addCell(pos++, translator.translate("table.header.attended.lectures"));//roll call attended + headerRow.addCell(pos++, translator.translate("table.header.absent.lectures"));//roll call absent + headerRow.addCell(pos++, translator.translate("table.header.authorized.absence"));//roll call authorized + headerRow.addCell(pos++, translator.translate("authorized.absence.reason"));//roll call reason + headerRow.addCell(pos++, translator.translate("rollcall.comment"));//roll call comment + + //author + headerRow.addCell(pos++, translator.translate("table.header.log.author"));//author + } + + private void addContent(OpenXMLWorksheet exportSheet, OpenXMLWorkbook workbook) { + + for(LectureBlockAuditLog logEntry:auditLog) { + int pos = 0; + Row row = exportSheet.newRow(); + Date creationDate = logEntry.getCreationDate(); + row.addCell(pos++, creationDate, workbook.getStyles().getDateTimeStyle()); + row.addCell(pos++, logEntry.getAction()); + + //repo entry title + row.addCell(pos++, getRepositoryEntryDisplayName(logEntry.getEntryKey()), null); + //lecture block + row.addCell(pos++, getLectureBlockTitle(logEntry.getLectureBlockKey()), null); + //date start / end + + //planned / effective + LectureBlock auditBlock = null; + LectureBlockRollCall auditRollCall = null; + if(logEntry.getRollCallKey() != null) { + auditRollCall = getAuditRollCall(logEntry.getAfter()); + } + if(auditRollCall == null) { + auditBlock = getAuditLectureBlock(logEntry.getAfter()); + } + + if(auditBlock != null) { + if(auditBlock.getStatus() == null) { + pos++; + } else { + row.addCell(pos++, auditBlock.getStatus().name(), null); + } + row.addCell(pos++, auditBlock.getPlannedLecturesNumber(), null); + row.addCell(pos++, auditBlock.getEffectiveLecturesNumber(), null); + row.addCell(pos++, auditBlock.getEffectiveEndDate(), workbook.getStyles().getDateTimeStyle()); + } else { + pos += 4; + } + + if(auditRollCall != null) { + Long assessedIdentityKey = logEntry.getIdentityKey(); + String fullname = userManager.getUserDisplayName(assessedIdentityKey); + row.addCell(pos++, fullname); + row.addCell(pos++, auditRollCall.getLecturesAttendedNumber(), null); + row.addCell(pos++, auditRollCall.getLecturesAbsentNumber(), null); + if(auditRollCall.getAbsenceAuthorized() != null && auditRollCall.getAbsenceAuthorized().booleanValue()) { + row.addCell(pos++, "x"); + } else { + pos++; + } + row.addCell(pos++, auditRollCall.getAbsenceReason(), null); + row.addCell(pos++, auditRollCall.getComment(), null); + } else { + pos += 6; + } + + Long authorKey = logEntry.getAuthorKey(); + if(authorKey != null) { + String fullname = userManager.getUserDisplayName(authorKey); + row.addCell(pos++, fullname); + } + } + } + + private LectureBlockRollCall getAuditRollCall(String xml) { + return lectureService.toAuditLectureBlockRollCall(xml); + } + + private LectureBlock getAuditLectureBlock(String xml) { + return lectureService.toAuditLectureBlock(xml); + } + + protected void cacheRepositoryEntry(RepositoryEntry entry) { + if(entry != null) { + displayNames.put(entry.getKey(), entry.getDisplayname()); + } + } + + private String getRepositoryEntryDisplayName(Long entryKey) { + + String displayName = displayNames.get(entryKey); + if(displayName == null) { + displayName = repositoryManager.lookupDisplayName(entryKey); + if(!StringHelper.containsNonWhitespace(displayName)) { + displayName = entryKey.toString(); + } + displayNames.put(entryKey, displayName); + } + return displayName; + } + + protected void cacheLectureBlock(LectureBlock lectureBlock) { + if(lectureBlock != null) { + lectureBlockTitles.put(lectureBlock.getKey(), lectureBlock.getTitle()); + } + } + + private String getLectureBlockTitle(Long lectureBlockKey) { + String title = lectureBlockTitles.get(lectureBlockKey); + if(title == null) { + LectureBlock block = lectureService.getLectureBlock(new LectureBlockRefForLog(lectureBlockKey)); + if(block == null) { + title = lectureBlockKey.toString(); + } else { + title = block.getTitle(); + } + lectureBlockTitles.put(lectureBlockKey, title); + } + return title; + } + + private static class LectureBlockRefForLog implements LectureBlockRef { + + private Long key; + + public LectureBlockRefForLog(Long key) { + this.key = key; + } + + @Override + public Long getKey() { + return key; + } + } +} diff --git a/src/main/java/org/olat/modules/lecture/ui/export/IdentityAuditLogExport.java b/src/main/java/org/olat/modules/lecture/ui/export/IdentityAuditLogExport.java new file mode 100644 index 0000000000000000000000000000000000000000..17dfa9aa96cf711cfd0ecd7c5da4059f2e166905 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/export/IdentityAuditLogExport.java @@ -0,0 +1,69 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.export; + +import java.util.Date; +import java.util.List; + +import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.core.util.openxml.OpenXMLWorksheet; +import org.olat.core.util.openxml.OpenXMLWorksheet.Row; +import org.olat.modules.lecture.LectureBlockAuditLog; + +/** + * + * + * Initial date: 12 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class IdentityAuditLogExport extends AbstractLectureBlockAuditLogExport { + + private Identity identity; + + public IdentityAuditLogExport(Identity identity, List<LectureBlockAuditLog> auditLog, Translator translator) { + super(label(identity), auditLog, translator); + this.identity = identity; + } + + private static final String label(Identity identity) { + return StringHelper.transformDisplayNameToFileSystemName(identity.getUser().getLastName()) + + "_" + StringHelper.transformDisplayNameToFileSystemName(identity.getUser().getFirstName()) + + "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) + + ".xlsx"; + } + + @Override + protected void addSheetSettings(OpenXMLWorksheet exportSheet) { + exportSheet.setHeaderRows(2); + super.addSheetSettings(exportSheet); + } + + @Override + protected void addHeaders(OpenXMLWorksheet exportSheet) { + Row headerRow = exportSheet.newRow(); + + int pos = 0; + headerRow.addCell(pos++, userManager.getUserDisplayName(identity)); + } +} diff --git a/src/main/java/org/olat/modules/lecture/ui/export/LectureBlockAuditLogComparator.java b/src/main/java/org/olat/modules/lecture/ui/export/LectureBlockAuditLogComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..0eb1da70663424895839240de5572f1d3ea40835 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/export/LectureBlockAuditLogComparator.java @@ -0,0 +1,50 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.export; + + +import java.util.Comparator; +import java.util.Date; + +import org.olat.modules.lecture.LectureBlockAuditLog; + +/** + * + * Initial date: 11 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LectureBlockAuditLogComparator implements Comparator<LectureBlockAuditLog> { + + @Override + public int compare(LectureBlockAuditLog o1, LectureBlockAuditLog o2) { + if(o1 == null && o2 == null) return 0; + if(o1 == null) return -1; + if(o2 == null) return 1; + + Date d1 = o1.getCreationDate(); + Date d2 = o2.getCreationDate(); + if(d1 == null && d2 == null) return 0; + if(d1 == null) return -1; + if(d2 == null) return 1; + return d1.compareTo(d2); + } + +} diff --git a/src/main/java/org/olat/modules/lecture/ui/export/LectureBlockAuditLogExport.java b/src/main/java/org/olat/modules/lecture/ui/export/LectureBlockAuditLogExport.java new file mode 100644 index 0000000000000000000000000000000000000000..8027b3813cd308aef45711d83f3d75af0c6f72de --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/export/LectureBlockAuditLogExport.java @@ -0,0 +1,81 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.export; + +import java.util.Date; +import java.util.List; + +import org.olat.core.gui.translator.Translator; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.core.util.openxml.OpenXMLWorksheet; +import org.olat.core.util.openxml.OpenXMLWorksheet.Row; +import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 7 avr. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LectureBlockAuditLogExport extends AbstractLectureBlockAuditLogExport { + + private RepositoryEntry entry; + private LectureBlock lectureBlock; + + public LectureBlockAuditLogExport(RepositoryEntry entry, LectureBlock lectureBlock, List<LectureBlockAuditLog> auditLog, Translator translator) { + super(label(lectureBlock), auditLog, translator); + this.entry = entry; + this.lectureBlock = lectureBlock; + cacheLectureBlock(lectureBlock); + cacheRepositoryEntry(entry); + } + + private static final String label(LectureBlock lectureBlock) { + return StringHelper.transformDisplayNameToFileSystemName(lectureBlock.getTitle()) + + "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) + + ".xlsx"; + } + + @Override + protected void addSheetSettings(OpenXMLWorksheet exportSheet) { + exportSheet.setHeaderRows(2); + super.addSheetSettings(exportSheet); + } + + @Override + protected void addHeaders(OpenXMLWorksheet exportSheet) { + Row headerRow = exportSheet.newRow(); + + int pos = 0; + headerRow.addCell(pos++, translator.translate("export.header.entry", new String[] { entry.getDisplayname() })); + + Formatter formatter = Formatter.getInstance(translator.getLocale()); + String[] args = new String[] { + lectureBlock.getTitle(), + formatter.formatDate(lectureBlock.getStartDate()), + formatter.formatTimeShort(lectureBlock.getStartDate()), + formatter.formatTimeShort(lectureBlock.getEndDate()) + }; + headerRow.addCell(pos++, translator.translate("export.header.lectureblocks", args)); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/LectureBlockExport.java b/src/main/java/org/olat/modules/lecture/ui/export/LectureBlockExport.java similarity index 95% rename from src/main/java/org/olat/modules/lecture/ui/LectureBlockExport.java rename to src/main/java/org/olat/modules/lecture/ui/export/LectureBlockExport.java index c74b265db23c46471a506e0ca72c437163acbb71..b9e6492f5b3d38c8401a59123e80353f36d46f2c 100644 --- a/src/main/java/org/olat/modules/lecture/ui/LectureBlockExport.java +++ b/src/main/java/org/olat/modules/lecture/ui/export/LectureBlockExport.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.lecture.ui; +package org.olat.modules.lecture.ui.export; import java.io.IOException; import java.io.OutputStream; @@ -40,6 +40,7 @@ import org.olat.core.util.openxml.OpenXMLWorksheet.Row; import org.olat.modules.lecture.LectureBlock; import org.olat.modules.lecture.LectureBlockRollCall; import org.olat.modules.lecture.LectureService; +import org.olat.modules.lecture.ui.ParticipantListRepositoryController; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -86,17 +87,21 @@ public class LectureBlockExport extends OpenXMLWorkbookResource { protected void generate(OutputStream out) { try(OpenXMLWorkbook workbook = new OpenXMLWorkbook(out, 1)) { OpenXMLWorksheet exportSheet = workbook.nextWorksheet(); - exportSheet.setHeaderRows(3); - addHeaders_1(exportSheet); - addHeaders_2(exportSheet); - addHeaders_3(exportSheet); - addContent(exportSheet); - addFooter(exportSheet); + generate(exportSheet); } catch (IOException e) { log.error("", e); } } + protected void generate(OpenXMLWorksheet exportSheet) { + exportSheet.setHeaderRows(3); + addHeaders_1(exportSheet); + addHeaders_2(exportSheet); + addHeaders_3(exportSheet); + addContent(exportSheet); + addFooter(exportSheet); + } + private void addFooter(OpenXMLWorksheet exportSheet) { exportSheet.newRow(); exportSheet.newRow(); @@ -230,6 +235,4 @@ public class LectureBlockExport extends OpenXMLWorkbookResource { } } } - - } diff --git a/src/main/java/org/olat/modules/lecture/ui/export/LecturesBlockPDFExport.java b/src/main/java/org/olat/modules/lecture/ui/export/LecturesBlockPDFExport.java new file mode 100644 index 0000000000000000000000000000000000000000..19608faf642c9b001c2c5d8bd50c6a8f36e43bf4 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/export/LecturesBlockPDFExport.java @@ -0,0 +1,508 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.export; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.TransformerException; + +import org.apache.pdfbox.exceptions.COSVisitorException; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; +import org.olat.core.id.User; +import org.olat.core.id.UserConstants; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.core.util.pdf.PdfDocument; +import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockRollCall; +import org.olat.repository.RepositoryEntry; + +import edu.emory.mathcs.backport.java.util.Arrays; + +/** + * + * Initial date: 22 juin 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LecturesBlockPDFExport extends PdfDocument implements MediaResource { + + private static final OLog log = Tracing.createLoggerFor(LecturesBlockPDFExport.class); + + private String teacher; + private int numOfLectures; + private final Translator translator; + private final LectureBlock lectureBlock; + private final RepositoryEntry entry; + private final boolean authorizedAbsenceEnabled; + + public LecturesBlockPDFExport(LectureBlock lectureBlock, boolean authorizedAbsenceEnabled, Translator translator) + throws IOException { + super(translator.getLocale()); + + marginTopBottom = 62.0f; + marginLeftRight = 62.0f; + entry = lectureBlock.getEntry(); + this.translator = translator; + this.lectureBlock = lectureBlock; + this.authorizedAbsenceEnabled = authorizedAbsenceEnabled; + + numOfLectures = lectureBlock.getEffectiveLecturesNumber(); + if(numOfLectures <= 0) { + numOfLectures = lectureBlock.getPlannedLecturesNumber(); + } + } + + public String getTeacher() { + return teacher; + } + + public void setTeacher(String teacher) { + this.teacher = teacher; + } + + @Override + public boolean acceptRanges() { + return false; + } + + @Override + public String getContentType() { + return "application/pdf"; + } + + @Override + public Long getSize() { + return null; + } + + @Override + public InputStream getInputStream() { + return null; + } + + @Override + public Long getLastModified() { + return null; + } + + @Override + public void prepare(HttpServletResponse hres) { + try { + Formatter formatter = Formatter.getInstance(translator.getLocale()); + String filename = lectureBlock.getTitle() + + "_" + formatter.formatDate(lectureBlock.getStartDate()) + + "_" + formatter.formatTimeShort(lectureBlock.getStartDate()) + + "-" + formatter.formatTimeShort(lectureBlock.getEndDate()) + + ".pdf"; + hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(filename)); + hres.setHeader("Content-Description",StringHelper.urlEncodeUTF8(filename)); + document.save(hres.getOutputStream()); + } catch (COSVisitorException | IOException e) { + log.error("", e); + } + } + + @Override + public void release() { + try { + close(); + } catch (IOException e) { + log.error("", e); + } + } + + public void create(List<Identity> rows, List<LectureBlockRollCall> rollCalls) + throws IOException, COSVisitorException, TransformerException { + addPageLandscape(); + String lectureBlockTitle = lectureBlock.getTitle(); + String resourceTitle = entry.getDisplayname(); + addMetadata(lectureBlockTitle, resourceTitle, teacher); + + String title = resourceTitle + " - " + lectureBlockTitle; + title = translator.translate("attendance.list.title", new String[] { title }); + addParagraph(title, 16, true, width); + + Formatter formatter = Formatter.getInstance(translator.getLocale()); + String dates = translator.translate("pdf.table.dates", new String[] { + formatter.formatDate(lectureBlock.getStartDate()), + formatter.formatTimeShort(lectureBlock.getStartDate()), + formatter.formatTimeShort(lectureBlock.getEndDate()) + }); + + addParagraph(dates, 12, true, width); + + float cellMargin = 5.0f; + float fontSize = 10.0f; + + Row[] content = getRows(rows, rollCalls); + + int numOfRows = content.length; + for(int offset=0; offset<numOfRows; ) { + offset += drawTable(content, offset, fontSize, cellMargin); + closePage(); + if(offset<numOfRows) { + addPageLandscape(); + } + } + + addPageNumbers(); + } + + private Row[] getRows(List<Identity> rows, List<LectureBlockRollCall> rollCalls) { + int numOfRows = rows.size(); + Map<Identity,LectureBlockRollCall> rollCallMap = new HashMap<>(); + for(LectureBlockRollCall rollCall:rollCalls) { + rollCallMap.put(rollCall.getIdentity(), rollCall); + } + + Row[] content = new Row[numOfRows]; + for(int i=0; i<numOfRows; i++) { + Identity row = rows.get(i); + String fullname = getName(row); + + String comment = null; + boolean authorised = false; + boolean[] absences = new boolean[numOfLectures]; + Arrays.fill(absences, false); + + LectureBlockRollCall rollCall = rollCallMap.get(rows.get(i)); + if(rollCall != null) { + if(rollCall.getLecturesAbsentList() != null) { + List<Integer> absenceList = rollCall.getLecturesAbsentList(); + for(int j=0; j<numOfLectures; j++) { + absences[j] = absenceList.contains(new Integer(j)); + } + } + if(rollCall.getAbsenceAuthorized() != null) { + authorised = rollCall.getAbsenceAuthorized().booleanValue(); + } + if(StringHelper.containsNonWhitespace(rollCall.getComment())) { + comment = rollCall.getComment(); + } + } + content[i] = new Row(fullname, absences, authorised, comment); + } + + return content; + } + + private String getName(Identity identity) { + StringBuilder sb = new StringBuilder(); + User user = identity.getUser(); + if(StringHelper.containsNonWhitespace(user.getFirstName())) { + + sb.append(user.getFirstName()); + } + if(StringHelper.containsNonWhitespace(user.getLastName())) { + if(sb.length() > 0) sb.append(" "); + sb.append(user.getLastName()); + } + + String institutionalIdentifier = user.getProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, translator.getLocale()); + if(StringHelper.containsNonWhitespace(institutionalIdentifier)) { + if(sb.length() > 0) sb.append(", "); + sb.append(institutionalIdentifier); + } + return sb.toString(); + } + + public int drawTable(Row[] content, int offset, float fontSize, float cellMargin) + throws IOException { + + float tableWidth = width; + float rowHeight = (lineHeightFactory * fontSize) + (2 * cellMargin); + + float allColWidth = 29f; + float authorisedColWidth = authorizedAbsenceEnabled ? 29f : 0f; + float lectureColWidth = 15f; + float lecturesColWidth = numOfLectures * lectureColWidth + cellMargin; + + float nameMaxSizeWithMargin = (tableWidth - lecturesColWidth - allColWidth - authorisedColWidth) / 2.0f; + if(nameMaxSizeWithMargin < 140.0f) { + nameMaxSizeWithMargin = 140.0f; + } + float commentColWidth = tableWidth - lecturesColWidth - allColWidth - authorisedColWidth - nameMaxSizeWithMargin; + float nameMaxSize = nameMaxSizeWithMargin - (2 * cellMargin); + + float availableHeight = currentY - marginTopBottom - rowHeight; + + float[] rowHeights = new float[content.length]; + float usedHeight = 0.0f; + int possibleRows = 0; + for(int i = offset; i < content.length; i++) { + String name = content[i].getName(); + float nameWidth = getStringWidth(name, fontSize); + float nameHeight; + if(nameWidth > nameMaxSize) { + nameHeight = rowHeight + (lineHeightFactory * fontSize); + } else { + nameHeight = rowHeight; + } + + if((usedHeight + nameHeight) > availableHeight) { + break; + } + usedHeight += nameHeight; + rowHeights[i] = nameHeight; + possibleRows++; + } + + int end = Math.min(offset + possibleRows, content.length); + int rows = end - offset; + + float tableHeight = usedHeight + rowHeight; + + // draw the horizontal line of the rows + float y = currentY; + float nexty = currentY; + drawLine(marginLeftRight, nexty, marginLeftRight + tableWidth, nexty, 0.5f); + nexty -= rowHeight; + for (int i =offset; i < end; i++) { + drawLine(marginLeftRight, nexty, marginLeftRight + tableWidth, nexty, 0.5f); + nexty -= rowHeights[i]; + } + drawLine(marginLeftRight, nexty, marginLeftRight + tableWidth, nexty, 0.5f); + + // draw the vertical line of the columns + float nextx = marginLeftRight; + drawLine(nextx, y, nextx, y - tableHeight, 0.5f); + nextx += nameMaxSizeWithMargin; + drawLine(nextx, y, nextx, y - tableHeight, 0.5f); + nextx += lecturesColWidth; + drawLine(nextx, y, nextx, y - tableHeight, 0.5f); + nextx += allColWidth; + drawLine(nextx, y, nextx, y - tableHeight, 0.5f); + if(authorizedAbsenceEnabled) { + nextx += authorisedColWidth; + drawLine(nextx, y, nextx, y - tableHeight, 0.5f); + } + nextx += commentColWidth; + drawLine(nextx, y, nextx, y - tableHeight, 0.5f); + + // now add the text + // draw the headers + final float textx = marginLeftRight + cellMargin; + float texty = currentY; + { + float headerY = texty - rowHeight + (2 * cellMargin); + float headerX = textx; + + currentContentStream.beginText(); + currentContentStream.setFont(fontBold, fontSize); + currentContentStream.moveTextPositionByAmount(headerX, headerY); + currentContentStream.drawString(translator.translate("pdf.table.header.participants")); + currentContentStream.endText(); + + headerX += nameMaxSizeWithMargin; + for(int i=0; i<numOfLectures; i++) { + currentContentStream.beginText(); + currentContentStream.setFont(fontBold, fontSize); + currentContentStream.moveTextPositionByAmount(headerX, headerY); + currentContentStream.drawString(Integer.toString(i+1)); + currentContentStream.endText(); + headerX += lectureColWidth; + } + + headerX += cellMargin; + currentContentStream.beginText(); + currentContentStream.setFont(fontBold, fontSize); + currentContentStream.moveTextPositionByAmount(headerX, headerY); + currentContentStream.drawString(translator.translate("pdf.table.header.all")); + currentContentStream.endText(); + headerX += allColWidth; + + if(authorizedAbsenceEnabled) { + currentContentStream.beginText(); + currentContentStream.setFont(fontBold, fontSize); + currentContentStream.moveTextPositionByAmount(headerX, headerY); + currentContentStream.drawString(translator.translate("pdf.table.header.authorised")); + currentContentStream.endText(); + headerX += authorisedColWidth; + } + + currentContentStream.beginText(); + currentContentStream.setFont(fontBold, fontSize); + currentContentStream.moveTextPositionByAmount(headerX, headerY); + currentContentStream.drawString(translator.translate("pdf.table.header.comment")); + currentContentStream.endText(); + } + + currentY -= rowHeight; + + //draw the content + texty = currentY - 15; + for (int i=offset; i<end; i++) { + String text = content[i].getName(); + if(text == null) continue; + + if(rowHeights[i] > rowHeight + 1) { + //can do 2 lines + String[] texts = splitText(text, nameMaxSize, fontSize); + float lineTexty = texty; + for(int k=0; k<2 && k<texts.length; k++) { + String textLine = texts[k]; + currentContentStream.beginText(); + currentContentStream.setFont(font, fontSize); + currentContentStream.moveTextPositionByAmount(textx, lineTexty); + currentContentStream.drawString(textLine); + currentContentStream.endText(); + lineTexty -= (lineHeightFactory * fontSize); + } + } else { + currentContentStream.beginText(); + currentContentStream.setFont(font, fontSize); + currentContentStream.moveTextPositionByAmount(textx, texty); + currentContentStream.drawString(text); + currentContentStream.endText(); + } + + float offetSetYTop = 7f; + float offetSetYBottom = 2f; + float boxWidth = 9.0f; + + //absences check box + boolean all = true; + boolean[] absences = content[i].getAbsences(); + float boxx = textx + nameMaxSizeWithMargin; + for (int j=0; j<absences.length; j++) { + drawLine(boxx, texty + offetSetYTop, boxx, texty - offetSetYBottom, 0.5f); + drawLine(boxx, texty - offetSetYBottom, boxx + boxWidth, texty - offetSetYBottom, 0.5f); + drawLine(boxx, texty + offetSetYTop, boxx + boxWidth, texty + offetSetYTop, 0.5f); + drawLine(boxx + boxWidth, texty + offetSetYTop, boxx + boxWidth, texty - offetSetYBottom, 0.5f); + + if(absences[j]) { + currentContentStream.beginText(); + currentContentStream.setFont(font, fontSize); + currentContentStream.moveTextPositionByAmount(boxx + 2f, texty); + currentContentStream.drawString("x"); + currentContentStream.endText(); + } + all &= absences[j]; + boxx += 15f; + } + + {// all check box + boxx += cellMargin; + float startBoxx = boxx + ((allColWidth - boxWidth - (2 * cellMargin)) / 2); + drawLine(startBoxx, texty + offetSetYTop, startBoxx, texty - offetSetYBottom, 0.5f); + drawLine(startBoxx, texty - offetSetYBottom, startBoxx + boxWidth, texty - offetSetYBottom, 0.5f); + drawLine(startBoxx, texty + offetSetYTop, startBoxx + boxWidth, texty + offetSetYTop, 0.5f); + drawLine(startBoxx + boxWidth, texty + offetSetYTop, startBoxx + boxWidth, texty - offetSetYBottom, 0.5f); + + if(all) { + currentContentStream.beginText(); + currentContentStream.setFont(font, fontSize); + currentContentStream.moveTextPositionByAmount(startBoxx + 2f, texty); + currentContentStream.drawString("x"); + currentContentStream.endText(); + } + boxx += allColWidth; + } + + {//authorised + float startBoxx = boxx + ((authorisedColWidth - boxWidth - (2 * cellMargin)) / 2); + drawLine(startBoxx, texty + offetSetYTop, startBoxx, texty - offetSetYBottom, 0.5f); + drawLine(startBoxx, texty - offetSetYBottom, startBoxx + boxWidth, texty - offetSetYBottom, 0.5f); + drawLine(startBoxx, texty + offetSetYTop, startBoxx + boxWidth, texty + offetSetYTop, 0.5f); + drawLine(startBoxx + boxWidth, texty + offetSetYTop, startBoxx + boxWidth, texty - offetSetYBottom, 0.5f); + + if(content[i].isAuthorised()) { + currentContentStream.beginText(); + currentContentStream.setFont(font, fontSize); + currentContentStream.moveTextPositionByAmount(startBoxx + 2f, texty); + currentContentStream.drawString("x"); + currentContentStream.endText(); + } + boxx += authorisedColWidth; + } + + {//comment + String comment = content[i].getComment(); + if(comment != null) { + float commentWidth = getStringWidth(comment, fontSize); + float commentCellWidth = commentColWidth - (2 * cellMargin); + if(commentWidth > commentCellWidth) { + commentWidth = getStringWidth(comment, fontSize - 2); + if(commentWidth > commentCellWidth) { + //cut + float numOfChars = comment.length() * (commentColWidth / commentWidth); + comment = comment.substring(0, Math.round(numOfChars) - 4) + "..."; + } + currentContentStream.beginText(); + currentContentStream.setFont(font, fontSize - 2); + currentContentStream.moveTextPositionByAmount(boxx + 2f, texty); + currentContentStream.drawString(comment); + currentContentStream.endText(); + } else { + currentContentStream.beginText(); + currentContentStream.setFont(font, fontSize); + currentContentStream.moveTextPositionByAmount(boxx + 2f, texty); + currentContentStream.drawString(comment); + currentContentStream.endText(); + } + } + } + + texty -= rowHeights[i]; + } + return rows; + } + + private static class Row { + + private final String name; + private final boolean[] absences; + private final boolean authorised; + private final String comment; + + public Row(String name, boolean[] absences, boolean authorised, String comment) { + this.name = name; + this.absences = absences; + this.authorised = authorised; + this.comment = comment; + } + + public String getName() { + return name; + } + + public boolean[] getAbsences() { + return absences; + } + + public boolean isAuthorised() { + return authorised; + } + + public String getComment() { + return comment; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/lecture/ui/LecturesBlockPDFExport.java b/src/main/java/org/olat/modules/lecture/ui/export/LecturesBlockSignaturePDFExport.java similarity index 89% rename from src/main/java/org/olat/modules/lecture/ui/LecturesBlockPDFExport.java rename to src/main/java/org/olat/modules/lecture/ui/export/LecturesBlockSignaturePDFExport.java index 68e09db815f3c8632538e3f00a2688240924bcb0..372bfd829cb5f6cc1c88d4332dfeb70b9bffc5f3 100644 --- a/src/main/java/org/olat/modules/lecture/ui/LecturesBlockPDFExport.java +++ b/src/main/java/org/olat/modules/lecture/ui/export/LecturesBlockSignaturePDFExport.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.lecture.ui; +package org.olat.modules.lecture.ui.export; import java.io.IOException; import java.io.InputStream; @@ -38,6 +38,7 @@ import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.pdf.PdfDocument; import org.olat.modules.lecture.LectureBlock; +import org.olat.repository.RepositoryEntry; /** * @@ -45,16 +46,16 @@ import org.olat.modules.lecture.LectureBlock; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class LecturesBlockPDFExport extends PdfDocument implements MediaResource { +public class LecturesBlockSignaturePDFExport extends PdfDocument implements MediaResource { - private static final OLog log = Tracing.createLoggerFor(LecturesBlockPDFExport.class); + private static final OLog log = Tracing.createLoggerFor(LecturesBlockSignaturePDFExport.class); - private String resourceTitle; private String teacher; private final Translator translator; private final LectureBlock lectureBlock; + private final RepositoryEntry entry; - public LecturesBlockPDFExport(LectureBlock lectureBlock, Translator translator) + public LecturesBlockSignaturePDFExport(LectureBlock lectureBlock, Translator translator) throws IOException { super(translator.getLocale()); @@ -62,6 +63,7 @@ public class LecturesBlockPDFExport extends PdfDocument implements MediaResource marginLeftRight = 62.0f; this.translator = translator; this.lectureBlock = lectureBlock; + entry = lectureBlock.getEntry(); } public String getTeacher() { @@ -72,14 +74,6 @@ public class LecturesBlockPDFExport extends PdfDocument implements MediaResource this.teacher = teacher; } - public String getResourceTitle() { - return resourceTitle; - } - - public void setResourceTitle(String resourceTitle) { - this.resourceTitle = resourceTitle; - } - @Override public boolean acceptRanges() { return false; @@ -111,8 +105,8 @@ public class LecturesBlockPDFExport extends PdfDocument implements MediaResource Formatter formatter = Formatter.getInstance(translator.getLocale()); String filename = lectureBlock.getTitle() + "_" + formatter.formatDate(lectureBlock.getStartDate()) - + "_" + formatter.formatTime(lectureBlock.getStartDate()) - + "-" + formatter.formatTime(lectureBlock.getEndDate()) + + "_" + formatter.formatTimeShort(lectureBlock.getStartDate()) + + "-" + formatter.formatTimeShort(lectureBlock.getEndDate()) + ".pdf"; hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(filename)); hres.setHeader("Content-Description",StringHelper.urlEncodeUTF8(filename)); @@ -135,17 +129,18 @@ public class LecturesBlockPDFExport extends PdfDocument implements MediaResource throws IOException, COSVisitorException, TransformerException { addPage(); String lectureBlockTitle = lectureBlock.getTitle(); + String resourceTitle = entry.getDisplayname(); addMetadata(lectureBlockTitle, resourceTitle, teacher); - - if(StringHelper.containsNonWhitespace(lectureBlockTitle)) { - addParagraph(lectureBlockTitle, 16, true, width); - } + + String title = resourceTitle + " - " + lectureBlockTitle; + title = translator.translate("attendance.list.to.sign.title", new String[] { title }); + addParagraph(title, 16, true, width); Formatter formatter = Formatter.getInstance(translator.getLocale()); String dates = translator.translate("pdf.table.dates", new String[] { formatter.formatDate(lectureBlock.getStartDate()), - formatter.formatTime(lectureBlock.getStartDate()), - formatter.formatTime(lectureBlock.getEndDate()) + formatter.formatTimeShort(lectureBlock.getStartDate()), + formatter.formatTimeShort(lectureBlock.getEndDate()) }); addParagraph(dates, 12, true, width); @@ -182,13 +177,13 @@ public class LecturesBlockPDFExport extends PdfDocument implements MediaResource private String getName(Identity identity) { StringBuilder sb = new StringBuilder(); User user = identity.getUser(); - if(StringHelper.containsNonWhitespace(user.getLastName())) { - sb.append(user.getLastName()); - } if(StringHelper.containsNonWhitespace(user.getFirstName())) { - if(sb.length() > 0) sb.append(", "); sb.append(user.getFirstName()); } + if(StringHelper.containsNonWhitespace(user.getLastName())) { + if(sb.length() > 0) sb.append(" "); + sb.append(user.getLastName()); + } String institutionalIdentifier = user.getProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, translator.getLocale()); if(StringHelper.containsNonWhitespace(institutionalIdentifier)) { @@ -203,9 +198,9 @@ public class LecturesBlockPDFExport extends PdfDocument implements MediaResource float tableWidth = width; float rowHeight = (lineHeightFactory * fontSize) + (2 * cellMargin); - float signatureColWidth = 150f; + float lecturesColWidth = 150f; - float nameMaxSizeWithMargin = tableWidth - signatureColWidth; + float nameMaxSizeWithMargin = tableWidth - lecturesColWidth; float nameMaxSize = nameMaxSizeWithMargin - (2 * cellMargin); float availableHeight = currentY - marginTopBottom - rowHeight; @@ -252,7 +247,7 @@ public class LecturesBlockPDFExport extends PdfDocument implements MediaResource drawLine(nextx, y, nextx, y - tableHeight, 0.5f); nextx += nameMaxSizeWithMargin; drawLine(nextx, y, nextx, y - tableHeight, 0.5f); - nextx += signatureColWidth; + nextx += lecturesColWidth; drawLine(nextx, y, nextx, y - tableHeight, 0.5f); // now add the text diff --git a/src/main/java/org/olat/modules/lecture/ui/export/LecturesBlocksEntryExport.java b/src/main/java/org/olat/modules/lecture/ui/export/LecturesBlocksEntryExport.java new file mode 100644 index 0000000000000000000000000000000000000000..32de1a83f9ed3f1354da45f0e7f9dd13b2399447 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/export/LecturesBlocksEntryExport.java @@ -0,0 +1,185 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.export; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.core.util.openxml.OpenXMLWorkbook; +import org.olat.core.util.openxml.OpenXMLWorkbookResource; +import org.olat.core.util.openxml.OpenXMLWorksheet; +import org.olat.core.util.openxml.OpenXMLWorksheet.Row; +import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureService; +import org.olat.modules.lecture.Reason; +import org.olat.modules.lecture.model.LectureBlockWithTeachers; +import org.olat.repository.RepositoryEntry; +import org.olat.user.UserManager; + +/** + * + * Initial date: 6 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LecturesBlocksEntryExport extends OpenXMLWorkbookResource { + + private static final OLog log = Tracing.createLoggerFor(LecturesBlocksEntryExport.class); + + private final Formatter formatter; + private final RepositoryEntry entry; + private final Translator translator; + private List<LectureBlockWithTeachers> blocks; + + private final UserManager userManager; + private final LectureService lectureService; + + public LecturesBlocksEntryExport(RepositoryEntry entry, Translator translator) { + super(label(entry)); + this.entry = entry; + this.translator = translator; + userManager = CoreSpringFactory.getImpl(UserManager.class); + lectureService = CoreSpringFactory.getImpl(LectureService.class); + formatter = Formatter.getInstance(translator.getLocale()); + } + + private static final String label(RepositoryEntry entry) { + return StringHelper.transformDisplayNameToFileSystemName(entry.getDisplayname()) + + "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) + + ".xlsx"; + } + + @Override + protected void generate(OutputStream out) { + blocks = lectureService.getLectureBlocksWithTeachers(entry); + Collections.sort(blocks, new LectureBlockWithTeachersComparator()); + + try(OpenXMLWorkbook workbook = new OpenXMLWorkbook(out, 1 + blocks.size())) { + //overview of all lecture blocks + OpenXMLWorksheet exportSheet = workbook.nextWorksheet(); + exportSheet.setHeaderRows(1); + addHeaders(exportSheet); + addContent(exportSheet); + + for(LectureBlockWithTeachers block:blocks) { + OpenXMLWorksheet exportBlockSheet = workbook.nextWorksheet(); + LectureBlockExport lectureBlockExport = new LectureBlockExport(block.getLectureBlock(), block.getTeachers(), true, translator); + lectureBlockExport.generate(exportBlockSheet); + } + } catch (IOException e) { + log.error("", e); + } + } + + private void addHeaders(OpenXMLWorksheet exportSheet) { + Row headerRow = exportSheet.newRow(); + + int pos = 0; + headerRow.addCell(pos++, translator.translate("lecture.title", null)); + headerRow.addCell(pos++, translator.translate("lecture.location", null)); + headerRow.addCell(pos++, translator.translate("lecture.date", null)); + headerRow.addCell(pos++, translator.translate("table.header.start.time", null)); + headerRow.addCell(pos++, translator.translate("table.header.end.time", null)); + headerRow.addCell(pos++, translator.translate("table.header.teachers", null)); + headerRow.addCell(pos++, translator.translate("table.header.status", null)); + headerRow.addCell(pos++, translator.translate("table.header.auto.close.date", null)); + headerRow.addCell(pos++, translator.translate("planned.lectures", null)); + headerRow.addCell(pos++, translator.translate("table.header.effective.lectures", null)); + headerRow.addCell(pos++, translator.translate("lecture.block.effective.end", null)); + headerRow.addCell(pos++, translator.translate("lecture.block.effective.reason", null)); + headerRow.addCell(pos++, translator.translate("table.header.comment", null)); + } + + private void addContent(OpenXMLWorksheet exportSheet) { + for(LectureBlockWithTeachers block:blocks) { + Row row = exportSheet.newRow(); + LectureBlock lectureBlock = block.getLectureBlock(); + + int pos = 0; + row.addCell(pos++, lectureBlock.getTitle()); + row.addCell(pos++, lectureBlock.getLocation()); + row.addCell(pos++, formatDate(lectureBlock.getStartDate())); + row.addCell(pos++, formatTime(lectureBlock.getStartDate())); + row.addCell(pos++, formatTime(lectureBlock.getEndDate())); + + StringBuilder teachers = new StringBuilder(); + for(Identity teacher:block.getTeachers()) { + if(teachers.length() > 0) teachers.append(", "); + teachers.append(userManager.getUserDisplayName(teacher)); + } + row.addCell(pos++, teachers.toString()); + if(lectureBlock.getRollCallStatus() == null) { + pos++; + } else { + row.addCell(pos++, translator.translate(lectureBlock.getRollCallStatus().name())); + } + row.addCell(pos++, formatter.formatDate(lectureBlock.getAutoClosedDate())); + + row.addCell(pos++, toInt(lectureBlock.getPlannedLecturesNumber())); + row.addCell(pos++, toInt(lectureBlock.getEffectiveLecturesNumber())); + row.addCell(pos++, formatTime(lectureBlock.getEffectiveEndDate())); + + Reason reason = lectureBlock.getReasonEffectiveEnd(); + if(reason == null) { + pos++; + } else { + row.addCell(pos++, reason.getTitle()); + } + row.addCell(pos++, lectureBlock.getComment()); + + } + } + + private String toInt(int number) { + return number < 0 ? null : Integer.toString(number); + } + + private String formatTime(Date time) { + return time == null ? null : formatter.formatTimeShort(time); + } + + private String formatDate(Date date) { + return date == null ? null : formatter.formatDate(date); + } + + private static class LectureBlockWithTeachersComparator implements Comparator<LectureBlockWithTeachers> { + + @Override + public int compare(LectureBlockWithTeachers o1, LectureBlockWithTeachers o2) { + Date s1 = o1.getLectureBlock().getStartDate(); + Date s2 = o2.getLectureBlock().getStartDate(); + if(s1 == null && s2 == null) return 0; + if(s1 == null) return 1; + if(s2 == null) return -1; + return s1.compareTo(s2); + } + } +} diff --git a/src/main/java/org/olat/modules/lecture/ui/export/RepositoryEntryAuditLogExport.java b/src/main/java/org/olat/modules/lecture/ui/export/RepositoryEntryAuditLogExport.java new file mode 100644 index 0000000000000000000000000000000000000000..69af6231e36d6cb55d7eec88af735347062af989 --- /dev/null +++ b/src/main/java/org/olat/modules/lecture/ui/export/RepositoryEntryAuditLogExport.java @@ -0,0 +1,68 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.ui.export; + +import java.util.Date; +import java.util.List; + +import org.olat.core.gui.translator.Translator; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.core.util.openxml.OpenXMLWorksheet; +import org.olat.core.util.openxml.OpenXMLWorksheet.Row; +import org.olat.modules.lecture.LectureBlockAuditLog; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 12 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class RepositoryEntryAuditLogExport extends AbstractLectureBlockAuditLogExport { + + private RepositoryEntry entry; + + public RepositoryEntryAuditLogExport(RepositoryEntry entry, List<LectureBlockAuditLog> auditLog, Translator translator) { + super(label(entry), auditLog, translator); + this.entry = entry; + cacheRepositoryEntry(entry); + } + + private static final String label(RepositoryEntry entry) { + return StringHelper.transformDisplayNameToFileSystemName(entry.getDisplayname()) + + "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) + + ".xlsx"; + } + + @Override + protected void addSheetSettings(OpenXMLWorksheet exportSheet) { + exportSheet.setHeaderRows(2); + super.addSheetSettings(exportSheet); + } + + @Override + protected void addHeaders(OpenXMLWorksheet exportSheet) { + Row headerRow = exportSheet.newRow(); + + int pos = 0; + headerRow.addCell(pos++, translator.translate("export.header.entry", new String[] { entry.getDisplayname() })); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/openmeetings/_spring/openmeetingsContext.xml b/src/main/java/org/olat/modules/openmeetings/_spring/openmeetingsContext.xml deleted file mode 100644 index d53ed9339a8c5edfab4fe1ca210b4cd89094ddde..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/modules/openmeetings/_spring/openmeetingsContext.xml +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context.xsd"> - - <context:component-scan base-package="org.olat.modules.openmeetings" /> - - <!-- OpenMeetings admin. panel --> - <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> - <property name="order" value="7210" /> - <property name="actionController"> - <bean class="org.olat.core.gui.control.creator.FactoryControllerCreator" scope="prototype"> - <property name="factoryName" value="org.olat.modules.openmeetings.OpenMeetingsUIFactory"/> - <property name="factoryMethod" value="createAdminController"/> - </bean> - </property> - <property name="navigationKey" value="openmeetings" /> - <property name="parentTreeNodeIdentifier" value="externalToolsParent" /> - <property name="i18nActionKey" value="admin.menu.title"/> - <property name="i18nDescriptionKey" value="admin.menu.title.alt"/> - <property name="translationPackage" value="org.olat.modules.openmeetings.ui"/> - <property name="extensionPoints"> - <list> - <value>org.olat.admin.SystemAdminMainController</value> - </list> - </property> - </bean> - -</beans> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/BinderConfiguration.java b/src/main/java/org/olat/modules/portfolio/BinderConfiguration.java index a270bccc0a0b96b7a55406d3576c018efc25a230..5e6b518a3c373a01c737f56d96bb61a303e67c52 100644 --- a/src/main/java/org/olat/modules/portfolio/BinderConfiguration.java +++ b/src/main/java/org/olat/modules/portfolio/BinderConfiguration.java @@ -39,15 +39,25 @@ public class BinderConfiguration { private final boolean timeline; private final boolean shareable; private final boolean options; + private final Float maxScore; + private final Float minScore; + private final String displayname; - public BinderConfiguration(boolean assessable, boolean withScore, boolean withPassed, - boolean timeline, boolean shareable, boolean options) { + public BinderConfiguration(boolean assessable, boolean withScore, Float maxScore, Float minScore, + boolean withPassed, boolean timeline, boolean shareable, boolean options, String displayname) { this.assessable = assessable; this.withScore = withScore; this.withPassed = withPassed; this.timeline = timeline; this.shareable = shareable; this.options = options; + this.maxScore = maxScore; + this.minScore = minScore; + this.displayname = displayname; + } + + public String getDisplayname() { + return displayname; } public boolean isAssessable() { @@ -57,6 +67,14 @@ public class BinderConfiguration { public boolean isWithScore() { return withScore; } + + public Float getMaxScore() { + return maxScore; + } + + public Float getMinScore() { + return minScore; + } public boolean isWithPassed() { return withPassed; @@ -84,37 +102,46 @@ public class BinderConfiguration { } public static BinderConfiguration createBusinessGroupConfig() { - return new BinderConfiguration(false, false, false, true, false, false); + return new BinderConfiguration(false, false, null, null, false, true, false, false, null); } public static BinderConfiguration createTemplateConfig(boolean optionsEditable) { - return new BinderConfiguration(false, false, false, false, false, optionsEditable); + return new BinderConfiguration(false, false, null, null, false, false, false, optionsEditable, null); } public static BinderConfiguration createInvitationConfig() { - return new BinderConfiguration(false, false, false, true, false, false); + return new BinderConfiguration(false, false, null, null, false, true, false, false, null); } public static BinderConfiguration createMyPagesConfig() { - return new BinderConfiguration(false, false, false, true, true, false); + return new BinderConfiguration(false, false, null, null, false, true, true, false, null); } public static BinderConfiguration createDeletedPagesConfig() { - return new BinderConfiguration(false, false, false, false, false, false); + return new BinderConfiguration(false, false, null, null, false, false, false, false, null); } public static BinderConfiguration createConfig(Binder binder) { boolean withScore = false; boolean withPassed = false; boolean assessable = false; + Float maxScore = null; + Float minScore = null; + + String displayname; RepositoryEntry entry = binder.getEntry(); if(binder.getSubIdent() != null) { ICourse course = CourseFactory.loadCourse(entry); + displayname = course.getCourseTitle(); CourseNode courseNode = course.getRunStructure().getNode(binder.getSubIdent()); if(courseNode instanceof PortfolioCourseNode) { PortfolioCourseNode pfNode = (PortfolioCourseNode)courseNode; withScore = pfNode.hasScoreConfigured(); + if(withScore) { + maxScore = pfNode.getMaxScoreConfiguration(); + minScore = pfNode.getMinScoreConfiguration(); + } withPassed = pfNode.hasPassedConfigured(); assessable = withPassed || withScore; } else { @@ -123,12 +150,14 @@ public class BinderConfiguration { assessable = true; } } else if(entry != null) { + displayname = entry.getDisplayname(); withPassed = true; withScore = false; assessable = true; } else { + displayname = null; withPassed = withScore = assessable = false; } - return new BinderConfiguration(assessable, withScore, withPassed, true, true, false); + return new BinderConfiguration(assessable, withScore, maxScore, minScore, withPassed, true, true, false, displayname); } } diff --git a/src/main/java/org/olat/modules/portfolio/BinderSecurityCallback.java b/src/main/java/org/olat/modules/portfolio/BinderSecurityCallback.java index ffd2cdef5e25fb67d70e905aedb687812d3bce35..86fd4c46a53be3b0868022bbe84ae06217c283eb 100644 --- a/src/main/java/org/olat/modules/portfolio/BinderSecurityCallback.java +++ b/src/main/java/org/olat/modules/portfolio/BinderSecurityCallback.java @@ -21,6 +21,8 @@ package org.olat.modules.portfolio; import java.util.List; +import org.olat.modules.assessment.Role; + /** * * Initial date: 15.06.2016<br> @@ -40,6 +42,8 @@ public interface BinderSecurityCallback { public boolean canDeleteBinder(Binder binder); + public boolean canExportBinder(); + /** * Can edit the edit the meta-data in this binder inclusive meta-data * of sections and pages. @@ -61,7 +65,9 @@ public interface BinderSecurityCallback { public boolean canEditPage(Page page); public boolean canEditPageMetadata(Page page, List<Assignment> assignments); - + + public boolean canEditCategories(Page page); + public boolean canPublish(Page page); public boolean canRevision(Page page); @@ -94,6 +100,14 @@ public interface BinderSecurityCallback { public boolean canViewElement(PortfolioElement element); + + /** + * View only the title of the element but not its content + * @param element + * @return + */ + public boolean canViewTitleOfElement(PortfolioElement element); + public boolean canViewPendingAssignments(Section section); public boolean canViewEmptySection(Section section); @@ -107,6 +121,9 @@ public interface BinderSecurityCallback { public boolean canViewAssess(PortfolioElement element); public boolean canViewAssessment(); + + + public Role getRole(); } diff --git a/src/main/java/org/olat/modules/portfolio/BinderSecurityCallbackFactory.java b/src/main/java/org/olat/modules/portfolio/BinderSecurityCallbackFactory.java index f5acbe70cfa1e4dd9572db66598954620c70fcb1..274e587fc68a411f87a8f323dacc2c8d8739180e 100644 --- a/src/main/java/org/olat/modules/portfolio/BinderSecurityCallbackFactory.java +++ b/src/main/java/org/olat/modules/portfolio/BinderSecurityCallbackFactory.java @@ -20,9 +20,11 @@ package org.olat.modules.portfolio; import java.util.Collections; +import java.util.Date; import java.util.List; import org.olat.core.CoreSpringFactory; +import org.olat.modules.assessment.Role; import org.olat.modules.portfolio.model.AccessRights; import org.olat.repository.model.RepositoryEntrySecurity; @@ -70,6 +72,12 @@ public class BinderSecurityCallbackFactory { return new BinderSecurityCallbackImpl(rights, template != null, deliveryOptions); } + public static final BinderSecurityCallback getCallbackForCourseCoach(Binder binder, List<AccessRights> rights) { + Binder template = binder.getTemplate(); + BinderDeliveryOptions deliveryOptions = getDeliveryOptions(binder); + return new BinderSecurityCallbackForCoach(rights, template != null, deliveryOptions); + } + /** * Invitee can only comment binders * @return @@ -102,7 +110,12 @@ public class BinderSecurityCallbackFactory { public boolean canRestorePage(Page page) { return page.getPageStatus() == PageStatus.deleted; } - + + @Override + public Role getRole() { + return Role.user; + } + } private static class BinderSecurityCallbackForDeletedBinder extends DefaultBinderSecurityCallback { @@ -188,6 +201,13 @@ public class BinderSecurityCallbackFactory { if(element instanceof Page) { Page page = (Page)element; if(page.getPageStatus() == null || page.getPageStatus() == PageStatus.draft) { + if(rights != null) { + for(AccessRights right:rights) { + if(right.getRole() == PortfolioRoles.readInvitee && right.matchElementAndAncestors(element)) { + return true; + } + } + } return false; } } @@ -264,6 +284,23 @@ public class BinderSecurityCallbackFactory { } } + private static class BinderSecurityCallbackForCoach extends BinderSecurityCallbackImpl { + + public BinderSecurityCallbackForCoach(List<AccessRights> rights, boolean task, BinderDeliveryOptions deliveryOptions) { + super(rights, task, deliveryOptions); + } + + @Override + public boolean canViewAssess(PortfolioElement element) { + return true; + } + + @Override + public boolean canDeleteBinder(Binder binder) { + return false; + } + } + private static class BinderSecurityCallbackImpl implements BinderSecurityCallback { /** @@ -293,6 +330,11 @@ public class BinderSecurityCallbackFactory { return owner; } + @Override + public boolean canExportBinder() { + return owner; + } + @Override public boolean canMoveToTrashBinder(Binder binder) { if(owner) { @@ -402,6 +444,14 @@ public class BinderSecurityCallbackFactory { } return false; } + + /** + * Owner can always edit page categories, regardless of the page state + */ + @Override + public boolean canEditCategories(Page page) { + return owner; + } @Override public boolean canPublish(Page page) { @@ -527,12 +577,74 @@ public class BinderSecurityCallbackFactory { @Override public boolean canViewElement(PortfolioElement element) { if(owner) { + if(task) { + if(element instanceof Section) { + Section section = (Section)element; + if(section.getBeginDate() != null && section.getBeginDate().after(new Date())) { + return false; + } + } else if(element instanceof Page) { + Page page = (Page)element; + Section section = page.getSection(); + if(section != null && section.getBeginDate() != null && section.getBeginDate().after(new Date())) { + return false; + } + } + } + return true; + } + + if(element instanceof Page) { + Page page = (Page)element; + if(page.getPageStatus() == null || page.getPageStatus() == PageStatus.draft) { + return false; + } + } + + //need to be recursive, if page -> section too -> binder too??? + if(rights != null) { + for(AccessRights right:rights) { + if((PortfolioRoles.reviewer.equals(right.getRole()) || PortfolioRoles.coach.equals(right.getRole())) + && right.matchElementAndAncestors(element)) { + return true; + } + } + } + return false; + } + + @Override + public boolean canViewTitleOfElement(PortfolioElement element) { + if(owner) { + if(task) { + if(element instanceof Section) { + Section section = (Section)element; + if(section.getBeginDate() != null && section.getBeginDate().after(new Date())) { + return false; + } + } else if(element instanceof Page) { + Page page = (Page)element; + Section section = page.getSection(); + if(section != null && section.getBeginDate() != null && section.getBeginDate().after(new Date())) { + return false; + } + } + } return true; } if(element instanceof Page) { Page page = (Page)element; if(page.getPageStatus() == null || page.getPageStatus() == PageStatus.draft) { + //need to be recursive, if page -> section too -> binder too??? + if(rights != null) { + for(AccessRights right:rights) { + if((PortfolioRoles.reviewer.equals(right.getRole()) || PortfolioRoles.coach.equals(right.getRole())) + && right.matchElementAndAncestors(element)) { + return true; + } + } + } return owner; } } @@ -551,7 +663,13 @@ public class BinderSecurityCallbackFactory { @Override public boolean canViewPendingAssignments(Section section) { - if(owner) return true; + if(owner) { + Date beginDate = section.getBeginDate(); + if(beginDate != null && beginDate.after(new Date())) { + return false; + } + return true; + } if(rights != null) { for(AccessRights right:rights) { @@ -631,6 +749,11 @@ public class BinderSecurityCallbackFactory { } return false; } + + @Override + public Role getRole() { + return owner ? Role.user : Role.coach; + } } private static class DefaultBinderSecurityCallback implements BinderSecurityCallback { @@ -640,6 +763,11 @@ public class BinderSecurityCallbackFactory { return false; } + @Override + public boolean canExportBinder() { + return false; + } + @Override public boolean canMoveToTrashBinder(Binder binder) { return false; @@ -699,7 +827,12 @@ public class BinderSecurityCallbackFactory { public boolean canEditPageMetadata(Page page, List<Assignment> assignments) { return false; } - + + @Override + public boolean canEditCategories(Page page) { + return false; + } + @Override public boolean canPublish(Page page) { return false; @@ -750,6 +883,11 @@ public class BinderSecurityCallbackFactory { return false; } + @Override + public boolean canViewTitleOfElement(PortfolioElement element) { + return canViewElement(element); + } + @Override public boolean canViewPendingAssignments(Section section) { return false; @@ -783,6 +921,11 @@ public class BinderSecurityCallbackFactory { @Override public boolean canViewAssessment() { return false; - } + } + + @Override + public Role getRole() { + return Role.coach; + } } } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/MediaHandler.java b/src/main/java/org/olat/modules/portfolio/MediaHandler.java index 545fe96ab8baee401074aa5637a957cc0d8f644f..8f6f4c9569f34b08755c7d71ff06677a2fc3f6e4 100644 --- a/src/main/java/org/olat/modules/portfolio/MediaHandler.java +++ b/src/main/java/org/olat/modules/portfolio/MediaHandler.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -53,7 +54,7 @@ public interface MediaHandler { public Media createMedia(AbstractArtefact artefact); - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media); + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints); public Controller getEditMediaController(UserRequest ureq, WindowControl wControl, Media media); diff --git a/src/main/java/org/olat/modules/portfolio/MediaRenderingHints.java b/src/main/java/org/olat/modules/portfolio/MediaRenderingHints.java new file mode 100644 index 0000000000000000000000000000000000000000..3cf3a97ffd45d3b837385f259ade3b225b172e75 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/MediaRenderingHints.java @@ -0,0 +1,34 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio; + +/** + * + * Initial date: 24 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface MediaRenderingHints { + + public boolean isToPdf(); + + public boolean isExtendedMetadata(); + +} diff --git a/src/main/java/org/olat/modules/portfolio/PortfolioService.java b/src/main/java/org/olat/modules/portfolio/PortfolioService.java index 2d2e632c2ae86f4b73618de959419c17cda46e09..09f5a4e6a1e61079916c92debda50457a4129c08 100644 --- a/src/main/java/org/olat/modules/portfolio/PortfolioService.java +++ b/src/main/java/org/olat/modules/portfolio/PortfolioService.java @@ -28,6 +28,7 @@ import java.util.Map; import org.olat.basesecurity.IdentityRef; import org.olat.core.id.Identity; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.modules.portfolio.model.AccessRightChange; import org.olat.modules.portfolio.model.AccessRights; @@ -544,9 +545,11 @@ public interface PortfolioService { * Change the status of the page. * @param page * @param status + * @param identity The user which does the change + * @param by The role of the user which does the change * @return */ - public Page changePageStatus(Page page, PageStatus status); + public Page changePageStatus(Page page, PageStatus status, Identity identity, Role by); /** * Close the section diff --git a/src/main/java/org/olat/modules/portfolio/handler/AbstractMediaHandler.java b/src/main/java/org/olat/modules/portfolio/handler/AbstractMediaHandler.java index aa48122ad1d2a8f2941c6afc6f3580a0992203c0..382328b871439baa5f34a447b0fa1aded8e03ffe 100644 --- a/src/main/java/org/olat/modules/portfolio/handler/AbstractMediaHandler.java +++ b/src/main/java/org/olat/modules/portfolio/handler/AbstractMediaHandler.java @@ -26,10 +26,13 @@ import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaHandler; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.model.MediaPart; -import org.olat.modules.portfolio.ui.editor.PageRunControllerElement; +import org.olat.modules.portfolio.model.StandardMediaRenderingHints; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; +import org.olat.modules.portfolio.ui.editor.PageRunControllerElement; import org.olat.modules.portfolio.ui.editor.PageRunElement; /** @@ -57,13 +60,13 @@ public abstract class AbstractMediaHandler implements MediaHandler, PageElementH } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints options) { if(element instanceof Media) { - return new PageRunControllerElement(getMediaController(ureq, wControl, (Media)element)); + return new PageRunControllerElement(getMediaController(ureq, wControl, (Media)element, new RenderingHints(options))); } if(element instanceof MediaPart) { MediaPart mediaPart = (MediaPart)element; - return new PageRunControllerElement(getMediaController(ureq, wControl, mediaPart.getMedia())); + return new PageRunControllerElement(getMediaController(ureq, wControl, mediaPart.getMedia(), new RenderingHints(options))); } return null; } @@ -71,11 +74,11 @@ public abstract class AbstractMediaHandler implements MediaHandler, PageElementH @Override public Controller getEditor(UserRequest ureq, WindowControl wControl, PageElement element) { if(element instanceof Media) { - return getMediaController(ureq, wControl, (Media)element); + return getMediaController(ureq, wControl, (Media)element, new StandardMediaRenderingHints()); } if(element instanceof MediaPart) { MediaPart mediaPart = (MediaPart)element; - return getMediaController(ureq, wControl, mediaPart.getMedia()); + return getMediaController(ureq, wControl, mediaPart.getMedia(), new StandardMediaRenderingHints()); } return null; } @@ -105,4 +108,28 @@ public abstract class AbstractMediaHandler implements MediaHandler, PageElementH return description; } } + + public static class RenderingHints implements MediaRenderingHints, PageElementRenderingHints { + + private final PageElementRenderingHints options; + + public RenderingHints(PageElementRenderingHints options) { + this.options = options; + } + + @Override + public boolean isToPdf() { + return options.isToPdf(); + } + + @Override + public boolean isOnePage() { + return options.isOnePage(); + } + + @Override + public boolean isExtendedMetadata() { + return options.isExtendedMetadata(); + } + } } diff --git a/src/main/java/org/olat/modules/portfolio/handler/CitationHandler.java b/src/main/java/org/olat/modules/portfolio/handler/CitationHandler.java index 632209ed779f6af4f91ff8cc8ba6c1db8f4d7153..34915d42b7a6d41f542a24b0a5d581b1e453396e 100644 --- a/src/main/java/org/olat/modules/portfolio/handler/CitationHandler.java +++ b/src/main/java/org/olat/modules/portfolio/handler/CitationHandler.java @@ -29,6 +29,7 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.manager.MediaDAO; import org.olat.modules.portfolio.ui.editor.InteractiveAddPageElementHandler; @@ -92,8 +93,8 @@ public class CitationHandler extends AbstractMediaHandler implements Interactive } @Override - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { - return new CitationMediaController(ureq, wControl, media); + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { + return new CitationMediaController(ureq, wControl, media, hints); } @Override diff --git a/src/main/java/org/olat/modules/portfolio/handler/EvaluationFormHandler.java b/src/main/java/org/olat/modules/portfolio/handler/EvaluationFormHandler.java index 865560d1595597249cca3d40be028979786534da..8d798babf6d7724bd24f9aa7189a93ff311f486a 100644 --- a/src/main/java/org/olat/modules/portfolio/handler/EvaluationFormHandler.java +++ b/src/main/java/org/olat/modules/portfolio/handler/EvaluationFormHandler.java @@ -46,9 +46,10 @@ import org.olat.modules.portfolio.model.AccessRights; import org.olat.modules.portfolio.model.EvaluationFormPart; import org.olat.modules.portfolio.ui.MultiEvaluationFormController; import org.olat.modules.portfolio.ui.PortfolioHomeController; -import org.olat.modules.portfolio.ui.editor.PageRunControllerElement; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; +import org.olat.modules.portfolio.ui.editor.PageRunControllerElement; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.repository.RepositoryEntry; @@ -71,7 +72,7 @@ public class EvaluationFormHandler implements PageElementHandler { } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints hints) { Controller ctrl = null; if(element instanceof EvaluationFormPart) { PortfolioService portfolioService = CoreSpringFactory.getImpl(PortfolioService.class); @@ -83,7 +84,7 @@ public class EvaluationFormHandler implements PageElementHandler { if(assignment == null) { ctrl = getController(ureq, wControl, body, eva); } else { - ctrl = getControllerForAssignment(ureq, wControl, body, assignment); + ctrl = getControllerForAssignment(ureq, wControl, body, assignment, hints.isOnePage()); } } @@ -117,7 +118,7 @@ public class EvaluationFormHandler implements PageElementHandler { return ctrl; } - private Controller getControllerForAssignment(UserRequest ureq, WindowControl wControl, PageBody body, Assignment assignment) { + private Controller getControllerForAssignment(UserRequest ureq, WindowControl wControl, PageBody body, Assignment assignment, boolean onePage) { PortfolioService portfolioService = CoreSpringFactory.getImpl(PortfolioService.class); //find the evaluation form @@ -150,26 +151,26 @@ public class EvaluationFormHandler implements PageElementHandler { } } else { if(hasRole(PortfolioRoles.owner, ureq.getIdentity(), accessRights)) { - boolean readOnly = (pageStatus == PageStatus.published) || (pageStatus == PageStatus.closed) || (pageStatus == PageStatus.deleted); + boolean readOnly = (pageStatus == PageStatus.published) || (pageStatus == PageStatus.closed) || (pageStatus == PageStatus.deleted) || onePage; Identity owner = getOwner(accessRights); List<Identity> coachesAndReviewers = getCoachesAndReviewers(accessRights); if(coachesAndReviewers.size() > 0) { - ctrl = new MultiEvaluationFormController(ureq, wControl, owner, coachesAndReviewers, body, re, false, readOnly, anonym); + ctrl = new MultiEvaluationFormController(ureq, wControl, owner, coachesAndReviewers, body, re, false, readOnly, onePage, anonym); } else { ctrl = new EvaluationFormController(ureq, wControl, ureq.getIdentity(), body, re, readOnly, false); } } else if(hasRole(PortfolioRoles.coach, ureq.getIdentity(), accessRights)) { Identity owner = getOwner(accessRights); List<Identity> coachesAndReviewers = getCoachesAndReviewers(accessRights); - boolean readOnly = (pageStatus == PageStatus.draft) || (pageStatus == PageStatus.closed) || (pageStatus == PageStatus.deleted); - ctrl = new MultiEvaluationFormController(ureq, wControl, owner, coachesAndReviewers, body, re, false, readOnly, anonym); + boolean readOnly = (pageStatus == PageStatus.draft) || (pageStatus == PageStatus.closed) || (pageStatus == PageStatus.deleted) || onePage; + ctrl = new MultiEvaluationFormController(ureq, wControl, owner, coachesAndReviewers, body, re, false, readOnly, onePage, anonym); } else if(hasRole(PortfolioRoles.reviewer, ureq.getIdentity(), accessRights) || hasRole(PortfolioRoles.invitee, ureq.getIdentity(), accessRights)) { - boolean readOnly = (pageStatus == PageStatus.draft) || (pageStatus == PageStatus.closed) || (pageStatus == PageStatus.deleted); + boolean readOnly = (pageStatus == PageStatus.draft) || (pageStatus == PageStatus.closed) || (pageStatus == PageStatus.deleted) || onePage; if(assignment.isReviewerSeeAutoEvaluation()) { Identity owner = getOwner(accessRights); List<Identity> reviewers = Collections.singletonList(ureq.getIdentity()); - ctrl = new MultiEvaluationFormController(ureq, wControl, owner, reviewers, body, re, true, readOnly, anonym); + ctrl = new MultiEvaluationFormController(ureq, wControl, owner, reviewers, body, re, true, readOnly, onePage, anonym); } else { ctrl = new EvaluationFormController(ureq, wControl, ureq.getIdentity(), body, re, readOnly, !readOnly); } diff --git a/src/main/java/org/olat/modules/portfolio/handler/FileHandler.java b/src/main/java/org/olat/modules/portfolio/handler/FileHandler.java index 9d9d59b66151e07f00fe1628dab7cf9bbba7b912..b34adbd5d7323d80570fd41d4a75a48e5c875037 100644 --- a/src/main/java/org/olat/modules/portfolio/handler/FileHandler.java +++ b/src/main/java/org/olat/modules/portfolio/handler/FileHandler.java @@ -39,6 +39,7 @@ import org.olat.core.util.vfs.VFSManager; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.manager.MediaDAO; import org.olat.modules.portfolio.manager.PortfolioFileStorage; @@ -184,8 +185,8 @@ public class FileHandler extends AbstractMediaHandler implements InteractiveAddP } @Override - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { - return new FileMediaController(ureq, wControl, media); + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { + return new FileMediaController(ureq, wControl, media, hints); } @Override diff --git a/src/main/java/org/olat/modules/portfolio/handler/ImageHandler.java b/src/main/java/org/olat/modules/portfolio/handler/ImageHandler.java index 99edd1a01ba5927e730291fc8fc08bb1ae1da7c9..242f8b146ec6d81b73de968d431faaf12824c622 100644 --- a/src/main/java/org/olat/modules/portfolio/handler/ImageHandler.java +++ b/src/main/java/org/olat/modules/portfolio/handler/ImageHandler.java @@ -22,14 +22,11 @@ package org.olat.modules.portfolio.handler; import java.io.File; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.commons.modules.bc.meta.MetaInfo; import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; import org.olat.core.commons.services.image.Size; import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.image.ImageComponent; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.util.CSSHelper; @@ -43,15 +40,12 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.manager.MediaDAO; import org.olat.modules.portfolio.manager.PortfolioFileStorage; -import org.olat.modules.portfolio.model.MediaPart; -import org.olat.modules.portfolio.ui.editor.PageRunComponent; import org.olat.modules.portfolio.ui.editor.InteractiveAddPageElementHandler; -import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementAddController; -import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.media.CollectImageMediaController; import org.olat.modules.portfolio.ui.media.ImageMediaController; import org.olat.modules.portfolio.ui.media.UploadMedia; @@ -70,7 +64,6 @@ import org.springframework.stereotype.Service; public class ImageHandler extends AbstractMediaHandler implements InteractiveAddPageElementHandler { public static final String IMAGE_TYPE = "image"; - private final AtomicInteger idGenerator = new AtomicInteger(); public static final Set<String> mimeTypes = new HashSet<>(); static { mimeTypes.add("image/gif"); @@ -168,38 +161,11 @@ public class ImageHandler extends AbstractMediaHandler implements InteractiveAdd public Media createMedia(AbstractArtefact artefact) { return null;//no specific image document in old portfolio } - - @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { - if(element instanceof Media) { - return new PageRunComponent(getContent(ureq, (Media)element)); - } - if(element instanceof MediaPart) { - MediaPart mediaPart = (MediaPart)element; - return new PageRunComponent(getContent(ureq, mediaPart.getMedia())); - } - return null; - } - - private ImageComponent getContent(UserRequest ureq, Media media) { - File mediaDir = new File(FolderConfig.getCanonicalRoot(), media.getStoragePath()); - File mediaFile = new File(mediaDir, media.getRootFilename()); - ImageComponent imageCmp = new ImageComponent(ureq.getUserSession(), "image_" + idGenerator.incrementAndGet()); - imageCmp.setMedia(mediaFile); - return imageCmp; - } @Override - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { - return new ImageMediaController(ureq, wControl, media); + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { + return new ImageMediaController(ureq, wControl, media, hints); } - - -/* - @Override - public Controller getEditor(UserRequest ureq, WindowControl wControl, PageElement element) { - return new ImageMediaEditorController(ureq, wControl, (MediaPart)element); - }*/ @Override public Controller getEditMediaController(UserRequest ureq, WindowControl wControl, Media media) { diff --git a/src/main/java/org/olat/modules/portfolio/handler/TextHandler.java b/src/main/java/org/olat/modules/portfolio/handler/TextHandler.java index 4f2251b7d7897732a9a0e2ac90b0a1c18f27e512..4905cea59761c9ad754b89b01a3202975d34f620 100644 --- a/src/main/java/org/olat/modules/portfolio/handler/TextHandler.java +++ b/src/main/java/org/olat/modules/portfolio/handler/TextHandler.java @@ -30,6 +30,7 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.manager.MediaDAO; import org.olat.modules.portfolio.ui.media.CollectTextMediaController; @@ -108,8 +109,8 @@ public class TextHandler extends AbstractMediaHandler { } @Override - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { - return new TextMediaController(ureq, wControl, media); + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { + return new TextMediaController(ureq, wControl, media, hints); } @Override diff --git a/src/main/java/org/olat/modules/portfolio/handler/VideoHandler.java b/src/main/java/org/olat/modules/portfolio/handler/VideoHandler.java index 7afcba02ca274f45278d80f2acd2ff39bac4fdfa..39a4b58bf78790251d086928f74eecd1d9cd1d84 100644 --- a/src/main/java/org/olat/modules/portfolio/handler/VideoHandler.java +++ b/src/main/java/org/olat/modules/portfolio/handler/VideoHandler.java @@ -22,14 +22,11 @@ package org.olat.modules.portfolio.handler; import java.io.File; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.commons.modules.bc.meta.MetaInfo; import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; import org.olat.core.commons.services.image.Size; import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.image.ImageComponent; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.util.CSSHelper; @@ -43,15 +40,12 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.manager.MediaDAO; import org.olat.modules.portfolio.manager.PortfolioFileStorage; -import org.olat.modules.portfolio.model.MediaPart; -import org.olat.modules.portfolio.ui.editor.PageRunComponent; import org.olat.modules.portfolio.ui.editor.InteractiveAddPageElementHandler; -import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementAddController; -import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.media.CollectVideoMediaController; import org.olat.modules.portfolio.ui.media.UploadMedia; import org.olat.modules.portfolio.ui.media.VideoMediaController; @@ -74,8 +68,6 @@ public class VideoHandler extends AbstractMediaHandler implements InteractiveAdd static { mimeTypes.add("video/mp4"); } - - private AtomicInteger idGenerator = new AtomicInteger(); @Autowired private MediaDAO mediaDao; @@ -166,31 +158,10 @@ public class VideoHandler extends AbstractMediaHandler implements InteractiveAdd public Media createMedia(AbstractArtefact artefact) { return null;//no specific image document in old portfolio } - - @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { - if(element instanceof Media) { - return new PageRunComponent(getContent(ureq, (Media)element)); - } - if(element instanceof MediaPart) { - MediaPart mediaPart = (MediaPart)element; - return new PageRunComponent(getContent(ureq, mediaPart.getMedia())); - } - return null; - } - - private ImageComponent getContent(UserRequest ureq, Media media) { - File mediaDir = new File(FolderConfig.getCanonicalRoot(), media.getStoragePath()); - File mediaFile = new File(mediaDir, media.getRootFilename()); - ImageComponent imageCmp = new ImageComponent(ureq.getUserSession(), "video_" + idGenerator.incrementAndGet()); - imageCmp.setMedia(mediaFile); - imageCmp.setMaxWithAndHeightToFitWithin(800, 600); - return imageCmp; - } @Override - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { - return new VideoMediaController(ureq, wControl, media); + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { + return new VideoMediaController(ureq, wControl, media, hints); } @Override diff --git a/src/main/java/org/olat/modules/portfolio/manager/PortfolioNotificationsHandler.java b/src/main/java/org/olat/modules/portfolio/manager/PortfolioNotificationsHandler.java index 6e8dea669267d0365e8a563bf4bbe420c6442448..35c1aefee563639ee7fcde2233decb10f1b27eb7 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioNotificationsHandler.java +++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioNotificationsHandler.java @@ -242,7 +242,8 @@ public class PortfolioNotificationsHandler implements NotificationsHandler { //page part Date partLastModified = (Date)object[1]; - if(secCallback.canViewElement(page)) { + Section section = page.getSection(); + if(secCallback.canViewElement(page) && secCallback.canViewElement(section)) { // page created if(isSameDay(pageCreationDate, pageLastModified) && pageCreationDate.compareTo(compareDate) >= 0) { if(!uniqueCreatePageKeys.containsKey(pageKey)) { diff --git a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java index 18de9c42d1512561ab8b263d925b9c7476a75dd8..7e5a0667a7baf211ebed69b8c77880a059ef0838 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java +++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java @@ -61,6 +61,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.fileresource.FileResourceManager; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentService; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.modules.forms.EvaluationFormSessionStatus; import org.olat.modules.forms.manager.EvaluationFormSessionDAO; @@ -1030,7 +1031,7 @@ public class PortfolioServiceImpl implements PortfolioService { } @Override - public Page changePageStatus(Page page, PageStatus status) { + public Page changePageStatus(Page page, PageStatus status, Identity identity, Role by) { PageStatus currentStatus = page.getPageStatus(); Page reloadedPage = pageDao.loadByKey(page.getKey()); ((PageImpl)reloadedPage).setPageStatus(status); @@ -1069,6 +1070,11 @@ public class PortfolioServiceImpl implements PortfolioService { } } } + if(reloadedPage.getSection() != null && reloadedPage.getSection().getBinder() != null) { + Binder binder = reloadedPage.getSection().getBinder(); + updateAssessmentEntryLastModification(binder, identity, by); + } + return pageDao.updatePage(reloadedPage); } @@ -1117,6 +1123,39 @@ public class PortfolioServiceImpl implements PortfolioService { reloadedSection = binderDao.updateSection(reloadedSection); return reloadedSection; } + + private void updateAssessmentEntryLastModification(Binder binder, Identity doer, Role by) { + if(binder.getEntry() == null) return; + + RepositoryEntry entry = binder.getEntry(); + List<Identity> assessedIdentities = getMembers(binder, PortfolioRoles.owner.name()); + + //order status from the entry / section + if("CourseModule".equals(entry.getOlatResource().getResourceableTypeName())) { + ICourse course = CourseFactory.loadCourse(entry); + CourseNode courseNode = course.getRunStructure().getNode(binder.getSubIdent()); + if(courseNode instanceof PortfolioCourseNode) { + PortfolioCourseNode pfNode = (PortfolioCourseNode)courseNode; + for(Identity assessedIdentity:assessedIdentities) { + UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course); + pfNode.updateLastModifications(userCourseEnv, doer, by); + } + } + } else { + OLATResource resource = ((BinderImpl)binder.getTemplate()).getOlatResource(); + RepositoryEntry referenceEntry = repositoryService.loadByResourceKey(resource.getKey()); + for(Identity assessedIdentity:assessedIdentities) { + AssessmentEntry assessmentEntry = assessmentService + .getOrCreateAssessmentEntry(assessedIdentity, null, binder.getEntry(), binder.getSubIdent(), referenceEntry); + if(by == Role.coach) { + assessmentEntry.setLastCoachModified(new Date()); + } else if(by == Role.user) { + assessmentEntry.setLastUserModified(new Date()); + } + assessmentService.updateAssessmentEntry(assessmentEntry); + } + } + } @Override public List<AssessmentSection> getAssessmentSections(BinderRef binder, Identity coach) { @@ -1212,7 +1251,7 @@ public class PortfolioServiceImpl implements PortfolioService { PortfolioCourseNode pfNode = (PortfolioCourseNode)courseNode; ScoreEvaluation scoreEval= new ScoreEvaluation(totalScore.floatValue(), totalPassed, binderStatus, true, true, binder.getKey()); UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course); - pfNode.updateUserScoreEvaluation(scoreEval, userCourseEnv, coachingIdentity, false); + pfNode.updateUserScoreEvaluation(scoreEval, userCourseEnv, coachingIdentity, false, Role.coach); } } else { OLATResource resource = ((BinderImpl)binder.getTemplate()).getOlatResource(); @@ -1268,7 +1307,7 @@ public class PortfolioServiceImpl implements PortfolioService { AssessmentEvaluation eval = pfNode.getUserScoreEvaluation(userCourseEnv); ScoreEvaluation scoreEval= new ScoreEvaluation(eval.getScore(), eval.getPassed(), status, true, fullyAssessed, binder.getKey()); - pfNode.updateUserScoreEvaluation(scoreEval, userCourseEnv, coachingIdentity, false); + pfNode.updateUserScoreEvaluation(scoreEval, userCourseEnv, coachingIdentity, false, Role.coach); } } else { OLATResource resource = ((BinderImpl)binder.getTemplate()).getOlatResource(); diff --git a/src/main/java/org/olat/modules/portfolio/model/CategoryImpl.java b/src/main/java/org/olat/modules/portfolio/model/CategoryImpl.java index 27875282bba6caeef6be645c4c0ce3601dd5b726..de3c44965720374539bb736b5f504c81b97a676d 100644 --- a/src/main/java/org/olat/modules/portfolio/model/CategoryImpl.java +++ b/src/main/java/org/olat/modules/portfolio/model/CategoryImpl.java @@ -81,6 +81,10 @@ public class CategoryImpl implements Persistable, CreateInfo, Category { } public void setName(String name) { + if (name != null && name.length() > 32) { + // cut, limted on db + name = name.substring(0, 32); + } this.name = name; } diff --git a/src/main/java/org/olat/modules/portfolio/model/ExtendedMediaRenderingHints.java b/src/main/java/org/olat/modules/portfolio/model/ExtendedMediaRenderingHints.java new file mode 100644 index 0000000000000000000000000000000000000000..2af88034fc279db91e9351d7d0f8b2cf3ebc2d86 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/model/ExtendedMediaRenderingHints.java @@ -0,0 +1,62 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio.model; + +import org.olat.modules.portfolio.MediaRenderingHints; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; + +/** + * + * Initial date: 24 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ExtendedMediaRenderingHints implements MediaRenderingHints, PageElementRenderingHints { + + private final boolean toPdf; + + private ExtendedMediaRenderingHints(boolean toPdf) { + this.toPdf = toPdf; + } + + @Override + public boolean isToPdf() { + return toPdf; + } + + @Override + public boolean isOnePage() { + return true; + } + + @Override + public boolean isExtendedMetadata() { + return true; + } + + public static PageElementRenderingHints toPdf() { + return new ExtendedMediaRenderingHints(true); + } + + public static PageElementRenderingHints toPrint() { + return new ExtendedMediaRenderingHints(false); + } + +} diff --git a/src/main/java/org/olat/modules/portfolio/model/StandardMediaRenderingHints.java b/src/main/java/org/olat/modules/portfolio/model/StandardMediaRenderingHints.java new file mode 100644 index 0000000000000000000000000000000000000000..8153a76e0d403a04bb29daee1dbd590c77387a02 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/model/StandardMediaRenderingHints.java @@ -0,0 +1,48 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio.model; + +import org.olat.modules.portfolio.MediaRenderingHints; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; + +/** + * + * Initial date: 24 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class StandardMediaRenderingHints implements MediaRenderingHints, PageElementRenderingHints { + + @Override + public boolean isToPdf() { + return false; + } + + @Override + public boolean isOnePage() { + return false; + } + + @Override + public boolean isExtendedMetadata() { + return false; + } + +} diff --git a/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java index c8b8c36b610c64c2f6c3e03b5e9a9c32c0868dd2..1242be9bdef2cfade65b6d91c50dd6292c6f2355 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java @@ -106,8 +106,8 @@ import org.springframework.beans.factory.annotation.Autowired; public abstract class AbstractPageListController extends FormBasicController implements Activateable2, TooledController, FlexiTableComponentDelegate { - public static final int PICTURE_WIDTH = 265; - public static final int PICTURE_HEIGHT = (PICTURE_WIDTH / 3) * 2; + public static final int PICTURE_WIDTH = 970 * 2; // max width for large images: 1294 * 75% , x2 for high res displays + public static final int PICTURE_HEIGHT = 230 * 2 ; // max size for large images, see CSS, x2 for high res displays protected TimelineElement timelineEl; private FormLink timelineSwitchOnButton, timelineSwitchOffButton; @@ -370,13 +370,14 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate { } protected PortfolioElementRow forgePageRow(UserRequest ureq, Page page, AssessmentSection assessmentSection, List<Assignment> assignments, - Map<OLATResourceable,List<Category>> categorizedElementMap, Map<Long,Long> numberOfCommentsMap) { + Map<OLATResourceable,List<Category>> categorizedElementMap, Map<Long,Long> numberOfCommentsMap, boolean selectElement) { Section section = page.getSection(); PortfolioElementRow row = new PortfolioElementRow(page, assessmentSection, config.isAssessable()); String openLinkId = "open_" + (++counter); FormLink openLink = uifactory.addFormLink(openLinkId, "open.full", "open.full.page", null, flc, Link.BUTTON_SMALL); openLink.setIconRightCSS("o_icon o_icon_start"); + openLink.setEnabled(selectElement); openLink.setPrimary(true); row.setOpenFormLink(openLink); openLink.setUserObject(row); diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderAssessmentController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderAssessmentController.java index 5e6a97b8b82ae221b3f633686b60eb43f9ffd199..1f19a13e1a4bf8c212b943047f1e87e1c7c0d701 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/BinderAssessmentController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/BinderAssessmentController.java @@ -23,8 +23,10 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; @@ -95,6 +97,8 @@ public class BinderAssessmentController extends FormBasicController { private boolean withScore; private boolean withPassed; + private Float minScore, maxScore; + private final String displayname; @Autowired private PortfolioService portfolioService; @@ -104,8 +108,11 @@ public class BinderAssessmentController extends FormBasicController { super(ureq, wControl, "section_assessment"); this.binder = binder; this.secCallback = secCallback; - this.withPassed = config.isWithPassed(); - this.withScore = config.isWithScore(); + withPassed = config.isWithPassed(); + withScore = config.isWithScore(); + minScore = config.getMinScore(); + maxScore = config.getMaxScore(); + displayname = config.getDisplayname(); initForm(ureq); loadModel(); } @@ -296,6 +303,50 @@ public class BinderAssessmentController extends FormBasicController { super.formInnerEvent(ureq, source, event); } + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + flc.contextRemove("scoreError"); + if(withScore && (maxScore != null || minScore != null)) { + double scoreTotal = 0.0d; + + Set<Section> visibleSections = new HashSet<>(); + List<AssessmentSectionWrapper> rows = model.getObjects(); + for(AssessmentSectionWrapper row:rows) { + BigDecimal score = row.getScore(); + if(row.getScoreEl() != null) { + String value = row.getScoreEl().getValue(); + if(StringHelper.containsNonWhitespace(value)) { + score = new BigDecimal(value); + } + } + if(score != null) { + scoreTotal += score.doubleValue(); + } + visibleSections.add(row.getSection()); + } + + // add score of other sections + List<AssessmentSection> assessmentSections = portfolioService.getAssessmentSections(binder, null); + for(AssessmentSection assessmentSection:assessmentSections) { + if(!visibleSections.contains(assessmentSection.getSection()) && assessmentSection.getScore() != null) { + scoreTotal += assessmentSection.getScore().doubleValue(); + } + } + + if(maxScore != null && (maxScore.doubleValue() < scoreTotal)) { + flc.contextPut("scoreError", translate("error.score", new String[] { "0", AssessmentHelper.getRoundedScore(maxScore), displayname })); + allOk &= false; + } else if(minScore != null && (minScore.doubleValue() > scoreTotal)) { + flc.contextPut("scoreError", translate("error.score", new String[] { "0", AssessmentHelper.getRoundedScore(maxScore), displayname })); + allOk &= false; + } + } + + return allOk & super.validateFormLogic(ureq); + } + @Override protected void formOK(UserRequest ureq) { commitChanges(); diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java index 6e6327a8d2448322c378a4aff39b352a51c611da..74295bb0d76d5fa5491959bf7e1bc8c7f73bae5e 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java @@ -397,12 +397,12 @@ public class BinderListController extends FormBasicController if(binder.isChanged()) { showInfo("warning.binder.synched"); } - BinderController binderCtrl = doOpenBinder(ureq, binder.getBinder()); + BinderController selectedBinderCtrl = doOpenBinder(ureq, binder.getBinder()); if(row instanceof BinderRow) { VFSLeaf image = portfolioService.getPosterImageLeaf(binder.getBinder()); ((BinderRow)row).setBackgroundImage(image); } - return binderCtrl; + return selectedBinderCtrl; } protected BinderController doOpenBinder(UserRequest ureq, Binder binder) { diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderOnePageController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderOnePageController.java new file mode 100644 index 0000000000000000000000000000000000000000..c157245e8d5e554cd1104123817acbe68e75e4b8 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/BinderOnePageController.java @@ -0,0 +1,226 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio.ui; + +import java.util.ArrayList; +import java.util.List; + +import org.olat.core.commons.services.commentAndRating.CommentAndRatingSecurityCallback; +import org.olat.core.commons.services.commentAndRating.ui.UserCommentsController; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.id.Identity; +import org.olat.core.id.OLATResourceable; +import org.olat.core.util.resource.OresHelper; +import org.olat.modules.portfolio.AssessmentSection; +import org.olat.modules.portfolio.Binder; +import org.olat.modules.portfolio.BinderRef; +import org.olat.modules.portfolio.BinderSecurityCallback; +import org.olat.modules.portfolio.BinderSecurityCallbackFactory; +import org.olat.modules.portfolio.MediaHandler; +import org.olat.modules.portfolio.Page; +import org.olat.modules.portfolio.PortfolioRoles; +import org.olat.modules.portfolio.PortfolioService; +import org.olat.modules.portfolio.Section; +import org.olat.modules.portfolio.handler.EvaluationFormHandler; +import org.olat.modules.portfolio.ui.editor.PageController; +import org.olat.modules.portfolio.ui.editor.PageElement; +import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; +import org.olat.modules.portfolio.ui.editor.PageProvider; +import org.olat.modules.portfolio.ui.editor.handler.HTMLRawPageElementHandler; +import org.olat.modules.portfolio.ui.editor.handler.SpacerElementHandler; +import org.olat.modules.portfolio.ui.editor.handler.TitlePageElementHandler; +import org.olat.modules.portfolio.ui.model.PortfolioElementRow; +import org.olat.modules.portfolio.ui.model.ReadOnlyCommentsSecurityCallback; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 22 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class BinderOnePageController extends BasicController { + + private final VelocityContainer mainVC; + + private int counter = 0; + private List<String> components = new ArrayList<>(); + private final PageElementRenderingHints renderingHints; + + @Autowired + private PortfolioService portfolioService; + + @Autowired + private UserManager userManager; + + public BinderOnePageController(UserRequest ureq, WindowControl wControl, + BinderRef binderRef, PageElementRenderingHints renderingHints, boolean print) { + super(ureq, wControl); + this.renderingHints = renderingHints; + + mainVC = createVelocityContainer("binder_one_page"); + mainVC.contextPut("components", components); + mainVC.contextPut("print", print); + mainVC.contextPut("mainCssClass", "o_binder_export"); + putInitialPanel(mainVC); + loadMetadataAndComponents(ureq, binderRef); + } + + public BinderOnePageController(UserRequest ureq, WindowControl wControl, + Page page, PageElementRenderingHints renderingHints, boolean print) { + super(ureq, wControl); + this.renderingHints = renderingHints; + + mainVC = createVelocityContainer("binder_one_page"); + mainVC.contextPut("components", components); + mainVC.contextPut("print", print); + mainVC.contextPut("mainCssClass", "o_page_export"); + putInitialPanel(mainVC); + loadPage(ureq, page); + } + + private void loadMetadataAndComponents(UserRequest ureq, BinderRef binderRef) { + Binder binder = portfolioService.getBinderByKey(binderRef.getKey()); + // load metadata + List<Identity> owners = portfolioService.getMembers(binder, PortfolioRoles.owner.name()); + StringBuilder ownerSb = new StringBuilder(); + for(Identity owner:owners) { + if(ownerSb.length() > 0) ownerSb.append(", "); + ownerSb.append(userManager.getUserDisplayName(owner)); + } + mainVC.contextPut("owners", ownerSb.toString()); + mainVC.contextPut("binderTitle", binder.getTitle()); + mainVC.contextPut("binderKey", binder.getKey()); + //load pages + List<Section> sections = portfolioService.getSections(binder); + List<Page> pages = portfolioService.getPages(binder, null); + + for(Section section:sections) { + loadSection(section); + for(Page page:pages) { + if(section.equals(page.getSection())) { + loadPage(ureq, page); + } + } + } + } + + private void loadSection(Section section) { + String id = "section_" + (++counter); + VelocityContainer rowVC = createVelocityContainer(id, "portfolio_element_row"); + + AssessmentSection assessmentSection = null; + PortfolioElementRow row = new PortfolioElementRow(section, assessmentSection, false, false); + rowVC.contextPut("row", row); + rowVC.contextPut("rowIndex", 0); + mainVC.put(id, rowVC); + components.add(id); + } + + + private void loadPage(UserRequest ureq, Page page) { + String id = "page_w_" + (++counter); + VelocityContainer pageVC = createVelocityContainer(id, "page_content_print"); + mainVC.put(id, pageVC); + components.add(id); + + BinderSecurityCallback secCallback = BinderSecurityCallbackFactory.getReadOnlyCallback(); + PageMetadataController metadatCtrl = new PageMetadataController(ureq, getWindowControl(), secCallback, page); + listenTo(metadatCtrl); + + Component pageMetaCmp = metadatCtrl.getInitialComponent(); + pageVC.put("meta", pageMetaCmp); + + PageController pageCtrl = new PageController(ureq, getWindowControl(), new PortfolioPageProvider(page), renderingHints); + listenTo(pageCtrl); + pageCtrl.loadElements(ureq); + + Component pageCmp = pageCtrl.getInitialComponent(); + pageVC.put("page", pageCmp); + + CommentAndRatingSecurityCallback commentSecCallback = new ReadOnlyCommentsSecurityCallback(); + OLATResourceable ores = OresHelper.createOLATResourceableInstance(Page.class, page.getKey()); + UserCommentsController commentsCtrl = new UserCommentsController(ureq, getWindowControl(), ores, null, commentSecCallback); + listenTo(commentsCtrl); + if(commentsCtrl.getNumOfComments() > 0) { + pageVC.put("comments", commentsCtrl.getInitialComponent()); + } + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } + + private class PortfolioPageProvider implements PageProvider { + + private final List<PageElementHandler> handlers = new ArrayList<>(); + + private Page page; + + public PortfolioPageProvider(Page page) { + this.page = page; + + //handler for title + TitlePageElementHandler titleRawHandler = new TitlePageElementHandler(); + handlers.add(titleRawHandler); + //handler for HTML code + HTMLRawPageElementHandler htlmRawHandler = new HTMLRawPageElementHandler(); + handlers.add(htlmRawHandler); + //handler for HTML code + SpacerElementHandler hrHandler = new SpacerElementHandler(); + handlers.add(hrHandler); + //handler for form + EvaluationFormHandler formHandler = new EvaluationFormHandler(); + handlers.add(formHandler); + + + List<MediaHandler> mediaHandlers = portfolioService.getMediaHandlers(); + for(MediaHandler mediaHandler:mediaHandlers) { + if(mediaHandler instanceof PageElementHandler) { + handlers.add((PageElementHandler)mediaHandler); + } + } + } + + @Override + public List<? extends PageElement> getElements() { + return portfolioService.getPageParts(page); + } + + @Override + public List<PageElementHandler> getAvailableHandlers() { + return handlers; + } + } + +} diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java index 34158338bba98084b2ff4efa68f392cbf052daa5..34d85f1888945c54e2e3d5e147f6d494c5bdee95 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java @@ -27,9 +27,12 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; +import org.olat.core.commons.fullWebApp.popup.BaseFullWebappPopupLayoutFactory; import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.dropdown.Dropdown; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions; @@ -41,12 +44,15 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.link.LinkPopupSettings; import org.olat.core.gui.components.stack.TooledStackedPanel; import org.olat.core.gui.components.stack.TooledStackedPanel.Align; 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.creator.ControllerCreator; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.media.MediaResource; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.ContextEntry; @@ -64,7 +70,10 @@ import org.olat.modules.portfolio.Page; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.PortfolioRoles; import org.olat.modules.portfolio.Section; +import org.olat.modules.portfolio.model.ExtendedMediaRenderingHints; import org.olat.modules.portfolio.ui.component.TimelinePoint; +import org.olat.modules.portfolio.ui.export.ExportBinderAsCPResource; +import org.olat.modules.portfolio.ui.export.ExportBinderAsPDFResource; import org.olat.modules.portfolio.ui.model.PortfolioElementRow; import org.olat.user.UserManager; import org.olat.util.logging.activity.LoggingResourceable; @@ -78,7 +87,8 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class BinderPageListController extends AbstractPageListController { - private Link newSectionLink, newEntryLink, newAssignmentLink; + private Link newSectionLink, newEntryLink, newAssignmentLink, + exportBinderAsCpLink, exportBinderAsPdfLink, printLink; private FormLink newSectionButton, previousSectionLink, nextSectionLink, showAllSectionsLink; private CloseableModalController cmc; @@ -110,6 +120,26 @@ public class BinderPageListController extends AbstractPageListController { @Override public void initTools() { + if(secCallback.canExportBinder()) { + Dropdown exportTools = new Dropdown("export.binder", "export.binder", false, getTranslator()); + exportTools.setElementCssClass("o_sel_pf_export_tools"); + exportTools.setIconCSS("o_icon o_icon_download"); + stackPanel.addTool(exportTools, Align.left); + + exportBinderAsCpLink = LinkFactory.createToolLink("export.binder.cp", translate("export.binder.cp"), this); + exportBinderAsCpLink.setIconLeftCSS("o_icon o_icon_download"); + exportTools.addComponent(exportBinderAsCpLink); + + printLink = LinkFactory.createToolLink("export.binder.onepage", translate("export.binder.onepage"), this); + printLink.setIconLeftCSS("o_icon o_icon_print"); + printLink.setPopup(new LinkPopupSettings(950, 750, "binder")); + exportTools.addComponent(printLink); + + //exportBinderAsPdfLink = LinkFactory.createToolLink("export.binder.pdf", translate("export.binder.pdf"), this); + //exportBinderAsPdfLink.setIconLeftCSS("o_icon o_filetype_pdf"); + //exportTools.addComponent(exportBinderAsPdfLink); + } + if(secCallback.canAddSection()) { newSectionLink = LinkFactory.createToolLink("new.section", translate("create.new.section"), this); newSectionLink.setIconLeftCSS("o_icon o_icon-lg o_icon_new_portfolio"); @@ -243,14 +273,15 @@ public class BinderPageListController extends AbstractPageListController { List<Page> pages = portfolioService.getPages(binder, searchString); for (Page page : pages) { - if(!secCallback.canViewElement(page)) { + boolean viewElement = secCallback.canViewElement(page); + boolean viewTitleElement = viewElement || secCallback.canViewTitleOfElement(page); + if(!viewTitleElement) { continue; } Section section = page.getSection(); - PortfolioElementRow pageRow = forgePageRow(ureq, page, sectionToAssessmentSectionMap.get(section), - sectionToAssignmentMap.get(section), categorizedElementMap, numberOfCommentsMap); + sectionToAssignmentMap.get(section), categorizedElementMap, numberOfCommentsMap, viewElement); rows.add(pageRow); if(secCallback.canAddPage(section)) { FormLink newEntryButton = uifactory.addFormLink("new.entry." + (++counter), "new.entry", "create.new.page", null, flc, Link.BUTTON); @@ -399,6 +430,12 @@ public class BinderPageListController extends AbstractPageListController { } else { doCreateNewAssignment(ureq, filteringSection); } + } else if(exportBinderAsCpLink == source) { + doExportBinderAsCP(ureq); + } else if(exportBinderAsPdfLink == source) { + doExportBinderAsPdf(ureq); + } else if(printLink == source) { + doPrint(ureq); } super.event(ureq, source, event); } @@ -562,6 +599,31 @@ public class BinderPageListController extends AbstractPageListController { cmc.activate(); } + private void doExportBinderAsCP(UserRequest ureq) { + MediaResource resource = new ExportBinderAsCPResource(binder, ureq, getLocale()); + ureq.getDispatchResult().setResultingMediaResource(resource); + } + + private void doExportBinderAsPdf(UserRequest ureq) { + MediaResource resource = new ExportBinderAsPDFResource(binder, ureq, getLocale()); + ureq.getDispatchResult().setResultingMediaResource(resource); + } + + private void doPrint(UserRequest ureq) { + ControllerCreator ctrlCreator = new ControllerCreator() { + @Override + public Controller createController(UserRequest lureq, WindowControl lwControl) { + BinderOnePageController printCtrl = new BinderOnePageController(lureq, lwControl, binder, + ExtendedMediaRenderingHints.toPrint(), true); + LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, lwControl, printCtrl); + layoutCtr.addDisposableChildController(printCtrl); // dispose controller on layout dispose + return layoutCtr; + } + }; + ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createPrintPopupLayout(ctrlCreator); + openInNewBrowserWindow(ureq, layoutCtrlr); + } + @Override protected void doOpenRow(UserRequest ureq, PortfolioElementRow row, boolean newElement) { if(row.isSection()) { diff --git a/src/main/java/org/olat/modules/portfolio/ui/CategoriesEditController.java b/src/main/java/org/olat/modules/portfolio/ui/CategoriesEditController.java new file mode 100644 index 0000000000000000000000000000000000000000..dafdab26c0a9db592bc74248f83b0b74c48e4c3d --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/CategoriesEditController.java @@ -0,0 +1,139 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio.ui; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +import org.olat.core.gui.components.form.flexible.elements.TextBoxListElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.modules.portfolio.Category; + +/** + * Reusable controller to show the list of categories / tags and edit them with + * a small edit button. When edited, an Event.CHANGED is fired + * + * Initial date: 28.07.2017<br> + * + * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com + * + */ +public class CategoriesEditController extends FormBasicController { + + private TextBoxListElement categoriesEl; + private FormLink editLink; + private FormSubmit saveButton; + + List<Category> categories; + + private Map<String,String> categoriesNames = new HashMap<>(); + private Map<String,Category> categoriesMap = new HashMap<>(); + + public CategoriesEditController(UserRequest ureq, WindowControl wControl, List<Category> categories) { + super(ureq, wControl, "categories_edit"); + this.categories = categories; + for(Category category:categories) { + categoriesNames.put(category.getName(), category.getName()); + categoriesMap.put(category.getName(), category); + } + initForm(ureq); + /* we add domID to categories_edit.html to reduce DIV count */ + this.flc.getFormItemComponent().setDomReplacementWrapperRequired(false); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + formLayout.setElementCssClass("o_sel_pf_edit_entry_tags_form"); + + categoriesEl = uifactory.addTextBoxListElement("categories", "categories", "categories.hint", categoriesNames, formLayout, getTranslator()); + categoriesEl.setHelpText(translate("categories.hint")); + categoriesEl.setElementCssClass("o_sel_ep_tagsinput"); + categoriesEl.setAllowDuplicates(false); + categoriesEl.setElementCssClass("o_block_inline"); + categoriesEl.getComponent().setSpanAsDomReplaceable(true); + + editLink = uifactory.addFormLink("edit", "edit", "edit", null, formLayout, Link.LINK); + editLink.setCustomEnabledLinkCSS("o_button_textstyle"); + + saveButton = uifactory.addFormSubmitButton("save", formLayout); + saveButton.setVisible(false); + saveButton.setElementCssClass("btn-xs"); + + // on init set to read-only + initFormEditableState(false); + } + + /** + * Internal helper to hide and disable elements of the form depending on the + * editable state of the form + * + * @param editable + */ + private void initFormEditableState(boolean editable) { + categoriesEl.setEnabled(editable); + editLink.setVisible(!editable); + saveButton.setVisible(editable); + // Special label when no categories are there + if (categoriesEl.getValueList().size() == 0) { + categoriesEl.setVisible(editable); + editLink.setI18nKey("categories.add"); + } else { + editLink.setI18nKey("edit"); + } + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + super.formInnerEvent(ureq, source, event); + if (source == editLink) { + initFormEditableState(true); + } + } + + @Override + protected void formOK(UserRequest ureq) { + fireEvent(ureq, Event.CHANGED_EVENT); + initFormEditableState(false); + } + + /** + * @return The list of categories as visually configured in the box + */ + public List<String> getUpdatedCategories() { + List<String> updatedCategories = categoriesEl.getValueList(); + return updatedCategories; + } + + @Override + protected void doDispose() { + // + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/DeletedPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/DeletedPageListController.java index c90c787a1d239c2a720d4dac8f6b7373eb4315b7..e04ddf53b8a43f35ab0db742a2fdbba7a54fd2be 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/DeletedPageListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/DeletedPageListController.java @@ -101,7 +101,7 @@ public class DeletedPageListController extends AbstractPageListController { List<Page> pages = portfolioService.searchDeletedPages(getIdentity(), searchString); List<PortfolioElementRow> rows = new ArrayList<>(pages.size()); for (Page page : pages) { - rows.add(forgePageRow(ureq, page, null, null, categorizedElementMap, numberOfCommentsMap)); + rows.add(forgePageRow(ureq, page, null, null, categorizedElementMap, numberOfCommentsMap, true)); } disposeRows();//clean up the posters diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java b/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java index 65f6dd5565482ebdccbef3ea182e8f2547aa9490..eb58a36a38bc71234822d175df35321a1f8edc9f 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java @@ -48,7 +48,6 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; -import org.olat.core.id.context.BusinessControlFactory; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; import org.olat.core.util.Formatter; @@ -60,6 +59,7 @@ import org.olat.modules.portfolio.PageStatus; import org.olat.modules.portfolio.PortfolioService; import org.olat.modules.portfolio.manager.MetadataXStream; import org.olat.modules.portfolio.model.BinderPageUsage; +import org.olat.modules.portfolio.model.StandardMediaRenderingHints; import org.olat.modules.portfolio.ui.event.MediaEvent; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; @@ -73,6 +73,7 @@ import org.springframework.beans.factory.annotation.Autowired; public class MediaDetailsController extends FormBasicController implements Activateable2, TooledController { private Link editLink, deleteLink; + private Link gotoOriginalLink; private final TooledStackedPanel stackPanel; private Controller mediaCtrl; @@ -128,36 +129,40 @@ public class MediaDetailsController extends FormBasicController implements Activ layoutCont.contextPut("description", StringHelper.xssScan(media.getDescription())); layoutCont.contextPut("iconCssClass", handler.getIconCssClass(media)); - mediaCtrl = handler.getMediaController(ureq, getWindowControl(), media); + mediaCtrl = handler.getMediaController(ureq, getWindowControl(), media, new StandardMediaRenderingHints()); if(mediaCtrl != null) { listenTo(mediaCtrl); layoutCont.put("media", mediaCtrl.getInitialComponent()); } + + String metaPage = velocity_root + "/media_details_metadata.html"; + FormLayoutContainer metaCont = FormLayoutContainer.createCustomFormLayout("meta", getTranslator(), metaPage); + layoutCont.add("meta", metaCont); + metaCont.setRootForm(mainForm); - layoutCont.contextPut("media", media); + metaCont.contextPut("media", media); String author = userManager.getUserDisplayName(media.getAuthor()); - layoutCont.contextPut("author", author); + metaCont.contextPut("author", author); if(media.getCollectionDate() != null) { String collectionDate = Formatter.getInstance(getLocale()).formatDate(media.getCollectionDate()); - layoutCont.contextPut("collectionDate", collectionDate); + metaCont.contextPut("collectionDate", collectionDate); } if (media.getBusinessPath() != null) { - String linkOriginal = BusinessControlFactory.getInstance().getURLFromBusinessPathString(media.getBusinessPath()); - layoutCont.contextPut("linkOriginal", linkOriginal); + gotoOriginalLink = LinkFactory.createLink("goto.original", metaCont.getFormItemComponent(), this); } if(StringHelper.containsNonWhitespace(media.getMetadataXml())) { Object metadata = MetadataXStream.get().fromXML(media.getMetadataXml()); - layoutCont.contextPut("metadata", metadata); + metaCont.contextPut("metadata", metadata); } List<Category> categories = portfolioService.getCategories(media); if(categories != null && categories.size() > 0) { Map<String,String> categoriesMap = categories.stream() .collect(Collectors.toMap(c -> c.getName(), c -> c.getName())); - TextBoxListElement categoriesEl = uifactory.addTextBoxListElement("categories", "categories", "categories.hint", categoriesMap, formLayout, getTranslator()); + TextBoxListElement categoriesEl = uifactory.addTextBoxListElement("categories", "categories", "categories.hint", categoriesMap, metaCont, getTranslator()); categoriesEl.setHelpText(translate("categories.hint")); categoriesEl.setElementCssClass("o_sel_ep_tagsinput"); categoriesEl.setEnabled(false); @@ -171,16 +176,16 @@ public class MediaDetailsController extends FormBasicController implements Activ FormLink link; if(binder.getBinderKey() == null) { - link = uifactory.addFormLink("binder_" + (++counter), "page", binder.getPageTitle(), null, layoutCont, Link.LINK | Link.NONTRANSLATED); + link = uifactory.addFormLink("binder_" + (++counter), "page", binder.getPageTitle(), null, metaCont, Link.LINK | Link.NONTRANSLATED); binderUniqueKeys.add(binder.getPageKey()); } else { - link = uifactory.addFormLink("binder_" + (++counter), "binder", binder.getBinderTitle(), null, layoutCont, Link.LINK | Link.NONTRANSLATED); + link = uifactory.addFormLink("binder_" + (++counter), "binder", binder.getBinderTitle(), null, metaCont, Link.LINK | Link.NONTRANSLATED); binderUniqueKeys.add(binder.getBinderKey()); } link.setUserObject(binder); binderLinks.add(link); } - layoutCont.contextPut("binderLinks", binderLinks); + metaCont.contextPut("binderLinks", binderLinks); } } @@ -209,6 +214,8 @@ public class MediaDetailsController extends FormBasicController implements Activ doEdit(ureq); } else if(deleteLink == source) { doConfirmDelete(ureq); + } else if(gotoOriginalLink == source) { + NewControllerFactory.getInstance().launch(media.getBusinessPath(), ureq, getWindowControl()); } super.event(ureq, source, event); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaMetadataController.java b/src/main/java/org/olat/modules/portfolio/ui/MediaMetadataController.java new file mode 100644 index 0000000000000000000000000000000000000000..3c97420d9300babbde5c3c2b80c4e6265fefffb5 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/MediaMetadataController.java @@ -0,0 +1,108 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio.ui; + +import java.util.List; +import java.util.stream.Collectors; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.modules.portfolio.Category; +import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.MediaHandler; +import org.olat.modules.portfolio.PortfolioService; +import org.olat.modules.portfolio.manager.MetadataXStream; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * A basic with encapsulate most of the metadata of a media. + * + * Initial date: 24 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class MediaMetadataController extends BasicController { + + private Media media; + + @Autowired + private UserManager userManager; + @Autowired + private PortfolioService portfolioService; + + public MediaMetadataController(UserRequest ureq, WindowControl wControl, Media media) { + super(ureq, wControl); + this.media = media; + + VelocityContainer mainVC = createVelocityContainer("media_details_metadata"); + putInitialPanel(mainVC); + loadMetadata(mainVC); + } + + private void loadMetadata(VelocityContainer metaVC) { + metaVC.contextPut("media", media); + String author = userManager.getUserDisplayName(media.getAuthor()); + metaVC.contextPut("author", author); + + MediaHandler handler = portfolioService.getMediaHandler(media.getType()); + String type = translate("artefact." + handler.getType()); + metaVC.contextPut("mediaType", type); + String iconCssClass = handler.getIconCssClass(media); + if(StringHelper.containsNonWhitespace(iconCssClass)) { + metaVC.contextPut("mediaIconCssClass", iconCssClass); + } + + if(media.getCollectionDate() != null) { + String collectionDate = Formatter.getInstance(getLocale()).formatDate(media.getCollectionDate()); + metaVC.contextPut("collectionDate", collectionDate); + } + + if(StringHelper.containsNonWhitespace(media.getMetadataXml())) { + Object metadata = MetadataXStream.get().fromXML(media.getMetadataXml()); + metaVC.contextPut("metadata", metadata); + } + + List<Category> categories = portfolioService.getCategories(media); + if(categories != null && categories.size() > 0) { + List<String> categoriesList = categories.stream().map(c -> c.getName()) + .collect(Collectors.toList()); + metaVC.contextPut("categoriesList", categoriesList); + } + } + + @Override + protected void doDispose() { + // + } + + + @Override + public void event(UserRequest ureq, Component source, Event event) { + // + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaUploadController.java b/src/main/java/org/olat/modules/portfolio/ui/MediaUploadController.java index 21f9c6871c292746047077924857dc9343001a09..0be3a2cd90b28e4ed9c875656a58583d9b4f970d 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/MediaUploadController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/MediaUploadController.java @@ -153,6 +153,12 @@ public class MediaUploadController extends FormBasicController implements PageEl } else if(getHandler() == null) { fileEl.setErrorKey("form.legende.mandatory", null); allOk &= false; + } + + titleEl.clearError(); + if (titleEl.isEmpty()) { + titleEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; } return allOk & super.validateFormLogic(ureq); @@ -184,6 +190,10 @@ public class MediaUploadController extends FormBasicController implements PageEl protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(fileEl == source) { getHandler(); + if (this.titleEl.isEmpty()) { + this.titleEl.setValue(fileEl.getUploadFileName()); + this.titleEl.getComponent().setDirty(true); + } } super.formInnerEvent(ureq, source, event); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/MultiEvaluationFormController.java b/src/main/java/org/olat/modules/portfolio/ui/MultiEvaluationFormController.java index a0bdc12a8f6be98aded196a875fe9807d800adba..ecdcc2c84b25c0a65b394e72ad4afd27fd799a34 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/MultiEvaluationFormController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/MultiEvaluationFormController.java @@ -63,8 +63,8 @@ public class MultiEvaluationFormController extends BasicController { private Link ownerLink; private Link compareLink; - private final VelocityContainer mainVC; - private final SegmentViewComponent segmentView; + private VelocityContainer mainVC; + private SegmentViewComponent segmentView; private List<Evaluator> evaluators = new ArrayList<>(); private List<Link> otherEvaluatorLinks = new ArrayList<>(); @@ -79,24 +79,89 @@ public class MultiEvaluationFormController extends BasicController { public MultiEvaluationFormController(UserRequest ureq, WindowControl wControl, Identity owner, List<Identity> otherEvaluators, PageBody anchor, RepositoryEntry formEntry, - boolean doneFirst, boolean readOnly, boolean anonym) { + boolean doneFirst, boolean readOnly, boolean onePage, boolean anonym) { super(ureq, wControl); this.owner = owner; this.anchor = anchor; this.readOnly = readOnly; this.doneFirst = doneFirst; this.formEntry = formEntry; + + if(onePage) { + initOnePageView(ureq, otherEvaluators, anonym); + } else { + initSegmentView(ureq, otherEvaluators, anonym); + } + putInitialPanel(mainVC); + } + + private void initOnePageView(UserRequest ureq, List<Identity> otherEvaluators, boolean anonym) { + mainVC = createVelocityContainer("multi_evaluation_one_page"); + List<EvaluatorPanel> panels = new ArrayList<>(); + mainVC.contextPut("panels", panels); + + boolean viewOthers = isViewOthers(); + + if(owner != null) { + String ownerFullname = userManager.getUserDisplayName(owner); + Evaluator evaluator = new Evaluator(owner, ownerFullname); + evaluators.add(evaluator); + boolean me = owner.equals(getIdentity()); + if(me || viewOthers) { + Controller ctrl = createEvalutationForm(ureq, owner); + String componentName = "panel_" + (++count); + panels.add(new EvaluatorPanel(evaluator, componentName, ctrl.getInitialComponent())); + mainVC.put(componentName, ctrl.getInitialComponent()); + } + } + + if(otherEvaluators != null && otherEvaluators.size() > 0) { + int countEva = 1; + for(Identity evaluator:otherEvaluators) { + boolean me = evaluator.equals(ureq.getIdentity()); + + String evaluatorFullname; + if(!me && anonym) { + evaluatorFullname = translate("anonym.evaluator", new String[] { Integer.toString(countEva++) }); + } else { + evaluatorFullname = userManager.getUserDisplayName(evaluator); + } + Evaluator eval = new Evaluator(evaluator, evaluatorFullname); + evaluators.add(eval); + if(me || viewOthers) { + Controller ctrl = createEvalutationForm(ureq, evaluator); + String componentName = "panel_" + (++count); + panels.add(new EvaluatorPanel(eval, componentName, ctrl.getInitialComponent())); + mainVC.put(componentName, ctrl.getInitialComponent()); + } + } + } + + if(viewOthers && (owner != null && otherEvaluators != null && otherEvaluators.size() > 0) || (otherEvaluators != null && otherEvaluators.size() > 1)) { + removeAsListenerAndDispose(compareEvaluationCtrl); + CompareEvaluationsFormController ctrl = new CompareEvaluationsFormController(ureq, getWindowControl(), evaluators, anchor, formEntry); + listenTo(ctrl); + + Evaluator eval = new Evaluator(null, translate("compare.evaluations")); + String componentName = "panel_" + (++count); + panels.add(new EvaluatorPanel(eval, componentName, ctrl.getInitialComponent())); + mainVC.put(componentName, ctrl.getInitialComponent()); + } + } + + private Controller createEvalutationForm(UserRequest ureq, Identity evaluator) { + boolean ro = readOnly || !evaluator.equals(getIdentity()); + boolean doneButton = !ro && evaluator.equals(getIdentity()) && (owner == null || !owner.equals(evaluator)); + EvaluationFormController evalutionFormCtrl = new EvaluationFormController(ureq, getWindowControl(), evaluator, anchor, formEntry, ro, doneButton); + listenTo(evalutionFormCtrl); + return evalutionFormCtrl; + } + private void initSegmentView(UserRequest ureq, List<Identity> otherEvaluators, boolean anonym) { mainVC = createVelocityContainer("multi_evaluation_form"); segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); - boolean viewOthers; - if(doneFirst) { - EvaluationFormSession session = evaluationFormManager.getSessionForPortfolioEvaluation(getIdentity(), anchor); - viewOthers = session == null ? false : session.getEvaluationFormSessionStatus() == EvaluationFormSessionStatus.done; - } else { - viewOthers = true; - } + boolean viewOthers = isViewOthers(); if(owner != null) { String ownerFullname = userManager.getUserDisplayName(owner); @@ -144,7 +209,17 @@ public class MultiEvaluationFormController extends BasicController { segmentView.setVisible(viewOthers); mainVC.put("segments", segmentView); - putInitialPanel(mainVC); + } + + private boolean isViewOthers() { + boolean viewOthers; + if(doneFirst) { + EvaluationFormSession session = evaluationFormManager.getSessionForPortfolioEvaluation(getIdentity(), anchor); + viewOthers = session == null ? false : session.getEvaluationFormSessionStatus() == EvaluationFormSessionStatus.done; + } else { + viewOthers = true; + } + return viewOthers; } @Override @@ -204,4 +279,30 @@ public class MultiEvaluationFormController extends BasicController { listenTo(compareEvaluationCtrl); mainVC.put("segmentCmp", compareEvaluationCtrl.getInitialComponent()); } + + public static class EvaluatorPanel { + + + private final Evaluator evaluator; + private final Component component; + private final String componentName; + + public EvaluatorPanel(Evaluator evaluator, String componentName, Component component) { + this.evaluator = evaluator; + this.component = component; + this.componentName = componentName; + } + + public Evaluator getEvaluator() { + return evaluator; + } + + public Component getComponent() { + return component; + } + + public String getComponentName() { + return componentName; + } + } } diff --git a/src/main/java/org/olat/modules/portfolio/ui/MyPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/MyPageListController.java index 628ac0b8aaf29ff9cf76362fbc44bb631a426270..fe38162ea57b2c1ea7ae5d04c79dcb7b991ffcad 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/MyPageListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/MyPageListController.java @@ -123,7 +123,7 @@ public class MyPageListController extends AbstractPageListController { } List<Assignment> assignmentList = pageToAssignments.get(page); - PortfolioElementRow row = forgePageRow(ureq, page, null, assignmentList, categorizedElementMap, numberOfCommentsMap); + PortfolioElementRow row = forgePageRow(ureq, page, null, assignmentList, categorizedElementMap, numberOfCommentsMap, true); rows.add(row); if(page.getSection() != null) { Section section = page.getSection(); diff --git a/src/main/java/org/olat/modules/portfolio/ui/PageMetadataController.java b/src/main/java/org/olat/modules/portfolio/ui/PageMetadataController.java index 54a537e5c64755c95028208a2507a081c8fd9240..45755407362db1569b570220938fac7ac3ad0e18 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/PageMetadataController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/PageMetadataController.java @@ -35,6 +35,7 @@ import org.olat.core.gui.components.image.ImageComponent; 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.controller.BasicController; @@ -68,13 +69,15 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class PageMetadataController extends BasicController { - public static final int PICTURE_WIDTH = 300; - public static final int PICTURE_HEIGHT = (PICTURE_WIDTH / 3) * 2;//max-height=200px is defined in css + public static final int PICTURE_WIDTH = 970 * 2; // max width for large images: 1294 * 75% , x2 for high res displays + public static final int PICTURE_HEIGHT = 300 * 2 ; // max size for large images, see CSS, x2 for high res displays private Link publishButton, revisionButton, closeButton, reopenButton; private ImageComponent imageCmp; private String mapperThumbnailUrl; private VelocityContainer mainVC; + + private CategoriesEditController categoriesEditCtr; private final Page page; private final List<Assignment> assignments; @@ -122,11 +125,20 @@ public class PageMetadataController extends BasicController { mainVC.contextPut("lastPublicationDate", page.getLastPublicationDate()); List<Category> categories = portfolioService.getCategories(page); - List<String> categoryNames = new ArrayList<>(categories.size()); - for(Category category:categories) { - categoryNames.add(category.getName()); + if (secCallback.canEditCategories(page)) { + // editable categories + categoriesEditCtr = new CategoriesEditController(ureq, getWindowControl(), categories); + listenTo(categoriesEditCtr); + mainVC.put("pageCategoriesCtr", categoriesEditCtr.getInitialComponent()); + } else { + // read-only categories + List<String> categoryNames = new ArrayList<>(categories.size()); + for(Category category:categories) { + categoryNames.add(category.getName()); + } + mainVC.contextPut("pageCategories", categoryNames); } - mainVC.contextPut("pageCategories", categoryNames); + mainVC.contextPut("lastModified", page.getLastModified()); if(StringHelper.containsNonWhitespace(page.getImagePath())) { @@ -228,6 +240,16 @@ public class PageMetadataController extends BasicController { fireEvent(ureq, new ReopenPageEvent()); } } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if (source == categoriesEditCtr) { + if (event == Event.CHANGED_EVENT) { + portfolioService.updateCategories(page, categoriesEditCtr.getUpdatedCategories()); + fireEvent(ureq, Event.CHANGED_EVENT); + } + } + } public class DocumentMapper implements Mapper { diff --git a/src/main/java/org/olat/modules/portfolio/ui/PageRunController.java b/src/main/java/org/olat/modules/portfolio/ui/PageRunController.java index 3901a474f9f146744f66fbc8a53de8b258c6ee1c..863b79d7ebec899464d102c72e6c107799264dc8 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/PageRunController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/PageRunController.java @@ -22,13 +22,17 @@ package org.olat.modules.portfolio.ui; import java.util.ArrayList; import java.util.List; +import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; +import org.olat.core.commons.fullWebApp.popup.BaseFullWebappPopupLayoutFactory; import org.olat.core.commons.services.commentAndRating.CommentAndRatingDefaultSecurityCallback; import org.olat.core.commons.services.commentAndRating.CommentAndRatingSecurityCallback; import org.olat.core.commons.services.commentAndRating.ui.UserCommentsAndRatingsController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.dropdown.Dropdown; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.link.LinkPopupSettings; import org.olat.core.gui.components.stack.TooledController; import org.olat.core.gui.components.stack.TooledStackedPanel; import org.olat.core.gui.components.stack.TooledStackedPanel.Align; @@ -37,10 +41,12 @@ 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.controller.BasicController; +import org.olat.core.gui.control.creator.ControllerCreator; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.gui.media.MediaResource; import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; @@ -57,7 +63,9 @@ import org.olat.modules.portfolio.PageStatus; import org.olat.modules.portfolio.PortfolioService; import org.olat.modules.portfolio.Section; import org.olat.modules.portfolio.handler.EvaluationFormHandler; +import org.olat.modules.portfolio.model.ExtendedMediaRenderingHints; import org.olat.modules.portfolio.model.MediaPart; +import org.olat.modules.portfolio.model.StandardMediaRenderingHints; import org.olat.modules.portfolio.ui.editor.AddElementInfos; import org.olat.modules.portfolio.ui.editor.FullEditorSecurityCallback; import org.olat.modules.portfolio.ui.editor.InteractiveAddPageElementHandler; @@ -68,6 +76,7 @@ import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementAddController; import org.olat.modules.portfolio.ui.editor.PageElementEditorController; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; import org.olat.modules.portfolio.ui.editor.PageProvider; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.editor.SimpleAddPageElementHandler; @@ -82,6 +91,7 @@ import org.olat.modules.portfolio.ui.event.PageRemovedEvent; import org.olat.modules.portfolio.ui.event.PublishEvent; import org.olat.modules.portfolio.ui.event.ReopenPageEvent; import org.olat.modules.portfolio.ui.event.RevisionEvent; +import org.olat.modules.portfolio.ui.export.ExportBinderAsPDFResource; import org.olat.modules.portfolio.ui.model.ReadOnlyCommentsSecurityCallback; import org.springframework.beans.factory.annotation.Autowired; @@ -94,7 +104,8 @@ import org.springframework.beans.factory.annotation.Autowired; public class PageRunController extends BasicController implements TooledController, Activateable2 { private VelocityContainer mainVC; - private Link editLink, editMetadataLink, moveToTrashLink, restoreLink, deleteLink; + private Link editLink, editMetadataLink, moveToTrashLink, restoreLink, deleteLink, + printLink, exportPageAsPdfLink; protected final TooledStackedPanel stackPanel; private CloseableModalController cmc; @@ -130,7 +141,7 @@ public class PageRunController extends BasicController implements TooledControll mainVC.contextPut("pageTitle", page.getTitle()); loadMeta(ureq); - pageCtrl = new PageController(ureq, getWindowControl(), new PortfolioPageProvider()); + pageCtrl = new PageController(ureq, getWindowControl(), new PortfolioPageProvider(), new StandardMediaRenderingHints()); listenTo(pageCtrl); mainVC.put("page", pageCtrl.getInitialComponent()); loadModel(ureq, false); @@ -144,6 +155,10 @@ public class PageRunController extends BasicController implements TooledControll listenTo(pageEditCtrl); mainVC.contextPut("isPersonalBinder", (!secCallback.canNewAssignment() && secCallback.canEditMetadataBinder())); mainVC.put("page", pageEditCtrl.getInitialComponent()); + // Remove comments controller in edit mode, save button confuses user + if(commentsCtrl != null && commentsCtrl.getCommentsCount() == 0) { + mainVC.remove(commentsCtrl.getInitialComponent()); + } } } @@ -152,12 +167,27 @@ public class PageRunController extends BasicController implements TooledControll editLink(!openInEditMode); stackPanel.addTool(editLink, Align.left); - editMetadataLink = LinkFactory.createToolLink("edit.page.metadata", translate("edit.page.metadata"), this); editMetadataLink.setIconLeftCSS("o_icon o_icon-lg o_icon_edit_metadata"); editMetadataLink.setVisible(secCallback.canEditPageMetadata(page, assignments)); stackPanel.addTool(editMetadataLink, Align.left); + if(secCallback.canExportBinder()) { + Dropdown exportTools = new Dropdown("export.page", "export.page", false, getTranslator()); + exportTools.setElementCssClass("o_sel_pf_export_tools"); + exportTools.setIconCSS("o_icon o_icon_download"); + stackPanel.addTool(exportTools, Align.left); + + printLink = LinkFactory.createToolLink("export.page.onepage", translate("export.page.onepage"), this); + printLink.setIconLeftCSS("o_icon o_icon_print"); + printLink.setPopup(new LinkPopupSettings(950, 750, "binder")); + exportTools.addComponent(printLink); + + //exportPageAsPdfLink = LinkFactory.createToolLink("export.page.pdf", translate("export.page.pdf"), this); + //exportPageAsPdfLink.setIconLeftCSS("o_icon o_filetype_pdf"); + //exportTools.addComponent(exportPageAsPdfLink); + } + moveToTrashLink = LinkFactory.createToolLink("delete.page", translate("delete.page"), this); moveToTrashLink.setIconLeftCSS("o_icon o_icon-lg o_icon_delete_item"); moveToTrashLink.setElementCssClass("o_sel_pf_move_page_to_trash"); @@ -285,7 +315,10 @@ public class PageRunController extends BasicController implements TooledControll doConfirmClose(ureq); } else if(event instanceof ReopenPageEvent) { doConfirmReopen(ureq); - } + } else if(event == Event.CHANGED_EVENT) { + // categories modified, just propagate + fireEvent(ureq, Event.CHANGED_EVENT); + } } else if(restorePageCtrl == source) { if(event == Event.DONE_EVENT) { loadMeta(ureq); @@ -348,6 +381,10 @@ public class PageRunController extends BasicController implements TooledControll doRestorePage(ureq); } else if(deleteLink == source) { doConfirmDelete(ureq); + } else if(printLink == source) { + doPrint(ureq); + } else if(exportPageAsPdfLink == source) { + doExportBinderAsPdf(ureq); } } @@ -393,7 +430,7 @@ public class PageRunController extends BasicController implements TooledControll } private void doPublish(UserRequest ureq) { - page = portfolioService.changePageStatus(page, PageStatus.published); + page = portfolioService.changePageStatus(page, PageStatus.published, getIdentity(), secCallback.getRole()); stackPanel.popUpToController(this); loadMeta(ureq); loadModel(ureq, false); @@ -409,7 +446,7 @@ public class PageRunController extends BasicController implements TooledControll } private void doRevision(UserRequest ureq) { - page = portfolioService.changePageStatus(page, PageStatus.inRevision); + page = portfolioService.changePageStatus(page, PageStatus.inRevision, getIdentity(), secCallback.getRole()); stackPanel.popUpToController(this); loadMeta(ureq); loadModel(ureq, false); @@ -423,7 +460,7 @@ public class PageRunController extends BasicController implements TooledControll } private void doClose(UserRequest ureq) { - page = portfolioService.changePageStatus(page, PageStatus.closed); + page = portfolioService.changePageStatus(page, PageStatus.closed, getIdentity(), secCallback.getRole()); stackPanel.popUpToController(this); loadMeta(ureq); loadModel(ureq, true); @@ -437,7 +474,7 @@ public class PageRunController extends BasicController implements TooledControll } private void doReopen(UserRequest ureq) { - page = portfolioService.changePageStatus(page, PageStatus.published); + page = portfolioService.changePageStatus(page, PageStatus.published, getIdentity(), secCallback.getRole()); stackPanel.popUpToController(this); loadMeta(ureq); loadModel(ureq, true); @@ -471,6 +508,11 @@ public class PageRunController extends BasicController implements TooledControll removeAsListenerAndDispose(pageEditCtrl); if(Boolean.FALSE.equals(editLink.getUserObject())) { doRunPage(ureq); + // Add comments controller again in run mode, maybe removed by + // previous edit mode entering + if(commentsCtrl != null) { + mainVC.put("comments", commentsCtrl.getInitialComponent()); + } } else { pageEditCtrl = new PageEditorController(ureq, getWindowControl(), new PortfolioPageEditorProvider(), new FullEditorSecurityCallback(), getTranslator()); @@ -478,6 +520,10 @@ public class PageRunController extends BasicController implements TooledControll mainVC.contextPut("isPersonalBinder", (!secCallback.canNewAssignment() && secCallback.canEditMetadataBinder())); mainVC.put("page", pageEditCtrl.getInitialComponent()); editLink(false); + // Remove comments controller in edit mode, save button confuses user + if(commentsCtrl != null && commentsCtrl.getCommentsCount() == 0) { + mainVC.remove(commentsCtrl.getInitialComponent()); + } } } @@ -498,6 +544,25 @@ public class PageRunController extends BasicController implements TooledControll listenTo(cmc); cmc.activate(); } + + private void doExportBinderAsPdf(UserRequest ureq) { + MediaResource resource = new ExportBinderAsPDFResource(page, ureq, getLocale()); + ureq.getDispatchResult().setResultingMediaResource(resource); + } + + private void doPrint(UserRequest ureq) { + ControllerCreator ctrlCreator = new ControllerCreator() { + @Override + public Controller createController(UserRequest lureq, WindowControl lwControl) { + BinderOnePageController printCtrl = new BinderOnePageController(lureq, lwControl, page, ExtendedMediaRenderingHints.toPrint(), true); + LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, lwControl, printCtrl); + layoutCtr.addDisposableChildController(printCtrl); // dispose controller on layout dispose + return layoutCtr; + } + }; + ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createPrintPopupLayout(ctrlCreator); + openInNewBrowserWindow(ureq, layoutCtrlr); + } private class PortfolioPageProvider implements PageProvider { @@ -643,7 +708,7 @@ public class PageRunController extends BasicController implements TooledControll } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints options) { return null; } diff --git a/src/main/java/org/olat/modules/portfolio/ui/PortfolioAssessmentDetailsController.java b/src/main/java/org/olat/modules/portfolio/ui/PortfolioAssessmentDetailsController.java index bb251a6e89a962b45b7925cf565ab226c798cb59..c101e8b656a31939788f3275612c248313c5d968 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/PortfolioAssessmentDetailsController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/PortfolioAssessmentDetailsController.java @@ -44,6 +44,8 @@ import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; /** + * This is the assessment view for a portfolio resource. The coaches can see + * all sections. * * Initial date: 28.06.2016<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com @@ -123,7 +125,7 @@ public class PortfolioAssessmentDetailsController extends BasicController { mainVC.contextPut("returnDate", returnDate); List<AccessRights> rights = portfolioService.getAccessRights(loadedBinder, getIdentity()); - BinderSecurityCallback secCallback = BinderSecurityCallbackFactory.getCallbackForCoach(loadedBinder, rights); + BinderSecurityCallback secCallback = BinderSecurityCallbackFactory.getCallbackForCourseCoach(loadedBinder, rights); BinderConfiguration config = BinderConfiguration.createConfig(loadedBinder); assessmentCtrl = new BinderAssessmentController(ureq, getWindowControl(), diff --git a/src/main/java/org/olat/modules/portfolio/ui/RestorePageController.java b/src/main/java/org/olat/modules/portfolio/ui/RestorePageController.java index d0ed978cba332eb5caef7d2ed7e78dace59c70e2..a12e31ca98fd9ccd70106eb5656865699abbbfc8 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/RestorePageController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/RestorePageController.java @@ -33,6 +33,7 @@ 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.modules.assessment.Role; import org.olat.modules.portfolio.Binder; import org.olat.modules.portfolio.Page; import org.olat.modules.portfolio.PageStatus; @@ -158,7 +159,7 @@ public class RestorePageController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { - page = portfolioService.changePageStatus(page, PageStatus.draft); + page = portfolioService.changePageStatus(page, PageStatus.draft, getIdentity(), Role.user); SectionRef selectSection = getSelectedSection(); if((page.getSection() == null && selectSection != null) || diff --git a/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java b/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java index 78e5deb2b64169150963e489d7bbe12ae2d9199b..aa457b0f646a4eca118d215b5352bce0474b9d74 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java @@ -24,6 +24,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; +import org.olat.core.commons.fullWebApp.popup.BaseFullWebappPopupLayoutFactory; import org.olat.core.commons.services.commentAndRating.CommentAndRatingDefaultSecurityCallback; import org.olat.core.commons.services.commentAndRating.CommentAndRatingSecurityCallback; import org.olat.core.commons.services.commentAndRating.ui.UserCommentsController; @@ -33,6 +35,7 @@ import org.olat.core.gui.components.dropdown.Dropdown; import org.olat.core.gui.components.dropdown.DropdownOrientation; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.link.LinkPopupSettings; import org.olat.core.gui.components.stack.TooledController; import org.olat.core.gui.components.stack.TooledStackedPanel; import org.olat.core.gui.components.stack.TooledStackedPanel.Align; @@ -41,10 +44,12 @@ 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.controller.BasicController; +import org.olat.core.gui.control.creator.ControllerCreator; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.gui.media.MediaResource; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.ContextEntry; @@ -66,12 +71,15 @@ import org.olat.modules.portfolio.PortfolioService; import org.olat.modules.portfolio.Section; import org.olat.modules.portfolio.SectionStatus; import org.olat.modules.portfolio.model.BinderStatistics; +import org.olat.modules.portfolio.model.ExtendedMediaRenderingHints; import org.olat.modules.portfolio.model.SectionRefImpl; import org.olat.modules.portfolio.ui.event.DeleteBinderEvent; import org.olat.modules.portfolio.ui.event.PageDeletedEvent; import org.olat.modules.portfolio.ui.event.PageRemovedEvent; import org.olat.modules.portfolio.ui.event.RestoreBinderEvent; import org.olat.modules.portfolio.ui.event.SectionSelectionEvent; +import org.olat.modules.portfolio.ui.export.ExportBinderAsCPResource; +import org.olat.modules.portfolio.ui.export.ExportBinderAsPDFResource; import org.olat.modules.portfolio.ui.model.ReadOnlyCommentsSecurityCallback; import org.olat.modules.portfolio.ui.renderer.PortfolioRendererHelper; import org.olat.user.UserManager; @@ -87,7 +95,8 @@ import org.springframework.beans.factory.annotation.Autowired; public class TableOfContentController extends BasicController implements TooledController, Activateable2 { private Link newSectionTool, newSectionButton, newEntryLink, newAssignmentLink, - editBinderMetadataLink, moveToTrashBinderLink, deleteBinderLink, restoreBinderLink; + editBinderMetadataLink, moveToTrashBinderLink, deleteBinderLink, restoreBinderLink, + exportBinderAsCpLink, printLink, exportBinderAsPdfLink; private final VelocityContainer mainVC; private final TooledStackedPanel stackPanel; @@ -162,6 +171,26 @@ public class TableOfContentController extends BasicController implements TooledC stackPanel.addTool(moveToTrashBinderLink, Align.left); } + if(secCallback.canExportBinder()) { + Dropdown exportTools = new Dropdown("export.binder", "export.binder", false, getTranslator()); + exportTools.setElementCssClass("o_sel_pf_export_tools"); + exportTools.setIconCSS("o_icon o_icon_download"); + stackPanel.addTool(exportTools, Align.left); + + exportBinderAsCpLink = LinkFactory.createToolLink("export.binder.cp", translate("export.binder.cp"), this); + exportBinderAsCpLink.setIconLeftCSS("o_icon o_icon_download"); + exportTools.addComponent(exportBinderAsCpLink); + + printLink = LinkFactory.createToolLink("export.binder.onepage", translate("export.binder.onepage"), this); + printLink.setIconLeftCSS("o_icon o_icon_print"); + printLink.setPopup(new LinkPopupSettings(950, 750, "binder")); + exportTools.addComponent(printLink); + + //exportBinderAsPdfLink = LinkFactory.createToolLink("export.binder.pdf", translate("export.binder.pdf"), this); + //exportBinderAsPdfLink.setIconLeftCSS("o_icon o_filetype_pdf"); + //exportTools.addComponent(exportBinderAsPdfLink); + } + if(secCallback.canDeleteBinder(binder)) { deleteBinderLink = LinkFactory.createToolLink("delete.binder", translate("delete.binder"), this); deleteBinderLink.setIconLeftCSS("o_icon o_icon-lg o_icon_delete_item"); @@ -245,10 +274,14 @@ public class TableOfContentController extends BasicController implements TooledC List<Page> pages = portfolioService.getPages(binder, null); for(Page page:pages) { Section section = page.getSection(); - if(secCallback.canViewElement(page) && section != null && sectionMap.containsKey(section.getKey())) { - SectionRow sectionRow = sectionMap.get(section.getKey()); - PageRow pageRow = forgePageRow(page, numberOfCommentsMap); - sectionRow.getPages().add(pageRow); + if(section != null && sectionMap.containsKey(section.getKey())) { + boolean viewElement = secCallback.canViewElement(page); + boolean viewTitleElement = secCallback.canViewTitleOfElement(page); + if(viewElement || viewTitleElement) { + SectionRow sectionRow = sectionMap.get(section.getKey()); + PageRow pageRow = forgePageRow(page, numberOfCommentsMap, viewElement); + sectionRow.getPages().add(pageRow); + } } } mainVC.contextPut("sections", sectionRows); @@ -350,7 +383,7 @@ public class TableOfContentController extends BasicController implements TooledC return sectionRow; } - private PageRow forgePageRow(Page page, Map<Long,Long> numberOfCommentsMap) { + private PageRow forgePageRow(Page page, Map<Long,Long> numberOfCommentsMap, boolean selectElement) { PageRow pageRow = new PageRow(page); String pageId = "page" + (++counter); @@ -358,6 +391,7 @@ public class TableOfContentController extends BasicController implements TooledC Link openLink = LinkFactory.createCustomLink(pageId, "open_page", title, Link.LINK | Link.NONTRANSLATED, mainVC, this); openLink.setElementCssClass("o_pf_open_entry"); openLink.setUserObject(pageRow); + openLink.setEnabled(selectElement); pageRow.setOpenLink(openLink); Long numOfComments = numberOfCommentsMap.get(page.getKey()); @@ -523,6 +557,12 @@ public class TableOfContentController extends BasicController implements TooledC doConfirmDeleteBinder(ureq); } else if(restoreBinderLink == source) { doConfirmRestore(ureq); + } else if(exportBinderAsCpLink == source) { + doExportBinderAsCP(ureq); + } else if(printLink == source) { + doPrint(ureq); + } else if(exportBinderAsPdfLink == source) { + doExportBinderAsPdf(ureq); } else if(source instanceof Link) { Link link = (Link)source; String cmd = link.getCommand(); @@ -769,6 +809,30 @@ public class TableOfContentController extends BasicController implements TooledC showInfo("delete.binder.success"); } + private void doExportBinderAsCP(UserRequest ureq) { + MediaResource resource = new ExportBinderAsCPResource(binder, ureq, getLocale()); + ureq.getDispatchResult().setResultingMediaResource(resource); + } + + private void doExportBinderAsPdf(UserRequest ureq) { + MediaResource resource = new ExportBinderAsPDFResource(binder, ureq, getLocale()); + ureq.getDispatchResult().setResultingMediaResource(resource); + } + + private void doPrint(UserRequest ureq) { + ControllerCreator ctrlCreator = new ControllerCreator() { + @Override + public Controller createController(UserRequest lureq, WindowControl lwControl) { + BinderOnePageController printCtrl = new BinderOnePageController(lureq, lwControl, binder, ExtendedMediaRenderingHints.toPrint(), true); + LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, lwControl, printCtrl); + layoutCtr.addDisposableChildController(printCtrl); // dispose controller on layout dispose + return layoutCtr; + } + }; + ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createPrintPopupLayout(ctrlCreator); + openInNewBrowserWindow(ureq, layoutCtrlr); + } + public class PageRow { private final Page page; diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/binder_one_page.html b/src/main/java/org/olat/modules/portfolio/ui/_content/binder_one_page.html new file mode 100644 index 0000000000000000000000000000000000000000..c649007b5829a9f1362e22d40afce0230114180a --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/binder_one_page.html @@ -0,0 +1,23 @@ +<div class="$mainCssClass"> +#if ($binderTitle) + <div class="o_binder o_print_break_after"> + <h1>$r.translate("binder.title", $binderTitle) + #if($owners && !$owners.isEmpty()) + <br /> + <small>$r.translate("binder.by",$owners)</small> + #end + </h1> + </div> +#end +#foreach($component in $components) + $r.render($component) +#end +#if($r.isTrue($print)) +<script type='text/javascript'> +/* <![CDATA[ */ + ## Execute deferred. Gives browser the time to finish the page rendering first before executing the print dialog. + jQuery(function() {window.print();}); +/* ]]> */ +</script> +#end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/categories_edit.html b/src/main/java/org/olat/modules/portfolio/ui/_content/categories_edit.html new file mode 100644 index 0000000000000000000000000000000000000000..fecfa11114333fe061db5236297e4370a234e4b6 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/categories_edit.html @@ -0,0 +1,3 @@ +<div #if(!$!f.domReplacementWrapperRequired) id="$r.getCId()" #end class="o_portfolio_categories_edit o_block_inline"> +$r.render("categories") $r.render("edit") $r.render("save") +</div> diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html b/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html index fe49a2c6da5529711d22a365a866967f7808e1ae..1cb728ee0f770c9af22abfe9a78edb07b299cbcd 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html @@ -5,100 +5,6 @@ <div class="row o_block_large"> <div class="col-md-6">$r.render("media")</div> <div class="col-md-6"> - <div class="panel panel-default o_artefact"> - <table class="table table-condensed table-striped"><tbody> - #if($r.isNotEmpty($author)) - <tr><th>$r.translate("author")</th> - <td>$r.escapeHtml($author)</td></tr> - #end - #if($r.isNotEmpty($collectionDate)) - <tr><th>$r.translate("artefact.collect.date")</th> - <td>$r.escapeHtml($collectionDate)</td></tr> - #end - #if($r.isNotEmpty($linkOriginal)) - <tr><th>$r.translate("artefact.collect.link")</th> - <td><input type="text" value="$r.escapeHtml($linkOriginal)" style="width:100%;" onclick="this.select();"/></td></tr> - #end - #if($r.isNotEmpty($media.creators)) - <tr><th>$r.translate("creators")</th> - <td>$r.escapeHtml($media.creators)</td></tr> - #end - #if($r.isNotEmpty($media.place)) - <tr><th>$r.translate("place")</th> - <td>$r.escapeHtml($media.place)</td></tr> - #end - #if($r.isNotEmpty($media.publisher)) - <tr><th>$r.translate("publisher")</th> - <td>$r.escapeHtml($media.publisher)</td></tr> - #end - #if($r.isNotEmpty($media.url)) - <tr><th>$r.translate("url")</th> - <td>$r.escapeHtml($media.url)</td></tr> - #end - #if($r.isNotEmpty($media.source)) - <tr><th>$r.translate("source")</th> - <td>$r.escapeHtml($media.source)</td></tr> - #end - #if($r.isNotEmpty($media.language)) - <tr><th>$r.translate("language")</th> - <td>$r.escapeHtml($media.language)</td></tr> - #end - - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.edition)) - <tr><th>$r.translate("mf.edition")</th> - <td>$r.escapeHtml($metadata.edition)</td></tr> - #end - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.editor)) - <tr><th>$r.translate("mf.editor")</th> - <td>$r.escapeHtml($metadata.editor)</td></tr> - #end - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.volume)) - <tr><th>$r.translate("volume")</th> - <td>$r.escapeHtml($metadata.volume)</td></tr> - #end - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.series)) - <tr><th>$r.translate("series")</th> - <td>$r.escapeHtml($metadata.series)</td></tr> - #end - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.publicationTitle)) - <tr><th>$r.translate("publication.title")</th> - <td>$r.escapeHtml($metadata.publicationTitle)</td></tr> - #end - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.issue)) - <tr><th>$r.translate("issue")</th> - <td>$r.escapeHtml($metadata.issue)</td></tr> - #end - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.pages)) - <tr><th>$r.translate("pages")</th> - <td>$r.escapeHtml($metadata.pages)</td></tr> - #end - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.institution)) - <tr><th>$r.translate("institution")</th> - <td>$r.escapeHtml($metadata.institution)</td></tr> - #end - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.isbn)) - <tr><th>$r.translate("mf.isbn")</th> - <td>$r.escapeHtml($metadata.isbn)</td></tr> - #end - - #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.lastVisit)) - <tr><th>$r.translate("mf.lastVisitDate")</th> - <td>$r.formatDate($metadata.lastVisit)</td></tr> - #end - - #if($r.available("categories")) - <tr><th>$r.translate("categories")</th> - <td>$r.render("categories")</td></tr> - #end - - #if($r.isNotEmpty($binderLinks)) - <tr><th>$r.translate("used.in")</th> - <td>#foreach($bLink in $binderLinks) - #if($foreach.count > 1), #end - $r.render($bLink) - #end</td></tr> - #end - </tbody></table> - </div> + <div class="panel panel-default o_artefact">$r.render("meta")</div> </div> </div> diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/media_details_metadata.html b/src/main/java/org/olat/modules/portfolio/ui/_content/media_details_metadata.html new file mode 100644 index 0000000000000000000000000000000000000000..0e730b185c79257896014ff09ba9de7fc809b082 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/media_details_metadata.html @@ -0,0 +1,103 @@ +<table class="table table-condensed table-striped"><tbody> + #if($r.isNotEmpty($mediaType)) + <tr><th>$r.translate("table.header.type")</th> + <td>#if($r.isNotEmpty($mediaIconCssClass))<i class="o_icon $mediaIconCssClass"> </i> #end $r.escapeHtml($mediaType)</td></tr> + #end + #if($r.isNotEmpty($author)) + <tr><th>$r.translate("author")</th> + <td>$r.escapeHtml($author)</td></tr> + #end + #if($r.isNotEmpty($collectionDate)) + <tr><th>$r.translate("artefact.collect.date")</th> + <td>$r.escapeHtml($collectionDate)</td></tr> + #end + #if($r.available("goto.original")) + <tr><th></th><td>$r.render("goto.original")</td> + #end + #if($r.isNotEmpty($media.creators)) + <tr><th>$r.translate("creators")</th> + <td>$r.escapeHtml($media.creators)</td></tr> + #end + #if($r.isNotEmpty($media.place)) + <tr><th>$r.translate("place")</th> + <td>$r.escapeHtml($media.place)</td></tr> + #end + #if($r.isNotEmpty($media.publisher)) + <tr><th>$r.translate("publisher")</th> + <td>$r.escapeHtml($media.publisher)</td></tr> + #end + #if($r.isNotEmpty($media.url)) + <tr><th>$r.translate("url")</th> + <td>$r.escapeHtml($media.url)</td></tr> + #end + #if($r.isNotEmpty($media.source)) + <tr><th>$r.translate("source")</th> + <td>$r.escapeHtml($media.source)</td></tr> + #end + #if($r.isNotEmpty($media.language)) + <tr><th>$r.translate("language")</th> + <td>$r.escapeHtml($media.language)</td></tr> + #end + + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.edition)) + <tr><th>$r.translate("mf.edition")</th> + <td>$r.escapeHtml($metadata.edition)</td></tr> + #end + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.editor)) + <tr><th>$r.translate("mf.editor")</th> + <td>$r.escapeHtml($metadata.editor)</td></tr> + #end + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.volume)) + <tr><th>$r.translate("volume")</th> + <td>$r.escapeHtml($metadata.volume)</td></tr> + #end + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.series)) + <tr><th>$r.translate("series")</th> + <td>$r.escapeHtml($metadata.series)</td></tr> + #end + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.publicationTitle)) + <tr><th>$r.translate("publication.title")</th> + <td>$r.escapeHtml($metadata.publicationTitle)</td></tr> + #end + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.issue)) + <tr><th>$r.translate("issue")</th> + <td>$r.escapeHtml($metadata.issue)</td></tr> + #end + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.pages)) + <tr><th>$r.translate("pages")</th> + <td>$r.escapeHtml($metadata.pages)</td></tr> + #end + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.institution)) + <tr><th>$r.translate("institution")</th> + <td>$r.escapeHtml($metadata.institution)</td></tr> + #end + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.isbn)) + <tr><th>$r.translate("mf.isbn")</th> + <td>$r.escapeHtml($metadata.isbn)</td></tr> + #end + + #if($r.isNotNull($metadata) && $r.isNotEmpty($metadata.lastVisit)) + <tr><th>$r.translate("mf.lastVisitDate")</th> + <td>$r.formatDate($metadata.lastVisit)</td></tr> + #end + + #if($r.available("categories")) + <tr><th>$r.translate("categories")</th> + <td>$r.render("categories")</td></tr> + #end + #if($r.isNotEmpty($categoriesList)) + <tr><th>$r.translate("categories")</th> + <td><i class="o_icon o_icon_tags" title="$r.translateInAttribute("categories")"> </i> + #foreach($category in $categoriesList) + <span class="tag label label-info">$category</span> + #end</td></tr> + #end + + #if($r.isNotEmpty($binderLinks)) + <tr><th>$r.translate("used.in")</th> + <td>#foreach($bLink in $binderLinks) + #if($foreach.count > 1), #end + $r.render($bLink) + #end</td></tr> + #end +</tbody></table> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/multi_evaluation_one_page.html b/src/main/java/org/olat/modules/portfolio/ui/_content/multi_evaluation_one_page.html new file mode 100644 index 0000000000000000000000000000000000000000..e058e30c63a48a302a7a1ced851559018b28ac52 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/multi_evaluation_one_page.html @@ -0,0 +1,6 @@ +#foreach($panel in $panels) +<div class="clearfix"> + <h3>$r.escapeHtml($panel.evaluator.fullName)</h3> + $r.render($panel.componentName) +</div> +#end \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/page_content_print.html b/src/main/java/org/olat/modules/portfolio/ui/_content/page_content_print.html new file mode 100644 index 0000000000000000000000000000000000000000..885bd7d778db8499650d2efb4993eebb1db3953f --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/page_content_print.html @@ -0,0 +1,7 @@ +<div class="o_print_break_after"> +$r.render("meta") +<div class="o_pf_content clearfix"><article>$r.render("page")</article></div> +#if($r.available("comments")) +<div class="o_pf_comments clearfix">$r.render("comments")</div> +#end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html b/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html index 8fcb16f9e30beaa2ba1dd398e8215ddd27f332f3..784034f13df75e92f22564641e1eeba7ca4f65b4 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html @@ -12,16 +12,20 @@ $r.translate("meta.last.modified", $r.formatDateAndTime($lastModified)) </span> - #if($r.isNotEmpty($pageCategories)) + #if($r.isNotEmpty($pageCategories) || $r.available("pageCategoriesCtr")) <span class="o_portfolio_categories text-muted o_small"> + #if ($r.available("pageCategoriesCtr")) + $r.render("pageCategoriesCtr") + #else <i class="o_icon o_icon_tags" title="$r.translateInAttribute("categories")"> </i> #foreach($category in $pageCategories) <span class="tag label label-info"> $category </span> #end - </span> #end + </span> + #end </div> #if($r.available("poster") || $r.isNotEmpty($pageSummary)) @@ -90,7 +94,7 @@ #end </ul> #end - <div class="pull-right"><a href="#page_assignment_${assignment.key}" data-toggle="collapse" data-target="#page_assignment_${assignment.key}" onclick="jQuery('#o_toggler_${assignment.key}').toggleClass('o_in'); return false;">$r.translate("assignment.hide")</a></div> + <div class="pull-right"><a href="#page_assignment_${assignment.key}" class="o_closer" data-toggle="collapse" data-target="#page_assignment_${assignment.key}" onclick="jQuery('#o_toggler_${assignment.key}').toggleClass('o_in'); return false;">$r.translate("assignment.hide")</a></div> </div> </div> </div> diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/portfolio_element_row.html b/src/main/java/org/olat/modules/portfolio/ui/_content/portfolio_element_row.html index 74c604bada41082fd29c7c5f07ab565daa0bbad5..7f1aac82e4d63ec11b3bf8570408ea6345b5f07f 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_content/portfolio_element_row.html +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/portfolio_element_row.html @@ -12,7 +12,7 @@ </div> #end #if(${row.isSection()}) -<div class="o_portfolio_section"> +<div class="o_portfolio_section #if(${row.isSectionEnded()}) o_section_ended #end"> <h3>$r.escapeHtml($row.sectionLongTitle) <small><i class="o_icon $row.sectionCssClassStatus" title="$r.translate("section.status"): $r.translate("$row.getSectionStatusI18nKey()")"> </i></small></h3> <div class="o_section_lead #if(${row.isSectionWithAssignmentToInstantiate()}) o_assignment_2_instantiate #else o_block_large_bottom #end"> <div class="o_portfolio_section_meta o_small"> @@ -29,7 +29,9 @@ </div> <div class="o_portfolio_status_block"> <span><strong>$r.translate("section.status"): </strong> $r.translate(${row.getSectionStatusI18nKey()})</span> - + #if(${row.isSectionEnded()}) + <p class="o_section_ended">$r.translate("section.ended.explain")</p> + #end #if($r.isNotNull($row.closeSectionLink)) $r.render($row.closeSectionLink) #end @@ -75,7 +77,7 @@ #end #if(${row.isPendingAssignment()}) #if($r.isNotNull($row.instantiateAssignmentLink)) - <div class="o_assignment_2_instantiate #if(${row.isLastAssignmentToInstantiate()}) last #end">$r.render($row.instantiateAssignmentLink) + <div class="o_assignment_2_instantiate #if(${row.isSectionEnded()}) o_section_ended #end #if(${row.isLastAssignmentToInstantiate()}) last #end">$r.render($row.instantiateAssignmentLink) <div id="o_assignment_summary_${row.instantiateAssignmentLink.formDispatchId}" style="display:none;"></div> <script type="text/javascript">/* <![CDATA[ */jQuery(function() { jQuery('#${row.instantiateAssignmentLink.formDispatchId}').tooltip({ @@ -161,12 +163,14 @@ </div> </div> </div> + #if($r.enabled($row.openFormItem)) <div class="o_portfolio_page_links o_noprint"> $r.render($row.openFormItem) #if($r.isNotNull($row.commentFormLink)) <span class="btn btn-sm o_portfolio_comment">$r.render($row.commentFormLink)</span> #end </div> + #end </div> #end #if($row.newEntry && $r.isNotNull($row.newEntryLink)) diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/section_assessment.html b/src/main/java/org/olat/modules/portfolio/ui/_content/section_assessment.html index 74f51e91dc51370fb06e45f55ab72149ea35d617..5d663c6d5023e03250d44472f33ab5bc9e5cb99b 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_content/section_assessment.html +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/section_assessment.html @@ -2,6 +2,9 @@ $r.contextHelpWithWrapper("Portfolio assignment: Grading") </div> $r.render("section-list") +#if($r.isNotEmpty($scoreError)) +<div class="o_error">$scoreError</div> +#end <div class="o_button_group"> $r.render("buttons") </div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties index d5f3cbaf26929db94e1b5c162367f00ee64378a4..ac61c2fc6d15e021ac50892cf0300f65db03f284 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties @@ -1,4 +1,4 @@ -#Thu Dec 15 14:32:23 CET 2016 +#Fri Aug 18 10:31:44 CEST 2017 access=Zugang access.binder=Die untenstehenden Personen haben Zugangsberechtigungen zu diesem Portfolio\: access.rights=Zugangsrecht hinzuf\u00FCgen @@ -73,6 +73,7 @@ binder.status=Status binder.title=Portfolio Mappe {0} binders=Mappe categories=Kategorien +categories.add=Kategorien hinzuf\u00FCgen categories.hint=Geben Sie den gew\u00FCnschten Text ein und dr\u00FCcken Sie die Eingabetaste, um eine Kategorie ihrer Wahl zu erstellen. changes.since=\u00C4nderungen seit citation=Zitat @@ -152,6 +153,14 @@ error.invalid.type=Dieser Dateityp ist nicht unters\u00FCtzt. error.invitation.mail.used=Diese E-Mailadresse wird bereits von einem OpenOLAT-Benutzer verwendet. error.mail.invalid=Bitte geben Sie eine g\u00FCltige E-Mailadresse an. error.mimetype=$org.olat.core.commons.modules.bc\:WrongMimeType +error.score=Punkte m\u00FCssen zwischen {0} und {1} sein. Oder die maximale Punktzahl, welche im Kurs definiert worden ist, wurde bereits mit anderen Sektionen erreicht. Mehr Informationen finden Sie im Bewertungswerkzeug des Kurses "{2}". +export.binder=Mappe exportieren +export.binder.cp=Mappe als CP exportieren +export.binder.onepage=Mappe in eine Seite +export.binder.pdf=Mappe als PDF exportieren +export.page=Seite exportieren +export.page.onepage=In eine Seite +export.page.pdf=Seite als PDF exportieren fileupload=Titelbild filter.show.all=Alle anzeigen firstName=Vorname @@ -160,6 +169,7 @@ goto.media.center=Mediathek \u00F6ffnen goto.my.binders=Zu meinen Mappen goto.my.pages=Zeige meine Eintr\u00E4ge goto.my.shared.items=Zu meinen freigegebenen Mappen +goto.original=Original anzeigen goto.shared.with.me=Zeige an mich freigegebene Mappen image.align=Richtung image.align.background=Als Hintergrundbild @@ -169,9 +179,9 @@ image.align.right=Kleines Bild, rechts von Zusammenfassung image.align.right.large=Grosses Bild, rechts von Zusammenfassung import.artefactV1=Artefakte importieren institution=Institution -invitation.link=Link invitation.extern.mail.body=Sie wurden von {2} {3} eingeladen, eine Sammelmappe in OLAT zu betrachten. Sie finden diese unter folgender Adresse\: {0} invitation.extern.mail.subject=Einladung zu einer freigegebenen Sammelmappe +invitation.link=Link invitation.mail.body=Sie wurden von {1} eingeladen, eine Sammelmappe in OLAT zu betrachten. Sie finden diese unter folgender Adresse\: {0} invitation.mail.failure=Fehler beim Versenden der E-Mail. Die eingeladenen Personen konnten nicht per E-Mail benachrichtigt werden. Versuchen Sie es sp\u00E4ter noch einmal oder kontaktieren Sie den Support. invitation.mail.subject=Einladung zu einer freigegebenen Sammelmappe @@ -303,6 +313,7 @@ save.done=$org.olat.modules.assessment.ui\:save.done section.delete=Bereich l\u00F6schen section.down=Unten section.edit=Bereich bearbeiten +section.ended.explain=Das Enddatum dieses Bereichs wurde erreicht. Es ist weiterhin m\u00F6glich, Aufgaben zu bearbeiten und freizugeben.. section.paging.all=Alle Eintr\u00E4ge zeigen section.paging.next=N\u00E4chster Bereich section.paging.one=Ein Bereich @@ -373,7 +384,7 @@ used.in=Verwendet in validate.email=E-Mailadresse validieren volume=Buchband warning.binder.synched=Die Portfolioaufgabe wurde mit ihrer Vorlage synchronisiert. -warning.evaluation.not.visible.title=Einsch\u00E4tzung nicht sichtbar warning.evaluation.not.visible.text=Zur zeit ist die Einsch\u00E4tzung nicht sichtbar. +warning.evaluation.not.visible.title=Einsch\u00E4tzung nicht sichtbar warning.portfolio.not.found=Die Portfolio Mappe konnte nicht gefunden werden. Sie wurde wahrscheinlich gel\u00F6scht. warning.template.in.use=Die Vorlage konnte nicht gel\u00F6scht werden weil einige Benutzer es nutzt. diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties index a62a9ff6821c267e4c9d4d355e84c6f619bd4bf0..87b5021df359baaa1cecb10579f1afc43cbbb048 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties @@ -1,4 +1,4 @@ -#Thu Dec 15 14:32:08 CET 2016 +#Fri Aug 18 10:31:35 CEST 2017 access=Access access.binder=The people below have access to the portfolio binder\: access.rights=Add access rights @@ -32,7 +32,7 @@ artefact.Forum=Forum post artefact.bc=File artefact.citation=Citation artefact.collect.date=Date -artefact.collect.link=Link to original +artefact.collect.link=Link artefact.descr=Description artefact.file=File artefact.image=Image @@ -73,6 +73,7 @@ binder.status=Status binder.title=Portfolio binder {0} binders=Binders categories=Categories +categories.add=Add categories categories.hint=Enter the category text and press "Enter" to create the desired category. changes.since=Changes citation=Citation @@ -152,6 +153,14 @@ error.invalid.type=This file type is not supported. error.invitation.mail.used=This e-mail address is already used by an OpenOLAT user. error.mail.invalid=Please provide a valid e-mail address. error.mimetype=$org.olat.core.commons.modules.bc\:WrongMimeType +error.score=Score is not between {0} and {1}. Or the maximum score defined in the course has already been reached with other sections. For more details see the assessment tool of the course "{2}". +export.binder=Export binder +export.binder.cp=Mappe als CP exportieren +export.binder.onepage=Mappe in eine Seite +export.binder.pdf=Mappe als PDF exportieren +export.page=Export page +export.page.onepage=In a single page +export.page.pdf=Export page as PDF fileupload=Teaser Image filter.show.all=Show all firstName=First name @@ -160,6 +169,7 @@ goto.media.center=open media center goto.my.binders=go to my binders goto.my.pages=show my entries goto.my.shared.items=go to my shares +goto.original=Go to original goto.shared.with.me=go to shared items image.align=Align image.align.background=Use as full-scale background image @@ -169,9 +179,9 @@ image.align.right=Small image, display on right side off summary image.align.right.large=Large image, place on right side off summary import.artefactV1=Import artefacts institution=Institution -invitation.link=Link -invitation.extern.mail.body={2} {3} has given you access right to the portfolio in OpenOLAT.\nTo open the corresponding binder, please go to: {0} +invitation.extern.mail.body={2} {3} has given you access right to the portfolio in OpenOLAT.\nTo open the corresponding binder, please go to\: {0} invitation.extern.mail.subject=Invitation to a portfolio binder +invitation.link=Link invitation.mail.body=You have been invited by {1} to have a look at a binder in OpenOLAT. Please go to\: {0} invitation.mail.failure=Error while sending your e-mail. The persons invited could not be notified. Please try again later or contact your support team. invitation.mail.subject=Invitation to a binder already released @@ -303,6 +313,7 @@ save.done=$org.olat.modules.assessment.ui\:save.done section.delete=Delete section section.down=Down section.edit=Edit section +section.ended.explain=The end date of this section is reached. It is still possible to edit tasks and to give access to them. section.paging.all=Show all entries section.paging.next=Next section.paging.one=One section @@ -373,7 +384,7 @@ used.in=Used in validate.email=Validate e-mail volume=Volume warning.binder.synched=The binder is synchronized with its template. -warning.evaluation.not.visible.title=Evaluation not visible warning.evaluation.not.visible.text=The evaluation is for the moment not visible. +warning.evaluation.not.visible.title=Evaluation not visible warning.portfolio.not.found=The portfolio cannot be found, probably deleted in the mean time warning.template.in.use=The template cannot deleted because some users use it. diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_fr.properties index a12895ee9c5afb99208f7c2076f23532518dc7a3..84e96c683d90576d3b31a17a2f7e42a7d327e092 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Thu Mar 09 17:09:02 CET 2017 +#Fri Aug 18 10:33:43 CEST 2017 access=Acc\u00E8s access.binder=Les personnes suivantes ont acc\u00E8s au classeur\: access.rights=Ajouter un droit d'acc\u00E8s @@ -62,7 +62,7 @@ attachments.error.file.exists=Ce fichier existe d\u00E9j\u00E0 et ne peut plus \ attachments.upload.successful=Le fichier {0} a \u00E9t\u00E9 ajout\u00E9 avec succ\u00E8s. Si besoin, d'autres fichiers peuvent \u00EAtre ajout\u00E9s. author=Auteur begin.date=Date de d\u00E9but -binder.atleastone=S\u00E9lectionner s'il-vous-pla\u00EEt au moins un classeur. +binder.atleastone=S\u00E9lectionner s'il vous pla\u00EEt au moins un classeur. binder.by=par {0} binder.entry.name=Pour le cours binder.last.update=Derni\u00E8re mise-\u00E0-jour @@ -73,6 +73,7 @@ binder.status=Status binder.title=Portfolio {0} binders=Classeurs categories=Cat\u00E9gories +categories.add=Ajouter des cat\u00E9gories categories.hint=Entrer le texte de la cat\u00E9gorie et passer "Entrez" pour cr\u00E9er la cat\u00E9gorie d\u00E9sir\u00E9e. changes.since=Changement depuis citation=Citation @@ -152,6 +153,7 @@ error.invalid.type=Ce type de fichier n'est pas support\u00E9. error.invitation.mail.used=Cette adresse e-mail est d\u00E9j\u00E0 utilis\u00E9e par un utilisateur OLAT. error.mail.invalid=Indiquez une adresse e-mail valide, svp. error.mimetype=$org.olat.core.commons.modules.bc\:WrongMimeType +error.score=Le nombre total de points doit se situer entre {0} et {1}. Ou le nombre de points maximum a d\u00E9j\u00E0 \u00E9t\u00E9 atteint avec d'autres sections. Vous trouverez plus d'informations dans l'outil d'\u00E9valuation du cours "{2}". fileupload=Image du titre filter.show.all=Tout affichez firstName=Pr\u00E9nom @@ -160,6 +162,7 @@ goto.media.center=Ouvrir la m\u00E9diath\u00E8que goto.my.binders=allez \u00E0 mes classeurs goto.my.pages=affichez mes contributions goto.my.shared.items=allez \u00E0 mes classeurs partag\u00E9s +goto.original=Montrer l'original goto.shared.with.me=allez \u00E0 la liste des classeurs partag\u00E9s avec moi image.align=Alignement image.align.background=Utilisez l'image comme fond diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_pt_BR.properties index 5bdf67364fe34a2497a4991a5f4179f73685e9ef..0e2c75d282342dec91db172c51a7529b1b49d6a8 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Thu Mar 16 21:51:57 CET 2017 +#Tue Sep 05 22:44:46 CEST 2017 access=Acesso access.binder=As pessoas abaixo t\u00EAm acesso \u00E0 carteira do portf\u00F3lio access.rights=Adicionar direitos de acesso @@ -73,6 +73,7 @@ binder.status=Status binder.title=Pasta do portf\u00F3lio {0} binders=Pastas (liga\u00E7\u00F5es) categories=Categorias +categories.add=Adicionar categorias categories.hint=Insira a categoria do texto e pressione "Enter" para criar a categoria desejada. changes.since=Mudan\u00E7as citation=Cita\u00E7\u00E3o @@ -152,6 +153,7 @@ error.invalid.type=Esse tipo de arquivo n\u00E3o \u00E9 suportado. error.invitation.mail.used=Este endere\u00E7o de e-mail j\u00E1 \u00E9 utilizado por um usu\u00E1rio OpenOLAT. error.mail.invalid=Por favor, forne\u00E7a um endere\u00E7o de e-mail v\u00E1lido. error.mimetype=$org.olat.core.commons.modules.bc\:WrongMimeType +error.score=A pontua\u00E7\u00E3o n\u00E3o est\u00E1 entre {0} e {1}. Ou a pontua\u00E7\u00E3o m\u00E1xima definida no curso j\u00E1 foi alcan\u00E7ada com outras se\u00E7\u00F5es. Para mais detalhes, veja a ferramenta de avalia\u00E7\u00E3o do curso "{2}". fileupload=Imagem teaser filter.show.all=Mostrar tudo firstName=Primeiro nome @@ -160,6 +162,7 @@ goto.media.center=Abrir m\u00EDdia center goto.my.binders=Ir para minhas pastas goto.my.pages=Mostrar minhas entradas goto.my.shared.items=Ir para meus compartilhamentos +goto.original=Ir para original goto.shared.with.me=Ir para itens compartilhados image.align=Alinhar image.align.background=Usar como imagem de fundo em grande escala diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/PageController.java b/src/main/java/org/olat/modules/portfolio/ui/editor/PageController.java index 62752bc1d77685613bf596cac8391f457ee72f2a..104f877c24c7bb9e9bf605b7a7b13d7fc476f7bf 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/editor/PageController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/editor/PageController.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -44,12 +45,14 @@ public class PageController extends BasicController { private int counter; private final PageProvider provider; private final VelocityContainer mainVC; + private final PageElementRenderingHints renderingHints; private Map<String,PageElementHandler> handlerMap = new HashMap<>(); - public PageController(UserRequest ureq, WindowControl wControl, PageProvider provider) { + public PageController(UserRequest ureq, WindowControl wControl, PageProvider provider, PageElementRenderingHints renderingHints) { super(ureq, wControl); this.provider = provider; + this.renderingHints = renderingHints; for(PageElementHandler handler:provider.getAvailableHandlers()) { handlerMap.put(handler.getType(), handler); @@ -84,9 +87,9 @@ public class PageController extends BasicController { for(PageElement element:elements) { PageElementHandler handler = handlerMap.get(element.getType()); if(handler != null) { - PageRunElement runElement = handler.getContent(ureq, getWindowControl(), element); + PageRunElement runElement = handler.getContent(ureq, getWindowControl(), element, renderingHints); String cmpId = "cpt-" + (++counter); - newFragments.add(new PageFragment(cmpId, runElement)); + newFragments.add(new PageFragment(handler.getType(), cmpId, runElement)); mainVC.put(cmpId, runElement.getComponent()); } } @@ -95,15 +98,21 @@ public class PageController extends BasicController { } public static final class PageFragment { - + + private final String type; private final String componentName; private final PageRunElement runElement; - public PageFragment(String componentName, PageRunElement runElement) { + public PageFragment(String type, String componentName, PageRunElement runElement) { + this.type = type; this.componentName = componentName; this.runElement = runElement; } + public String getCssClass() { + return "o_ed_".concat(type); + } + public String getComponentName() { return componentName; } diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/PageElementHandler.java b/src/main/java/org/olat/modules/portfolio/ui/editor/PageElementHandler.java index 6595b64aa2e7a730324f567be861b6d5c387d808..96c7803ec820aa16c0d1c359011d5a0a57bd23c1 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/editor/PageElementHandler.java +++ b/src/main/java/org/olat/modules/portfolio/ui/editor/PageElementHandler.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -35,7 +36,7 @@ public interface PageElementHandler { public String getIconCssClass(); - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element); + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints options); public Controller getEditor(UserRequest ureq, WindowControl wControl, PageElement element); diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/PageElementRenderingHints.java b/src/main/java/org/olat/modules/portfolio/ui/editor/PageElementRenderingHints.java new file mode 100644 index 0000000000000000000000000000000000000000..fc1298d5f32c721fef560ec6cfa3e3af666fbd25 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/editor/PageElementRenderingHints.java @@ -0,0 +1,36 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio.ui.editor; + +/** + * + * Initial date: 24 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface PageElementRenderingHints { + + public boolean isToPdf(); + + public boolean isOnePage(); + + public boolean isExtendedMetadata(); + +} diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/_content/page_run.html b/src/main/java/org/olat/modules/portfolio/ui/editor/_content/page_run.html index f90281137cba9ee831c88ff527800b2f148d502e..d059e1383df821b89e7398b4a7efb672f0f6cec0 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/editor/_content/page_run.html +++ b/src/main/java/org/olat/modules/portfolio/ui/editor/_content/page_run.html @@ -1,3 +1,3 @@ #foreach($fragment in $fragments) - <div class="">$r.render($fragment.componentName)</div> + <div class="$fragment.cssClass">$r.render($fragment.componentName)</div> #end \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/handler/HTMLRawPageElementHandler.java b/src/main/java/org/olat/modules/portfolio/ui/editor/handler/HTMLRawPageElementHandler.java index 8b2e8ef30eaa5f3cfd3fed794fd9e9d9e0118cd0..1860c7ba73c19d29f2a1673dc1a6bb16339b9d4d 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/editor/handler/HTMLRawPageElementHandler.java +++ b/src/main/java/org/olat/modules/portfolio/ui/editor/handler/HTMLRawPageElementHandler.java @@ -22,7 +22,7 @@ package org.olat.modules.portfolio.ui.editor.handler; import java.util.Locale; import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.text.TextComponent; import org.olat.core.gui.components.text.TextFactory; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.translator.Translator; @@ -34,6 +34,7 @@ import org.olat.modules.portfolio.ui.editor.HTMLRawEditorController; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementEditorController; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; import org.olat.modules.portfolio.ui.editor.PageRunComponent; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.editor.SimpleAddPageElementHandler; @@ -59,13 +60,14 @@ public class HTMLRawPageElementHandler implements PageElementHandler, SimpleAddP } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints options) { String content = ""; if(element instanceof HTMLPart) { content = ((HTMLPart)element).getContent(); content = Formatter.formatLatexFormulas(content); } - Component cmp = TextFactory.createTextComponentFromString("htmlRawCmp" + CodeHelper.getRAMUniqueID(), content, null, false, null); + TextComponent cmp = TextFactory.createTextComponentFromString("htmlRawCmp" + CodeHelper.getRAMUniqueID(), content, null, false, null); + cmp.setElementCssClass("o_pf_html_raw"); return new PageRunComponent(cmp); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/handler/SpacerElementHandler.java b/src/main/java/org/olat/modules/portfolio/ui/editor/handler/SpacerElementHandler.java index d3babb0bd9fe8ec9763ea79a061865a46e4665f7..465da8baac12f57a090dc25c1326547cc77a8557 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/editor/handler/SpacerElementHandler.java +++ b/src/main/java/org/olat/modules/portfolio/ui/editor/handler/SpacerElementHandler.java @@ -30,6 +30,7 @@ import org.olat.modules.portfolio.model.SpacerPart; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementEditorController; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; import org.olat.modules.portfolio.ui.editor.PageRunComponent; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.editor.SimpleAddPageElementHandler; @@ -56,7 +57,7 @@ public class SpacerElementHandler implements PageElementHandler, SimpleAddPageEl } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints options) { if(element instanceof SpacerPart) { Component cmp = new SpacerElementComponent("spacer_" + idGenerator.incrementAndGet()); return new PageRunComponent(cmp); diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/handler/TitlePageElementHandler.java b/src/main/java/org/olat/modules/portfolio/ui/editor/handler/TitlePageElementHandler.java index 3dbdbb3d2dfdb1eca9816fb9180e9460aa6141bc..5278f86047eb6c8e5eb8dad62b349bdce29867ac 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/editor/handler/TitlePageElementHandler.java +++ b/src/main/java/org/olat/modules/portfolio/ui/editor/handler/TitlePageElementHandler.java @@ -23,7 +23,7 @@ import java.util.Locale; import java.util.concurrent.atomic.AtomicInteger; import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.text.TextComponent; import org.olat.core.gui.components.text.TextFactory; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.translator.Translator; @@ -32,6 +32,7 @@ import org.olat.modules.portfolio.model.TitlePart; import org.olat.modules.portfolio.ui.editor.PageElement; import org.olat.modules.portfolio.ui.editor.PageElementEditorController; import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageElementRenderingHints; import org.olat.modules.portfolio.ui.editor.PageRunComponent; import org.olat.modules.portfolio.ui.editor.PageRunElement; import org.olat.modules.portfolio.ui.editor.SimpleAddPageElementHandler; @@ -58,12 +59,12 @@ public class TitlePageElementHandler implements PageElementHandler, SimpleAddPag } @Override - public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element) { + public PageRunElement getContent(UserRequest ureq, WindowControl wControl, PageElement element, PageElementRenderingHints options) { String content = ""; if(element instanceof TitlePart) { content = ((TitlePart)element).getContent(); } - Component cmp = TextFactory.createTextComponentFromString("title_" + idGenerator.incrementAndGet(), content, null, false, null); + TextComponent cmp = TextFactory.createTextComponentFromString("title_" + idGenerator.incrementAndGet(), content, null, false, null); return new PageRunComponent(cmp); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/export/BinderPhantomWorker.java b/src/main/java/org/olat/modules/portfolio/ui/export/BinderPhantomWorker.java new file mode 100644 index 0000000000000000000000000000000000000000..6e4a2755407731f432ba5d960ec97196a696a17b --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/export/BinderPhantomWorker.java @@ -0,0 +1,169 @@ +/** + + + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio.ui.export; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; + +/** + * + * Initial date: 16.11.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class BinderPhantomWorker { + + private static final OLog log = Tracing.createLoggerFor(BinderPhantomWorker.class); + + public BinderPhantomWorker() { + // + } + + public File fill(File indexHtml, File destinationDir, String filename) { + try { + File outputFile = new File(destinationDir, filename); + //deploy script + File rasterizePath = new File(destinationDir, "rasterize.js"); + try(InputStream inRasteriez = BinderPhantomWorker.class.getResourceAsStream("rasterize.js")) { + Files.copy(inRasteriez, rasterizePath.toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch(Exception e) { + log.error("Can not read rasterize.js library for PhantomJS PDF generation", e); + } + + List<String> cmds = new ArrayList<String>(); + cmds.add("phantomjs"); + cmds.add(rasterizePath.getAbsolutePath()); + cmds.add(indexHtml.getAbsolutePath()); + cmds.add(outputFile.getAbsolutePath()); + + CountDownLatch doneSignal = new CountDownLatch(1); + ProcessWorker worker = new ProcessWorker(cmds, doneSignal); + worker.start(); + + try { + doneSignal.await(30000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + log.error("", e); + } + + worker.destroyProcess(); + return outputFile; + } catch (Exception e) { + log.error("", e); + return null; + } + } + + private static class ProcessWorker extends Thread { + + private volatile Process process; + + private int exitValue = -1; + private final List<String> cmd; + private final CountDownLatch doneSignal; + + public ProcessWorker(List<String> cmd, CountDownLatch doneSignal) { + this.cmd = cmd; + this.doneSignal = doneSignal; + } + + public void destroyProcess() { + if (process != null) { + process.destroy(); + process = null; + } + } + + @Override + public void run() { + try { + if(log.isDebug()) { + log.debug(cmd.toString()); + } + + ProcessBuilder builder = new ProcessBuilder(cmd); + process = builder.start(); + executeProcess(process); + doneSignal.countDown(); + } catch (IOException e) { + log.error ("Could not spawn convert sub process", e); + destroyProcess(); + } + } + + private final void executeProcess(Process proc) { + StringBuilder errors = new StringBuilder(); + StringBuilder output = new StringBuilder(); + String line; + + InputStream stderr = proc.getErrorStream(); + InputStreamReader iserr = new InputStreamReader(stderr); + BufferedReader berr = new BufferedReader(iserr); + line = null; + try { + while ((line = berr.readLine()) != null) { + errors.append(line); + } + } catch (IOException e) { + // + } + + InputStream stdout = proc.getInputStream(); + InputStreamReader isr = new InputStreamReader(stdout); + BufferedReader br = new BufferedReader(isr); + line = null; + try { + while ((line = br.readLine()) != null) { + output.append(line); + } + } catch (IOException e) { + // + } + + if(log.isDebug()) { + log.debug("Error: " + errors.toString()); + log.debug("Output: " + output.toString()); + } + + try { + exitValue = proc.waitFor(); + if (exitValue != 0) { + log.warn("Problem with PhantomJS? " + exitValue); + } + } catch (InterruptedException e) { + log.warn("Takes too long"); + } + } + } +} diff --git a/src/main/java/org/olat/modules/portfolio/ui/export/ExportBinderAsCPResource.java b/src/main/java/org/olat/modules/portfolio/ui/export/ExportBinderAsCPResource.java new file mode 100644 index 0000000000000000000000000000000000000000..e5db6128a8a7b4535f500e7c5008019f911ff5b2 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/export/ExportBinderAsCPResource.java @@ -0,0 +1,598 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio.ui.export; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; + +import org.cyberneko.html.parsers.SAXParser; +import org.olat.core.CoreSpringFactory; +import org.olat.core.commons.services.commentAndRating.CommentAndRatingSecurityCallback; +import org.olat.core.commons.services.commentAndRating.ui.UserCommentsController; +import org.olat.core.dispatcher.DispatcherModule; +import org.olat.core.dispatcher.mapper.Mapper; +import org.olat.core.dispatcher.mapper.MapperService; +import org.olat.core.gui.GlobalSettings; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.winmgr.AJAXFlags; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.gui.render.RenderResult; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.render.velocity.VelocityRenderDecorator; +import org.olat.core.gui.translator.Translator; +import org.olat.core.gui.util.SyntheticUserRequest; +import org.olat.core.gui.util.WindowControlMocker; +import org.olat.core.helpers.Settings; +import org.olat.core.id.OLATResourceable; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.FileUtils; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.core.util.WebappHelper; +import org.olat.core.util.ZipUtil; +import org.olat.core.util.io.ShieldOutputStream; +import org.olat.core.util.resource.OresHelper; +import org.olat.imscp.xml.manifest.ItemType; +import org.olat.imscp.xml.manifest.ManifestMetadataType; +import org.olat.imscp.xml.manifest.ManifestType; +import org.olat.imscp.xml.manifest.OrganizationType; +import org.olat.imscp.xml.manifest.OrganizationsType; +import org.olat.imscp.xml.manifest.ResourceType; +import org.olat.imscp.xml.manifest.ResourcesType; +import org.olat.modules.cp.CPOfflineReadableManager; +import org.olat.modules.portfolio.AssessmentSection; +import org.olat.modules.portfolio.Binder; +import org.olat.modules.portfolio.BinderRef; +import org.olat.modules.portfolio.BinderSecurityCallback; +import org.olat.modules.portfolio.BinderSecurityCallbackFactory; +import org.olat.modules.portfolio.MediaHandler; +import org.olat.modules.portfolio.Page; +import org.olat.modules.portfolio.PortfolioService; +import org.olat.modules.portfolio.Section; +import org.olat.modules.portfolio.handler.EvaluationFormHandler; +import org.olat.modules.portfolio.model.ExtendedMediaRenderingHints; +import org.olat.modules.portfolio.ui.AbstractPageListController; +import org.olat.modules.portfolio.ui.PageMetadataController; +import org.olat.modules.portfolio.ui.editor.PageController; +import org.olat.modules.portfolio.ui.editor.PageElement; +import org.olat.modules.portfolio.ui.editor.PageElementHandler; +import org.olat.modules.portfolio.ui.editor.PageProvider; +import org.olat.modules.portfolio.ui.editor.handler.HTMLRawPageElementHandler; +import org.olat.modules.portfolio.ui.editor.handler.SpacerElementHandler; +import org.olat.modules.portfolio.ui.editor.handler.TitlePageElementHandler; +import org.olat.modules.portfolio.ui.model.PortfolioElementRow; +import org.olat.modules.portfolio.ui.model.ReadOnlyCommentsSecurityCallback; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * + * Initial date: 17 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ExportBinderAsCPResource implements MediaResource { + + private static final OLog log = Tracing.createLoggerFor(ExportBinderAsCPResource.class); + + private static final String SCHEMA_LOCATIONS = "http://www.imsglobal.org/xsd/imscp_v1p1 http://www.imsglobal.org/xsd/imscp_v1p2.xsd"; + private static final org.olat.imscp.xml.manifest.ObjectFactory cpObjectFactory = new org.olat.imscp.xml.manifest.ObjectFactory(); + private static JAXBContext context; + static { + try { + context = JAXBContext.newInstance("org.olat.imscp.xml.manifest"); + } catch (JAXBException e) { + log.error("", e); + } + } + + private final UserRequest ureq; + private final BinderRef binderRef; + private final Translator translator; + private final MapperService mapperService; + + private final PortfolioService portfolioService; + + public ExportBinderAsCPResource(BinderRef binderRef, UserRequest ureq, Locale locale) { + this.ureq = new SyntheticUserRequest(ureq.getIdentity(), locale, ureq.getUserSession()); + this.binderRef = binderRef; + this.translator = Util.createPackageTranslator(AbstractPageListController.class, locale); + portfolioService = CoreSpringFactory.getImpl(PortfolioService.class); + mapperService = CoreSpringFactory.getImpl(MapperService.class); + } + + @Override + public boolean acceptRanges() { + return false; + } + + @Override + public String getContentType() { + return "application/zip"; + } + + @Override + public Long getSize() { + return null; + } + + @Override + public Long getLastModified() { + return null; + } + + @Override + public InputStream getInputStream() { + return null; + } + + @Override + public void release() { + // + } + + @Override + public void prepare(HttpServletResponse hres) { + try { + hres.setCharacterEncoding("UTF-8"); + } catch (Exception e) { + log.error("", e); + } + + try(ZipOutputStream zout = new ZipOutputStream(hres.getOutputStream())) { + Binder binder = portfolioService.getBinderByKey(binderRef.getKey()); + String label = binder.getTitle(); + String secureLabel = StringHelper.transformDisplayNameToFileSystemName(label); + + String file = secureLabel + ".zip"; + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(file)); + hres.setHeader("Content-Description", StringHelper.urlEncodeUTF8(label)); + + //load pages + List<Section> sections = portfolioService.getSections(binder); + List<Page> pages = portfolioService.getPages(binder, null); + + //manifest + ManifestType manifest = createImsManifest(binder, sections, pages); + zout.putNextEntry(new ZipEntry("imsmanifest.xml")); + write(manifest, new ShieldOutputStream(zout)); + zout.closeEntry(); + + //write pages + for(Section section:sections) { + exportSection(section, zout); + } + //write pages + for(Page page:pages) { + exportPage(page, zout); + } + + //theme and javascripts + exportCSSAndJs(zout); + + // make it readable offline + ByteArrayOutputStream manifestOut = new ByteArrayOutputStream(); + write(manifest, manifestOut); + String manifestXml = new String(manifestOut.toByteArray()); + String indexSrc = sectionFilename(sections.get(0)); + CPOfflineReadableManager.getInstance().makeCPOfflineReadable(manifestXml, indexSrc, zout); + } catch (Exception e) { + log.error("", e); + } + } + + private ManifestType createImsManifest(Binder binder, List<Section> sections, List<Page> pages) { + ManifestType manifest = cpObjectFactory.createManifestType(); + manifest.setIdentifier(UUID.randomUUID().toString()); + //schema + ManifestMetadataType metadataType = cpObjectFactory.createManifestMetadataType(); + manifest.setMetadata(metadataType); + //organizations + OrganizationsType organizations = cpObjectFactory.createOrganizationsType(); + manifest.setOrganizations(organizations); + OrganizationType organization = cpObjectFactory.createOrganizationType(); + organization.setIdentifier("binder_" + binder.getKey()); + organization.setTitle(binder.getTitle()); + organization.setStructure("hierarchical"); + organizations.getOrganization().add(organization); + organizations.setDefault(organization); + + ResourcesType resources = cpObjectFactory.createResourcesType(); + manifest.setResources(resources); + + Map<Section, ItemType> sectionToItemMap = new HashMap<>(); + for(Section section:sections) { + ItemType sectionItem = cpObjectFactory.createItemType(); + String itemIdentifier = "section_" + section.getKey().toString(); + String resourceIdentifier = "res_" + itemIdentifier; + sectionItem.setTitle(section.getTitle()); + sectionItem.setIdentifier(itemIdentifier); + sectionItem.setIdentifierref(resourceIdentifier); + sectionItem.setIsvisible(Boolean.TRUE); + organization.getItem().add(sectionItem); + sectionToItemMap.put(section, sectionItem); + + ResourceType resource = cpObjectFactory.createResourceType(); + resource.setIdentifier(resourceIdentifier); + resource.setType("webcontent"); + resource.setHref(sectionFilename(section)); + resources.getResource().add(resource); + } + + for(Page page:pages) { + ItemType sectionItem = sectionToItemMap.get(page.getSection()); + if(sectionItem == null) { + continue; + } + + ItemType pageItem = cpObjectFactory.createItemType(); + pageItem.setTitle(page.getTitle()); + String itemIdentifier = "page_" + page.getKey().toString(); + String resourceIdentifier = "res_" + itemIdentifier; + pageItem.setIdentifier(itemIdentifier); + pageItem.setIdentifierref(resourceIdentifier); + pageItem.setIsvisible(Boolean.TRUE); + sectionItem.getItem().add(pageItem); + + ResourceType resource = cpObjectFactory.createResourceType(); + resource.setIdentifier(resourceIdentifier); + resource.setType("webcontent"); + resource.setHref(pageFilename(page)); + resources.getResource().add(resource); + } + return manifest; + } + + private String pageFilename(Page page) { + String title = page.getTitle(); + String filename = StringHelper.transformDisplayNameToFileSystemName(title).toLowerCase(); + return filename + "_p" + page.getKey() + ".html"; + } + + private String sectionFilename(Section section) { + String title = section.getTitle(); + String filename = StringHelper.transformDisplayNameToFileSystemName(title).toLowerCase(); + return filename + "_s" + section.getKey() + ".html"; + } + + private final void write(ManifestType manifest, OutputStream out) { + try { + Marshaller marshaller = context.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, SCHEMA_LOCATIONS); + marshaller.marshal(cpObjectFactory.createManifest(manifest), out); + } catch (JAXBException e) { + log.error("", e); + } + } + + private void exportSection(Section section, ZipOutputStream zout) throws IOException { + String pagePath = Util.getPackageVelocityRoot(AbstractPageListController.class) + "/portfolio_element_row.html"; + VelocityContainer rowVC = new VelocityContainer("html", pagePath, translator, null); + + AssessmentSection assessmentSection = null; + PortfolioElementRow row = new PortfolioElementRow(section, assessmentSection, false, false); + rowVC.contextPut("row", row); + rowVC.contextPut("rowIndex", 0); + + String html = createResultHTML(null, rowVC, null, "o_section_export"); + convertToZipEntry(zout, sectionFilename(section), html); + } + + private void exportPage(Page page, ZipOutputStream zout) throws IOException { + WindowControl mockwControl = new WindowControlMocker(); + BinderSecurityCallback secCallback = BinderSecurityCallbackFactory.getReadOnlyCallback(); + PageMetadataController metadatCtrl = new PageMetadataController(ureq, mockwControl, secCallback, page); + + PageController pageCtrl = new PageController(ureq, mockwControl, new PortfolioPageProvider(page), ExtendedMediaRenderingHints.toPrint()); + pageCtrl.loadElements(ureq); + + CommentAndRatingSecurityCallback commentSecCallback = new ReadOnlyCommentsSecurityCallback(); + OLATResourceable ores = OresHelper.createOLATResourceableInstance(Page.class, page.getKey()); + UserCommentsController commentsCtrl = new UserCommentsController(ureq, mockwControl, ores, null, commentSecCallback); + Component metadata = metadatCtrl.getInitialComponent(); + Component component = pageCtrl.getInitialComponent(); + Component comments = commentsCtrl.getNumOfComments() > 0 ? commentsCtrl.getInitialComponent() : null; + String html = createResultHTML(metadata, component, comments, "o_page_export"); + html = exportMedia(html, zout); + convertToZipEntry(zout, pageFilename(page), html); + + pageCtrl.dispose(); + metadatCtrl.dispose(); + } + + private String createResultHTML(Component metadata, Component content, Component comments, String bodyCssClass) { + String pagePath = Util.getPackageVelocityRoot(this.getClass()) + "/export.html"; + VelocityContainer mainVC = new VelocityContainer("html", pagePath, translator, null); + mainVC.contextPut("bodyCssClass", bodyCssClass); + if(metadata != null) { + mainVC.put("metadata", metadata); + } + if(content != null) { + mainVC.put("content", content); + } + if(comments != null) { + mainVC.put("comments", comments); + } + return renderVelocityContainer(mainVC) ; + } + + private String renderVelocityContainer(VelocityContainer mainVC) { + StringOutput sb = new StringOutput(32000); + URLBuilder ubu = new URLBuilder("auth", "1", "0"); + Renderer renderer = Renderer.getInstance(mainVC, translator, ubu, new RenderResult(), new EmptyGlobalSettings()); + VelocityRenderDecorator vrdec = new VelocityRenderDecorator(renderer, mainVC, sb); + mainVC.contextPut("r", vrdec); + renderer.render(sb, mainVC, null); + return sb.toString(); + } + + private void convertToZipEntry(ZipOutputStream zout, String link, String content) throws IOException { + zout.putNextEntry(new ZipEntry(link)); + try (InputStream in = new ByteArrayInputStream(content.getBytes())) { + FileUtils.copy(in, zout); + } catch (Exception e) { + log.error("Error during copy of resource export", e); + } finally { + zout.closeEntry(); + } + } + + private void exportCSSAndJs(ZipOutputStream zout) { + //Copy resource files or file trees to export file tree + File sasstheme = new File(WebappHelper.getContextRealPath("/static/themes/light")); + ZipUtil.addDirectoryToZip(sasstheme.toPath(), "css/offline/light", zout); + File fontawesome = new File(WebappHelper.getContextRealPath("/static/font-awesome")); + ZipUtil.addDirectoryToZip(fontawesome.toPath(), "css/font-awesome", zout); + File jQueryJs = new File(WebappHelper.getContextRealPath("/static/js/jquery/")); + ZipUtil.addDirectoryToZip(jQueryJs.toPath(), "js/jquery", zout); + File d3Js = new File(WebappHelper.getContextRealPath("/static/js/d3/")); + ZipUtil.addDirectoryToZip(d3Js.toPath(), "js/d3", zout); + } + + public String exportMedia(String html, ZipOutputStream zout) { + try { + SAXParser parser = new SAXParser(); + ExportMedia contentHandler = new ExportMedia(zout); + parser.setContentHandler(contentHandler); + parser.parse(new InputSource(new StringReader(html))); + Map<String,String> replaces = contentHandler.getReplaces(); + for(Map.Entry<String,String> replacement:replaces.entrySet()) { + html = html.replace(replacement.getKey(), replacement.getValue()); + } + } catch (SAXException | IOException e) { + log.error("", e); + } catch (Exception e) { + log.error("", e); + } + return html; + } + + private class ExportMedia extends DefaultHandler { + + private ZipOutputStream zout; + private StringBuilder script; + private Map<String,String> replaces = new HashMap<>(); + + public ExportMedia(ZipOutputStream zout) { + this.zout = zout; + } + + public Map<String,String> getReplaces() { + return replaces; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if("img".equalsIgnoreCase(localName)) { + String src = attributes.getValue("src"); + String cleanedSrc = processMedia(src); + if(cleanedSrc != null) { + replaces.put(src, cleanedSrc); + } + } else if("a".equalsIgnoreCase(localName)) { + String href = attributes.getValue("href"); + String cleanedHref = processMedia(href); + if(cleanedHref != null) { + replaces.put(href, cleanedHref); + } + } else if("script".equalsIgnoreCase(localName)) { + script = new StringBuilder(); + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if(script != null && start >= 0 && length > 0) { + script.append(ch, start, length); + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if("script".equalsIgnoreCase(localName) && script != null) { + processVideoScript(script); + script = null; + } + } + + private void processVideoScript(StringBuilder content) { + String player = "BPlayer.insertPlayer('"; + int playerIndex = content.indexOf(player); + if(playerIndex > 0) { + int mapperIndex = script.indexOf(DispatcherModule.PATH_MAPPED, playerIndex); + int endVariable = script.indexOf("','", mapperIndex); + String src = script.substring(mapperIndex, endVariable); + String cleanedSrc = processMedia(src); + if(cleanedSrc != null) { + String url = script.substring(playerIndex + player.length(), endVariable); + replaces.put(url, cleanedSrc); + } + } + } + + private String processMedia(String src) { + String serverContext = Settings.getServerContextPath(); + if(serverContext != null && serverContext.length() > 1 && src.startsWith(serverContext)) { + src = src.substring(serverContext.length(), src.length()); + } + + if(!src.startsWith(DispatcherModule.PATH_MAPPED)) { + return null; + } + + String subInfo = src.substring(DispatcherModule.PATH_MAPPED.length()); + int slashPos = subInfo.indexOf('/'); + + String id; + if (slashPos == -1) { + id = subInfo; + } else { + id = subInfo.substring(0, slashPos); + } + + try { + Mapper mapper = mapperService.getMapperById(ureq.getUserSession(), id); + if(mapper == null) return null; + + String mod = slashPos > 0 ? subInfo.substring(slashPos) : ""; + MediaResource resource = mapper.handle(mod, null); + if(resource == null) return null; + + String cleanedSrc = src.substring(1); + int index = cleanedSrc.lastIndexOf('?'); + if(index > 0) { + cleanedSrc = cleanedSrc.substring(0, index); + } + + try (InputStream in = resource.getInputStream()) { + zout.putNextEntry(new ZipEntry(cleanedSrc)); + FileUtils.copy(in, zout); + } catch (Exception e) { + log.error("Error during copy of resource export", e); + } finally { + zout.closeEntry(); + } + return cleanedSrc; + } catch (IOException e) { + log.error("Error during copy of resource export", e); + return null; + } + } + } + + private static class EmptyGlobalSettings implements GlobalSettings { + @Override + public int getFontSize() { + return 100; + } + + @Override + public AJAXFlags getAjaxFlags() { + return new EmptyAJAXFlags(); + } + + @Override + public boolean isIdDivsForced() { + return false; + } + }; + + private static class EmptyAJAXFlags extends AJAXFlags { + + public EmptyAJAXFlags() { + super(null); + } + + @Override + public boolean isIframePostEnabled() { + return false; + } + } + + private class PortfolioPageProvider implements PageProvider { + + private final List<PageElementHandler> handlers = new ArrayList<>(); + + private Page page; + + public PortfolioPageProvider(Page page) { + this.page = page; + + //handler for title + TitlePageElementHandler titleRawHandler = new TitlePageElementHandler(); + handlers.add(titleRawHandler); + //handler for HTML code + HTMLRawPageElementHandler htlmRawHandler = new HTMLRawPageElementHandler(); + handlers.add(htlmRawHandler); + //handler for HTML code + SpacerElementHandler hrHandler = new SpacerElementHandler(); + handlers.add(hrHandler); + //handler for form + EvaluationFormHandler formHandler = new EvaluationFormHandler(); + handlers.add(formHandler); + + + List<MediaHandler> mediaHandlers = portfolioService.getMediaHandlers(); + for(MediaHandler mediaHandler:mediaHandlers) { + if(mediaHandler instanceof PageElementHandler) { + handlers.add((PageElementHandler)mediaHandler); + } + } + } + + @Override + public List<? extends PageElement> getElements() { + return portfolioService.getPageParts(page); + } + + @Override + public List<PageElementHandler> getAvailableHandlers() { + return handlers; + } + } +} diff --git a/src/main/java/org/olat/modules/portfolio/ui/export/ExportBinderAsPDFResource.java b/src/main/java/org/olat/modules/portfolio/ui/export/ExportBinderAsPDFResource.java new file mode 100644 index 0000000000000000000000000000000000000000..d08565f0efc9dce36b19d9ecc2fb3e1c718e2828 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/export/ExportBinderAsPDFResource.java @@ -0,0 +1,396 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.portfolio.ui.export; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.IOUtils; +import org.cyberneko.html.parsers.SAXParser; +import org.olat.core.CoreSpringFactory; +import org.olat.core.dispatcher.DispatcherModule; +import org.olat.core.dispatcher.mapper.Mapper; +import org.olat.core.dispatcher.mapper.MapperService; +import org.olat.core.gui.GlobalSettings; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.winmgr.AJAXFlags; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.gui.render.RenderResult; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.render.velocity.VelocityRenderDecorator; +import org.olat.core.gui.translator.Translator; +import org.olat.core.gui.util.SyntheticUserRequest; +import org.olat.core.gui.util.WindowControlMocker; +import org.olat.core.helpers.Settings; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.FileUtils; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.core.util.WebappHelper; +import org.olat.modules.portfolio.Binder; +import org.olat.modules.portfolio.BinderRef; +import org.olat.modules.portfolio.Page; +import org.olat.modules.portfolio.PortfolioService; +import org.olat.modules.portfolio.model.ExtendedMediaRenderingHints; +import org.olat.modules.portfolio.ui.BinderOnePageController; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * It makes a flat html file, copy all medias around it + * and render it as PDF via phantomjs. + * + * + * + * Initial date: 24 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ExportBinderAsPDFResource implements MediaResource { + + private static final OLog log = Tracing.createLoggerFor(ExportBinderAsPDFResource.class); + + private File htmlDir; + private File pdfFile; + + private final UserRequest ureq; + private final Page selectedPage; + private final BinderRef binderRef; + private final Translator translator; + private final MapperService mapperService; + + private final PortfolioService portfolioService; + + public ExportBinderAsPDFResource(BinderRef binderRef, UserRequest ureq, Locale locale) { + this.ureq = new SyntheticUserRequest(ureq.getIdentity(), locale, ureq.getUserSession()); + this.binderRef = binderRef; + selectedPage = null; + translator = Util.createPackageTranslator(ExportBinderAsPDFResource.class, locale); + portfolioService = CoreSpringFactory.getImpl(PortfolioService.class); + mapperService = CoreSpringFactory.getImpl(MapperService.class); + } + + public ExportBinderAsPDFResource(Page selectedPage, UserRequest ureq, Locale locale) { + this.ureq = new SyntheticUserRequest(ureq.getIdentity(), locale, ureq.getUserSession()); + binderRef = null; + this.selectedPage = selectedPage; + translator = Util.createPackageTranslator(ExportBinderAsPDFResource.class, locale); + portfolioService = CoreSpringFactory.getImpl(PortfolioService.class); + mapperService = CoreSpringFactory.getImpl(MapperService.class); + } + + @Override + public boolean acceptRanges() { + return false; + } + + @Override + public String getContentType() { + return "application/pdf"; + } + + @Override + public Long getSize() { + return null; + } + + @Override + public Long getLastModified() { + return null; + } + + @Override + public InputStream getInputStream() { + try { + return new FileInputStream(pdfFile); + } catch (FileNotFoundException e) { + log.error("", e); + return null; + } + } + + @Override + public void release() { + if(htmlDir != null && htmlDir.exists()) { + FileUtils.deleteDirsAndFiles(htmlDir, true, true); + } + } + + @Override + public void prepare(HttpServletResponse hres) { + try { + hres.setCharacterEncoding("UTF-8"); + } catch (Exception e) { + log.error("", e); + } + + htmlDir = prepareHtml(); + pdfFile = renderPdf(htmlDir); + + String label; + if(selectedPage != null) { + label = selectedPage.getTitle(); + } else { + Binder binder = portfolioService.getBinderByKey(binderRef.getKey()); + label = binder.getTitle(); + } + + String secureLabel = StringHelper.transformDisplayNameToFileSystemName(label); + + String file = secureLabel + ".pdf"; + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(file)); + hres.setHeader("Content-Description", StringHelper.urlEncodeUTF8(label)); + } + + private File prepareHtml() { + File outputDir = new File(WebappHelper.getTmpDir(), "pf" + UUID.randomUUID()); + outputDir.mkdirs(); + + WindowControl mockwControl = new WindowControlMocker(); + BinderOnePageController printCtrl; + if(selectedPage != null) { + printCtrl = new BinderOnePageController(ureq, mockwControl, selectedPage, ExtendedMediaRenderingHints.toPdf(), false); + } else { + printCtrl = new BinderOnePageController(ureq, mockwControl, binderRef, ExtendedMediaRenderingHints.toPdf(), false); + } + Component content = printCtrl.getInitialComponent(); + String html = createResultHTML(content); + + File indexHtml = new File(outputDir, "index.html"); + exportCSSAndJs(outputDir); + html = exportMedia(html, outputDir); + try(OutputStream out= new FileOutputStream(indexHtml)) { + IOUtils.write(html, out, "UTF-8"); + } catch(IOException e) { + log.error("", e); + } + printCtrl.dispose(); + return outputDir; + } + + private File renderPdf(File outputDir) { + File indexHtml = new File(outputDir, "index.html"); + BinderPhantomWorker worker = new BinderPhantomWorker(); + File filePdf = worker.fill(indexHtml, outputDir, "portfolio.pdf"); + return filePdf; + } + + private String createResultHTML(Component content) { + String pagePath = Util.getPackageVelocityRoot(this.getClass()) + "/export.html"; + VelocityContainer mainVC = new VelocityContainer("html", pagePath, translator, null); + mainVC.put("cmp", content); + mainVC.contextPut("bodyCssClass", "o_portfolio_export"); + + StringOutput sb = new StringOutput(32000); + URLBuilder ubu = new URLBuilder("auth", "1", "0"); + Renderer renderer = Renderer.getInstance(mainVC, translator, ubu, new RenderResult(), new EmptyGlobalSettings()); + VelocityRenderDecorator vrdec = new VelocityRenderDecorator(renderer, mainVC, sb); + mainVC.contextPut("r", vrdec); + renderer.render(sb, mainVC, null); + return sb.toString(); + } + + private void exportCSSAndJs(File outputDir) { + //Copy resource files or file trees to export file tree + File sasstheme = new File(WebappHelper.getContextRealPath("/static/themes/light")); + File lightDir = new File(new File(outputDir.getAbsolutePath(), "css"), "offline"); + FileUtils.copyDirToDir(sasstheme, lightDir, "Copy theme"); + + File fontawesome = new File(WebappHelper.getContextRealPath("/static/font-awesome")); + File fontDir = new File(outputDir, "css"); + FileUtils.copyDirToDir(fontawesome, fontDir, "Copy font awesome"); + + File js = new File(WebappHelper.getContextRealPath("/static/js/jquery/")); + File jsDir = new File(outputDir, "js"); + FileUtils.copyDirToDir(js, jsDir, "Copy javascripts"); + } + + public String exportMedia(String html, File outputDir) { + try { + SAXParser parser = new SAXParser(); + ExportMedia contentHandler = new ExportMedia(outputDir); + parser.setContentHandler(contentHandler); + parser.parse(new InputSource(new StringReader(html))); + Map<String,String> replaces = contentHandler.getReplaces(); + for(Map.Entry<String,String> replacement:replaces.entrySet()) { + html = html.replace(replacement.getKey(), replacement.getValue()); + } + } catch (SAXException | IOException e) { + log.error("", e); + } catch (Exception e) { + log.error("", e); + } + return html; + } + + private class ExportMedia extends DefaultHandler { + + private File outputDir; + private StringBuilder script; + private Map<String,String> replaces = new HashMap<>(); + + public ExportMedia(File outputDir) { + this.outputDir = outputDir; + } + + public Map<String,String> getReplaces() { + return replaces; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if("img".equalsIgnoreCase(localName)) { + String src = attributes.getValue("src"); + String cleanedSrc = processMedia(src); + if(cleanedSrc != null) { + replaces.put(src, cleanedSrc); + } + } else if("a".equalsIgnoreCase(localName)) { + String href = attributes.getValue("href"); + String cleanedHref = processMedia(href); + if(cleanedHref != null) { + replaces.put(href, cleanedHref); + } + } else if("script".equalsIgnoreCase(localName)) { + script = new StringBuilder(); + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if(script != null && start >= 0 && length > 0) { + script.append(ch, start, length); + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if("script".equalsIgnoreCase(localName) && script != null) { + processVideoScript(script); + script = null; + } + } + + private void processVideoScript(StringBuilder content) { + String player = "BPlayer.insertPlayer('"; + int playerIndex = content.indexOf(player); + if(playerIndex > 0) { + int mapperIndex = script.indexOf(DispatcherModule.PATH_MAPPED, playerIndex); + int endVariable = script.indexOf("','", mapperIndex); + String src = script.substring(mapperIndex, endVariable); + String cleanedSrc = processMedia(src); + if(cleanedSrc != null) { + String url = script.substring(playerIndex + player.length(), endVariable); + replaces.put(url, cleanedSrc); + } + } + } + + private String processMedia(String src) { + String serverContext = Settings.getServerContextPath(); + if(serverContext != null && serverContext.length() > 1 && src.startsWith(serverContext)) { + src = src.substring(serverContext.length(), src.length()); + } + + if(!src.startsWith(DispatcherModule.PATH_MAPPED)) return null; + + String subInfo = src.substring(DispatcherModule.PATH_MAPPED.length()); + int slashPos = subInfo.indexOf('/'); + + String id; + if (slashPos == -1) { + id = subInfo; + } else { + id = subInfo.substring(0, slashPos); + } + + Mapper mapper = mapperService.getMapperById(ureq.getUserSession(), id); + if(mapper == null) return null; + + String mod = slashPos > 0 ? subInfo.substring(slashPos) : ""; + MediaResource resource = mapper.handle(mod, null); + if(resource == null) return null; + + String cleanedSrc = src.substring(1); + int index = cleanedSrc.lastIndexOf('?'); + if(index > 0) { + cleanedSrc = cleanedSrc.substring(0, index); + } + + File entry = new File(outputDir, cleanedSrc); + try (InputStream in = resource.getInputStream()) { + FileUtils.copyToFile(in, entry, "Copy media"); + } catch (IOException e) { + log.error("Error during copy of resource export", e); + } + return cleanedSrc; + } + } + + private static class EmptyGlobalSettings implements GlobalSettings { + @Override + public int getFontSize() { + return 100; + } + + @Override + public AJAXFlags getAjaxFlags() { + return new EmptyAJAXFlags(); + } + + @Override + public boolean isIdDivsForced() { + return false; + } + }; + + private static class EmptyAJAXFlags extends AJAXFlags { + + public EmptyAJAXFlags() { + super(null); + } + + @Override + public boolean isIframePostEnabled() { + return false; + } + } +} diff --git a/src/main/java/org/olat/modules/portfolio/ui/export/_content/export.html b/src/main/java/org/olat/modules/portfolio/ui/export/_content/export.html new file mode 100644 index 0000000000000000000000000000000000000000..de11efd51539a173f103ab2e65f6948f0d66a5b8 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/export/_content/export.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>$rootTitle</title> + <link rel='stylesheet' href='css/offline/light/theme.css' /> + <link rel='stylesheet' href='js/jquery/sliderpips/jquery-ui-slider-pips.css' /> + <link rel='stylesheet' href='js/jquery/ui/jquery-ui-1.11.4.custom.min.css' /> + + <script type="text/javascript" src='js/jquery/jquery-2.1.3.min.js'></script> + <script type="text/javascript" src='js/d3/d3.min.js'></script> + <script type="text/javascript" src='js/jquery/ui/jquery-ui-1.11.4.custom.qti.min.js'></script> + <script type="text/javascript" src='js/jquery/sliderpips/jquery-ui-slider-pips.js'></script> + <script type="text/javascript" src='js/jquery/openolat/jquery.statistics.radarchart.js'></script> + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <script type="text/javascript"> +/* <![CDATA[ */ +function setFlexiFormDirtyByListener(e){ + // +} +function o_mathjax() { + jQuery.ajax("${r.mathJaxCdnFullUrl()}MathJax.js?config=TeX-AMS-MML_HTMLorMML", { + cache: true, + dataType: "script", + success: function() { + MathJax.Hub.Config({ + extensions: ["jsMath2jax.js"], + messageStyle: 'none', + showProcessingMessages: false, + showMathMenu: false, + menuSettings: { }, + jsMath2jax: { + preview: "none" + }, + tex2jax: { + ignoreClass: "math" + }, + "HTML-CSS": { + EqnChunk: 5, EqnChunkFactor: 1, EqnChunkDelay: 100 + }, + "fast-preview": { + disabled: true + } + }); + } + }); +} +var BFormatter = { + // format on load + formatLatexFormulas : function(domId) {} +}; +var BPlayer = { + insertPlayer: function (address,domId,width,height,start,duration,provider,streamer,autostart,repeat,controlbar,poster) { + var content = '<video src="' + address + '" controls width="' + width + '" height="' + height + '" />'; + jQuery('#' + domId).append(content); + } +} +jQuery(function() { + if ((window.unsafeWindow == null ? window : unsafeWindow).MathJax == null) { + var count = jQuery('div.math,span.math,math,div.mathEntryInteraction').length; + if (count > 0) { + o_mathjax(); + } + } +}); +/* ]]> */ + </script> +</head> +<body class="o_page_margins o_offline_export $bodyCssClass"> + <div id="o_main"> + #if($r.available("cmp")) + $r.render("cmp") + #end + #if($r.available("metadata")) + <div class="o_pf_metadat">$r.render("metadata")</div> + #end + #if($r.available("content")) + <div class="o_pf_content">$r.render("content")</div> + #end + #if($r.available("comments")) + <div class="o_pf_comments">$r.render("comments")</div> + #end + </div> +</body> +</html> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/CitationMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/CitationMediaController.java index 3868e654299399bcba184dc565034f67fe0725a5..9b1edc429f7c9bb137333db41d92943d1959f090 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/CitationMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/CitationMediaController.java @@ -29,7 +29,9 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.modules.portfolio.Citation; import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.manager.MetadataXStream; +import org.olat.modules.portfolio.ui.MediaMetadataController; import org.olat.modules.portfolio.ui.PortfolioHomeController; import org.olat.modules.portfolio.ui.component.CitationComponent; @@ -41,7 +43,7 @@ import org.olat.modules.portfolio.ui.component.CitationComponent; */ public class CitationMediaController extends BasicController { - public CitationMediaController(UserRequest ureq, WindowControl wControl, Media media) { + public CitationMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(PortfolioHomeController.class, getLocale(), getTranslator())); @@ -62,6 +64,13 @@ public class CitationMediaController extends BasicController { cmp.setDublinCoreMetadata(media); mainVC.put("cit", cmp); } + + + if(hints.isExtendedMetadata()) { + MediaMetadataController metaCtrl = new MediaMetadataController(ureq, wControl, media); + listenTo(metaCtrl); + mainVC.put("meta", metaCtrl.getInitialComponent()); + } } @Override diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/CollectCitationMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/CollectCitationMediaController.java index d5aae01dc6a1dcbab4aea8f14ce686eeaacf14e3..997fb721078fa58328f7f56f7e68001e51dee996 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/CollectCitationMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/CollectCitationMediaController.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -112,6 +113,10 @@ public class CollectCitationMediaController extends FormBasicController implemen businessPath = media.getBusinessPath(); mediaReference = media; + if(StringHelper.containsNonWhitespace(mediaReference.getMetadataXml())) { + citation = (CitationXml)MetadataXStream.get().fromXML(mediaReference.getMetadataXml()); + } + List<Category> categoryList = portfolioService.getCategories(media); for(Category category:categoryList) { categories.put(category.getName(), category.getName()); @@ -282,6 +287,12 @@ public class CollectCitationMediaController extends FormBasicController implemen @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; + + titleEl.clearError(); + if (titleEl.isEmpty()) { + titleEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } return allOk & super.validateFormLogic(ureq); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/CollectFileMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/CollectFileMediaController.java index 5bd3e9bf11268e7492d106151d8ce4fc9db684c9..04dd23bfbf698f6c7ddee9a0c745776ead0c4a90 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/CollectFileMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/CollectFileMediaController.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; @@ -180,9 +181,26 @@ public class CollectFileMediaController extends FormBasicController implements P fileEl.setErrorKey("form.legende.mandatory", null); allOk &= false; } + + titleEl.clearError(); + if (titleEl.isEmpty()) { + titleEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } return allOk & super.validateFormLogic(ureq); } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(fileEl == source) { + if (this.titleEl.isEmpty()) { + this.titleEl.setValue(fileEl.getUploadFileName()); + this.titleEl.getComponent().setDirty(true); + } + } + super.formInnerEvent(ureq, source, event); + } @Override protected void formOK(UserRequest ureq) { diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/CollectImageMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/CollectImageMediaController.java index b2332851b8f552fbbc6a20d6508828058e2b65ca..273e13aee54003b8ae74b1765138c5d817247638 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/CollectImageMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/CollectImageMediaController.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.Set; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; @@ -147,7 +148,6 @@ public class CollectImageMediaController extends FormBasicController implements fileEl.addActionListener(FormEvent.ONCHANGE); fileEl.setMaxUploadSizeKB(10000, null, null); fileEl.setPreview(ureq.getUserSession(), true); - fileEl.setDeleteEnabled(true); if(mediaReference != null) { fileEl.setEnabled(false); VFSItem item = fileHandler.getImage(mediaReference); @@ -190,9 +190,26 @@ public class CollectImageMediaController extends FormBasicController implements fileEl.setErrorKey("form.legende.mandatory", null); allOk &= false; } + + titleEl.clearError(); + if (titleEl.isEmpty()) { + titleEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } return allOk & super.validateFormLogic(ureq); } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(fileEl == source) { + if (this.titleEl.isEmpty()) { + this.titleEl.setValue(fileEl.getUploadFileName()); + this.titleEl.getComponent().setDirty(true); + } + } + super.formInnerEvent(ureq, source, event); + } @Override protected void formOK(UserRequest ureq) { diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/CollectTextMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/CollectTextMediaController.java index 549d4707b1fc5ed74829d2558492c2f83ad28745..d756f72d30038cd706640a8ed204e9ed30db847f 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/CollectTextMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/CollectTextMediaController.java @@ -155,6 +155,12 @@ public class CollectTextMediaController extends FormBasicController implements P @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; + + titleEl.clearError(); + if (titleEl.isEmpty()) { + titleEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } return allOk & super.validateFormLogic(ureq); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/CollectVideoMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/CollectVideoMediaController.java index 8f15b7facbd91bda36251189db7ad0d43fd54eab..c3470bd4670b6afab08825edb60bfff665c4d280 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/CollectVideoMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/CollectVideoMediaController.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; @@ -178,9 +179,26 @@ public class CollectVideoMediaController extends FormBasicController implements fileEl.setErrorKey("form.legende.mandatory", null); allOk &= false; } + + titleEl.clearError(); + if (titleEl.isEmpty()) { + titleEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } return allOk & super.validateFormLogic(ureq); } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(fileEl == source) { + if (this.titleEl.isEmpty()) { + this.titleEl.setValue(fileEl.getUploadFileName()); + this.titleEl.getComponent().setDirty(true); + } + } + super.formInnerEvent(ureq, source, event); + } @Override protected void formOK(UserRequest ureq) { diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/FileMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/FileMediaController.java index 9fd478c4663aa3566472e6f9ef319d5e368b5657..21aed6b9ab51f6db6c7e220ce668f0956d251603 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/FileMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/FileMediaController.java @@ -19,13 +19,16 @@ */ package org.olat.modules.portfolio.ui.media; +import javax.servlet.http.HttpServletRequest; + +import org.olat.core.dispatcher.mapper.Mapper; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.download.DownloadComponent; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.util.CSSHelper; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; @@ -33,8 +36,11 @@ import org.olat.core.util.Util; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.VFSMediaResource; import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.manager.PortfolioFileStorage; +import org.olat.modules.portfolio.ui.MediaMetadataController; import org.olat.modules.portfolio.ui.PortfolioHomeController; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; @@ -53,7 +59,7 @@ public class FileMediaController extends BasicController { @Autowired private UserManager userManager; - public FileMediaController(UserRequest ureq, WindowControl wControl, Media media) { + public FileMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(PortfolioHomeController.class, getLocale(), getTranslator())); @@ -70,8 +76,12 @@ public class FileMediaController extends BasicController { VFSContainer container = fileStorage.getMediaContainer(media); VFSItem item = container.resolve(media.getRootFilename()); if(item instanceof VFSLeaf) { - DownloadComponent downloadCmp = new DownloadComponent("download", (VFSLeaf)item); - mainVC.put("download", downloadCmp); + VFSLeaf leaf = (VFSLeaf)item; + String mapperUri = registerCacheableMapper(ureq, "File-Media-" + media.getKey() + "-" + leaf.getLastModified(), new FileMapper(leaf)); + mainVC.contextPut("mapperUri", mapperUri); + String iconCss = CSSHelper.createFiletypeIconCssClassFor(leaf.getName()); + mainVC.contextPut("fileIconCss", iconCss); + mainVC.contextPut("filename", leaf.getName()); mainVC.contextPut("size", Formatter.formatBytes(((VFSLeaf) item).getSize())); String cssClass = CSSHelper.createFiletypeIconCssClassFor(item.getName()); @@ -81,6 +91,12 @@ public class FileMediaController extends BasicController { mainVC.contextPut("cssClass", cssClass); } + if(hints.isExtendedMetadata()) { + MediaMetadataController metaCtrl = new MediaMetadataController(ureq, wControl, media); + listenTo(metaCtrl); + mainVC.put("meta", metaCtrl.getInitialComponent()); + } + mainVC.setDomReplacementWrapperRequired(false); putInitialPanel(mainVC); } @@ -94,4 +110,18 @@ public class FileMediaController extends BasicController { protected void doDispose() { // } + + private static class FileMapper implements Mapper { + + private final VFSLeaf file; + + public FileMapper(VFSLeaf file) { + this.file = file; + } + + @Override + public MediaResource handle(String relPath, HttpServletRequest request) { + return new VFSMediaResource(file); + } + } } diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/ImageMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/ImageMediaController.java index 4d735f17e16f947ceec9e5ed729f67d8220604c0..ebf17f5208c6ffa2da295c5a9108892eb1544082 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/ImageMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/ImageMediaController.java @@ -25,10 +25,13 @@ import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.image.ImageComponent; +import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.MediaRenderingHints; +import org.olat.modules.portfolio.ui.MediaMetadataController; /** * @@ -37,19 +40,27 @@ import org.olat.modules.portfolio.Media; * */ public class ImageMediaController extends BasicController { - - public ImageMediaController(UserRequest ureq, WindowControl wControl, Media media) { + + public ImageMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { super(ureq, wControl); - + + VelocityContainer mainVC = createVelocityContainer("media_image"); File mediaDir = new File(FolderConfig.getCanonicalRoot(), media.getStoragePath()); File mediaFile = new File(mediaDir, media.getRootFilename()); ImageComponent imageCmp = new ImageComponent(ureq.getUserSession(), "image"); imageCmp.setMedia(mediaFile); - - putInitialPanel(imageCmp); + imageCmp.setDivImageWrapper(false); + mainVC.put("image", imageCmp); + mainVC.contextPut("media", media); + mainVC.contextPut("extendedMetadata", hints.isExtendedMetadata()); + if(hints.isExtendedMetadata()) { + MediaMetadataController metaCtrl = new MediaMetadataController(ureq, wControl, media); + listenTo(metaCtrl); + mainVC.put("meta", metaCtrl.getInitialComponent()); + } + putInitialPanel(mainVC); } - @Override protected void event(UserRequest ureq, Component source, Event event) { // diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/StandardEditMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/StandardEditMediaController.java index df215148b59a893917a1c989312af598342e0a9a..7d0e4038050fade721454e39af01feb921a23c2e 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/StandardEditMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/StandardEditMediaController.java @@ -54,7 +54,6 @@ public class StandardEditMediaController extends FormBasicController { private TextBoxListElement categoriesEl; private Media mediaReference; - private final String businessPath; private Map<String,String> categories = new HashMap<>(); @Autowired @@ -63,7 +62,6 @@ public class StandardEditMediaController extends FormBasicController { public StandardEditMediaController(UserRequest ureq, WindowControl wControl, Media media) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(PortfolioHomeController.class, getLocale(), getTranslator())); - businessPath = media.getBusinessPath(); mediaReference = media; List<Category> categoryList = portfolioService.getCategories(media); diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/TextMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/TextMediaController.java index 54378e138a53816b0c4b1b90c24b9d0c3eb7e91c..c8b96c9e7afb92f7782d03e0a233f7ec25e88bbc 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/TextMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/TextMediaController.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -23,10 +24,18 @@ import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.text.TextComponent; import org.olat.core.gui.components.text.TextFactory; +import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.MediaRenderingHints; +import org.olat.modules.portfolio.ui.MediaMetadataController; +import org.olat.modules.portfolio.ui.PortfolioHomeController; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -36,11 +45,31 @@ import org.olat.modules.portfolio.Media; */ public class TextMediaController extends BasicController { - public TextMediaController(UserRequest ureq, WindowControl wControl, Media media) { + @Autowired + private UserManager userManager; + + public TextMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { super(ureq, wControl); + setTranslator(Util.createPackageTranslator(PortfolioHomeController.class, getLocale(), getTranslator())); + VelocityContainer mainVC = createVelocityContainer("media_text"); TextComponent cmp = TextFactory.createTextComponentFromString("text", media.getContent(), null, false, null); - putInitialPanel(cmp); + mainVC.put("text", cmp); + + String desc = media.getDescription(); + mainVC.contextPut("description", StringHelper.containsNonWhitespace(desc) ? desc : null); + String title = media.getTitle(); + mainVC.contextPut("title", StringHelper.containsNonWhitespace(title) ? title : null); + + mainVC.contextPut("creationdate", media.getCreationDate()); + mainVC.contextPut("author", userManager.getUserDisplayName(media.getAuthor())); + + if(hints.isExtendedMetadata()) { + MediaMetadataController metaCtrl = new MediaMetadataController(ureq, wControl, media); + listenTo(metaCtrl); + mainVC.put("meta", metaCtrl.getInitialComponent()); + } + putInitialPanel(mainVC); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/VideoMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/VideoMediaController.java index 5a93a54b264599ce6be7bc71a31703fbefd5996b..a11031dab8cd74389ad80784967c772efba0ebbe 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/VideoMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/VideoMediaController.java @@ -22,13 +22,17 @@ package org.olat.modules.portfolio.ui.media; import java.io.File; import org.olat.core.commons.modules.bc.FolderConfig; +import org.olat.core.commons.services.image.Size; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.image.ImageComponent; +import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.MediaRenderingHints; +import org.olat.modules.portfolio.ui.MediaMetadataController; /** * @@ -38,15 +42,31 @@ import org.olat.modules.portfolio.Media; */ public class VideoMediaController extends BasicController { - public VideoMediaController(UserRequest ureq, WindowControl wControl, Media media) { + public VideoMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { super(ureq, wControl); + VelocityContainer mainVC = createVelocityContainer("media_video"); + File mediaDir = new File(FolderConfig.getCanonicalRoot(), media.getStoragePath()); File mediaFile = new File(mediaDir, media.getRootFilename()); - ImageComponent imageCmp = new ImageComponent(ureq.getUserSession(), "image"); - imageCmp.setMedia(mediaFile); + ImageComponent videoCmp = new ImageComponent(ureq.getUserSession(), "image"); + videoCmp.setMedia(mediaFile); + mainVC.put("video", videoCmp); + mainVC.contextPut("pdf", hints.isToPdf()); + if(hints.isToPdf()) { + videoCmp.setMaxWithAndHeightToFitWithin(800, 600); + Size size = videoCmp.getScaledSize(); + if(size != null) { + mainVC.contextPut("scaledSize", size); + } + } - putInitialPanel(imageCmp); + if(hints.isExtendedMetadata()) { + MediaMetadataController metaCtrl = new MediaMetadataController(ureq, wControl, media); + listenTo(metaCtrl); + mainVC.put("meta", metaCtrl.getInitialComponent()); + } + putInitialPanel(mainVC); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_citation.html b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_citation.html index e91a317c63ff96239e3d004cba48573d9cd43b05..2e706fdcefa4d204da425f2a9ce845b3382276c6 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_citation.html +++ b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_citation.html @@ -6,10 +6,10 @@ </h5> #end <blockquote class="o_quote"> - $r.xssScan($citation) + <div class="">$r.xssScan($citation)</div> </blockquote> #if ($description) - <div class="o_desc o_block"> + <div class="o_desc o_block_small"> $r.xssScan($description) </div> #end @@ -18,4 +18,9 @@ $r.render("cit") </div> #end -</div> \ No newline at end of file + #if($r.available("meta")) + <div class="panel panel-default o_artefact_metadata o_block_large_bottom"> + $r.render("meta") + </div> + #end +</div> diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_file.html b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_file.html index 116013b519337f4f6374e98fea4061c961f9db1c..3555fdec3f64e6ee0ba98f75f92d6343b4679d57 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_file.html +++ b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_file.html @@ -1,12 +1,11 @@ <div class="o_file"> #if($title) <h5> - <i class="o_icon o_icon-fw $cssClass"> </i> $title <small>$r.translate("document.by",$author)</small> </h5> #end - <div class="o_meta small text-muted"> + <div class="o_meta small text-muted o_noprint"> $r.translate("document.creationdate", $r.formatDateAndTime($creationdate)) </div> @@ -16,9 +15,12 @@ </div> #end <div class="o_download"> - $r.render("download") - <span class="o_size"> - ($size) - </span> + <a id="o_c8000010939" href="$mapperUri/$filename" target="_blank"><i class="o_icon o_icon-fw $cssClass"></i> $filename</a> + <span class="o_size">($size)</span> </div> -</div> + #if($r.available("meta")) + <div class="panel panel-default o_artefact_metadata"> + $r.render("meta") + </div> + #end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_image.html b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_image.html new file mode 100644 index 0000000000000000000000000000000000000000..066fc4e15f6c96c9c345916b82837a2b4bcbd94e --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_image.html @@ -0,0 +1,17 @@ +<div class="o_image"> + <div class="o_figure_caption_bottom"> + <figure class="o_image"> + $r.render("image") + #if($r.isNotEmpty($media.description)) + <figcaption> + $media.description + </figcaption> + #end + </figure> + </div> + #if($r.available("meta") && $r.isTrue($extendedMetadata)) + <div class="panel panel-default o_artefact_metadata"> + $r.render("meta") + </div> + #end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_text.html b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_text.html new file mode 100644 index 0000000000000000000000000000000000000000..6f13bc2c7c80483b2c1499db65ed4f9d2b812929 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_text.html @@ -0,0 +1,14 @@ +<div class="o_text"> + #if($title) + <h5> + $title + <small>$r.translate("document.by",$author)</small> + </h5> + #end + $r.render("text") + #if($r.available("meta")) + <div class="panel panel-default o_artefact_metadata"> + $r.render("meta") + </div> + #end +</div> diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_video.html b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_video.html new file mode 100644 index 0000000000000000000000000000000000000000..8c45360f368f56dbd6d5becfcf33d23a14a5301c --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_video.html @@ -0,0 +1,15 @@ +<div class="o_video"> + #if($r.isTrue($pdf)) + <div class="o_pf_video_placeholder" #if($r.isNotNull($scaledSize)) style="width: ${scaledSize.width}px; height: ${scaledSize.height}px;" #end><i class="o_icon o_icon-5x o_filetype_mp4"> </i></div> + #else + <div class="o_pf_video_placeholder visible-print-block" #if($r.isNotNull($scaledSize)) style="width: ${scaledSize.width}px; height: ${scaledSize.height}px;" #end><i class="o_icon o_icon-5x o_filetype_mp4"> </i></div> + <div class="o_noprint"> + $r.render("video") + </div> + #end + #if($r.available("meta")) + <div class="panel panel-default o_artefact_metadata"> + $r.render("meta") + </div> + #end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/portfolio/ui/model/PortfolioElementRow.java b/src/main/java/org/olat/modules/portfolio/ui/model/PortfolioElementRow.java index ee246629ab0ce2aabb136d9598850da22aa20b03..ce3868c746ceca307319971ee5ae66b9c21a3382 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/model/PortfolioElementRow.java +++ b/src/main/java/org/olat/modules/portfolio/ui/model/PortfolioElementRow.java @@ -417,6 +417,10 @@ public class PortfolioElementRow { public void setInstantiateAssignmentLink(FormLink instantiateAssignmentLink) { this.instantiateAssignmentLink = instantiateAssignmentLink; } + + public boolean isSectionEnded() { + return section != null && section.getEndDate() != null && new Date().after(section.getEndDate()); + } public FormLink getCloseSectionLink() { return closeSectionLink; diff --git a/src/main/java/org/olat/modules/qpool/QPoolSPI.java b/src/main/java/org/olat/modules/qpool/QPoolSPI.java index 68fe49c6b671696c2efec651bb89f10b54025e79..8fad01a0f9ca102778894bfbe42fd774c752be29 100644 --- a/src/main/java/org/olat/modules/qpool/QPoolSPI.java +++ b/src/main/java/org/olat/modules/qpool/QPoolSPI.java @@ -30,7 +30,6 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.media.MediaResource; import org.olat.core.id.Identity; -import org.olat.core.util.vfs.VFSLeaf; /** * @@ -48,8 +47,6 @@ public interface QPoolSPI { public boolean isCompatible(String filename, File file); - public boolean isCompatible(String filename, VFSLeaf file); - /** * * @param question diff --git a/src/main/java/org/olat/modules/qpool/QPoolService.java b/src/main/java/org/olat/modules/qpool/QPoolService.java index a7eb26affc39f1253978549f15d6a4c4e0989afe..24707c2d169a6d02919cfd774bdc11fdfa55a879 100644 --- a/src/main/java/org/olat/modules/qpool/QPoolService.java +++ b/src/main/java/org/olat/modules/qpool/QPoolService.java @@ -70,7 +70,7 @@ public interface QPoolService { public QuestionItem updateItem(QuestionItem item); - public void deleteItems(List<QuestionItemShort> items); + public void deleteItems(List<? extends QuestionItemShort> items); public int countItems(SearchQuestionItemParams params); diff --git a/src/main/java/org/olat/modules/qpool/impl/FileQPoolServiceProvider.java b/src/main/java/org/olat/modules/qpool/impl/FileQPoolServiceProvider.java index e90811e16309b5c0a65c6c8f4740bf05f906e3bc..071c4a080a6f86a2a6e188e3476aa46256f17ddb 100644 --- a/src/main/java/org/olat/modules/qpool/impl/FileQPoolServiceProvider.java +++ b/src/main/java/org/olat/modules/qpool/impl/FileQPoolServiceProvider.java @@ -26,7 +26,6 @@ import java.util.List; import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; -import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.qpool.QItemFactory; import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItem; @@ -80,11 +79,6 @@ public class FileQPoolServiceProvider extends AbstractQPoolServiceProvider { && !filename.toLowerCase().endsWith(".zip"); } - @Override - public boolean isCompatible(String filename, VFSLeaf file) { - return isCompatible(filename, (File)null); - } - @Override public List<QItemFactory> getItemfactories() { return Collections.emptyList(); diff --git a/src/main/java/org/olat/modules/qpool/impl/TextQPoolServiceProvider.java b/src/main/java/org/olat/modules/qpool/impl/TextQPoolServiceProvider.java index 2164f036e22f2ab20b40564b784e0ae37ae0fe37..27d21081fc82aafdea43bf0f5b148248209510e6 100644 --- a/src/main/java/org/olat/modules/qpool/impl/TextQPoolServiceProvider.java +++ b/src/main/java/org/olat/modules/qpool/impl/TextQPoolServiceProvider.java @@ -26,7 +26,6 @@ import java.util.List; import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; -import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.qpool.QItemFactory; import org.olat.modules.qpool.QPoolService; import org.olat.modules.qpool.QuestionItem; @@ -77,11 +76,6 @@ public class TextQPoolServiceProvider extends AbstractQPoolServiceProvider { public boolean isCompatible(String filename, File file) { return filename.toLowerCase().endsWith(".txt"); } - - @Override - public boolean isCompatible(String filename, VFSLeaf file) { - return isCompatible(filename, (File)null); - } @Override public List<QItemFactory> getItemfactories() { diff --git a/src/main/java/org/olat/modules/qpool/manager/CollectionDAO.java b/src/main/java/org/olat/modules/qpool/manager/CollectionDAO.java index 7e1a300cf7949286c9f94d1c9f8da08ce907b91e..adea8da0a05d7b9100360f1486869b7980643d6b 100644 --- a/src/main/java/org/olat/modules/qpool/manager/CollectionDAO.java +++ b/src/main/java/org/olat/modules/qpool/manager/CollectionDAO.java @@ -160,7 +160,7 @@ public class CollectionDAO { public int removeItemFromCollection(List<QuestionItemShort> items, QuestionItemCollection collection) { if(items == null || items.isEmpty()) return 0;//noting to do - List<Long> keys = new ArrayList<Long>(); + List<Long> keys = new ArrayList<>(); for(QuestionItemShort item:items) { keys.add(item.getKey()); } @@ -174,10 +174,10 @@ public class CollectionDAO { .executeUpdate(); } - public int deleteItemFromCollections(List<QuestionItemShort> items) { + public int deleteItemFromCollections(List<? extends QuestionItemShort> items) { if(items == null || items.isEmpty()) return 0;//noting to do - List<Long> keys = new ArrayList<Long>(); + List<Long> keys = new ArrayList<>(); for(QuestionItemShort item:items) { keys.add(item.getKey()); } diff --git a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java index 4b6b890e4cfcb044f47e20fab70b5ca3ce53d68c..e373e31b992e7a409703c87a588cdefc57b55b50 100644 --- a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java +++ b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java @@ -73,10 +73,10 @@ public class PoolDAO { return pool; } - public int removeFromPools(List<QuestionItemShort> items) { + public int removeFromPools(List<? extends QuestionItemShort> items) { if(items == null || items.isEmpty()) return 0; - List<Long> keys = new ArrayList<Long>(); + List<Long> keys = new ArrayList<>(); for(QuestionItemShort item:items) { keys.add(item.getKey()); } 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 cffa62aed082255927eab4bcd97bd074530075aa..e94021a0bde370ae650c14c4e5909b748b08ec6d 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java @@ -36,8 +36,6 @@ import org.olat.basesecurity.SecurityGroupMembershipImpl; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.services.mark.impl.MarkImpl; import org.olat.core.id.Identity; -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.group.BusinessGroup; import org.olat.modules.qpool.QuestionItem; @@ -62,8 +60,6 @@ import org.springframework.stereotype.Service; @Service("questionDao") public class QuestionItemDAO { - private static final OLog log = Tracing.createLoggerFor(QuestionItemDAO.class); - @Autowired private DB dbInstance; @Autowired @@ -427,8 +423,8 @@ public class QuestionItemDAO { .getResultList(); } - public int removeFromShares(List<QuestionItemShort> items) { - List<Long> keys = new ArrayList<Long>(); + public int removeFromShares(List<? extends QuestionItemShort> items) { + List<Long> keys = new ArrayList<>(); for(QuestionItemShort item:items) { keys.add(item.getKey()); } @@ -441,7 +437,7 @@ public class QuestionItemDAO { } public int removeFromShare(List<QuestionItemShort> items, OLATResource resource) { - List<Long> keys = new ArrayList<Long>(); + List<Long> keys = new ArrayList<>(); for(QuestionItemShort item:items) { keys.add(item.getKey()); } 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 830a331088eaa393770c9248520104c16af271a6..58600b25e0a5b16d9114c652bc02ec1c95025fd6 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java @@ -87,6 +87,7 @@ public class QuestionItemDocumentFactory { oDocument.setParentContextType(searchResourceContext.getParentContextType()); oDocument.setParentContextName(searchResourceContext.getParentContextName()); + System.out.println(item.getTitle()); //author StringBuilder authorSb = new StringBuilder(); List<Identity> owners = qpoolService.getAuthors(item); diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java index 35e9fd48f0356c4c4ea2f96df86700d087d1841f..bae904c8fa6e7cb63205acd9be1f364128b9eea3 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolServiceImpl.java @@ -114,7 +114,7 @@ public class QuestionPoolServiceImpl implements QPoolService { @Override - public void deleteItems(List<QuestionItemShort> items) { + public void deleteItems(List<? extends QuestionItemShort> items) { if(items == null || items.isEmpty()) { return; //nothing to do } @@ -330,6 +330,7 @@ public class QuestionPoolServiceImpl implements QPoolService { public QuestionItem createAndPersistItem(Identity owner, String subject, String format, String language, TaxonomyLevel taxonLevel, String dir, String rootFilename, QItemType type) { QuestionItemImpl newItem = questionItemDao.createAndPersist(owner, subject, format, language, taxonLevel, dir, rootFilename, type); + dbInstance.commit(); lifeIndexer.indexDocument(QItemDocument.TYPE, newItem.getKey()); return newItem; } @@ -406,6 +407,7 @@ public class QuestionPoolServiceImpl implements QPoolService { poolDao.addItemToPool(item, pools, editable); keys.add(item.getKey()); } + dbInstance.commit(); lifeIndexer.indexDocument(QItemDocument.TYPE, keys); } diff --git a/src/main/java/org/olat/modules/qpool/restapi/QuestionItemVO.java b/src/main/java/org/olat/modules/qpool/restapi/QuestionItemVO.java new file mode 100644 index 0000000000000000000000000000000000000000..3827ead6026a7f976bf804f2f6af8031c89f9384 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/restapi/QuestionItemVO.java @@ -0,0 +1,85 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.restapi; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.olat.modules.qpool.QuestionItem; + +/** + * + * Initial date: 8 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "questionItemVO") +public class QuestionItemVO { + + private Long key; + private String identifier; + private String masterIdentifier; + private String title; + + public QuestionItemVO() { + // + } + + public QuestionItemVO(QuestionItem item) { + key = item.getKey(); + identifier = item.getIdentifier(); + masterIdentifier = item.getMasterIdentifier(); + title = item.getTitle(); + } + + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getMasterIdentifier() { + return masterIdentifier; + } + + public void setMasterIdentifier(String masterIdentifier) { + this.masterIdentifier = masterIdentifier; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} diff --git a/src/main/java/org/olat/modules/qpool/restapi/QuestionItemVOes.java b/src/main/java/org/olat/modules/qpool/restapi/QuestionItemVOes.java new file mode 100644 index 0000000000000000000000000000000000000000..6be10a576a7214e06f258b1430d1e60e87341964 --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/restapi/QuestionItemVOes.java @@ -0,0 +1,64 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.restapi; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + * Initial date: 8 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "questionItemVOes") +public class QuestionItemVOes { + + @XmlElementWrapper(name="questionItems") + @XmlElement(name="questionItem") + private QuestionItemVO[] questionItems; + @XmlAttribute(name="totalCount") + private int totalCount; + + public QuestionItemVOes() { + // + } + + public QuestionItemVO[] getQuestionItems() { + return questionItems; + } + + public void setQuestionItems(QuestionItemVO[] questionItems) { + this.questionItems = questionItems; + } + + public int getTotalCount() { + return totalCount; + } + + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } +} diff --git a/src/main/java/org/olat/modules/qpool/restapi/QuestionPoolWebService.java b/src/main/java/org/olat/modules/qpool/restapi/QuestionPoolWebService.java new file mode 100644 index 0000000000000000000000000000000000000000..60323d0286674345451f9f4a9d8792355f88e45f --- /dev/null +++ b/src/main/java/org/olat/modules/qpool/restapi/QuestionPoolWebService.java @@ -0,0 +1,298 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.qpool.restapi; + +import static org.olat.restapi.security.RestSecurityHelper.isQuestionPoolManager; + +import java.io.File; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.olat.basesecurity.BaseSecurity; +import org.olat.core.CoreSpringFactory; +import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.i18n.I18nManager; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItem; +import org.olat.modules.qpool.QuestionItemShort; +import org.olat.restapi.security.RestSecurityHelper; +import org.olat.restapi.support.MultipartReader; +import org.olat.user.restapi.UserVO; +import org.olat.user.restapi.UserVOFactory; + +/** + * + * Initial date: 8 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Path("qpool/items") +public class QuestionPoolWebService { + + private static final OLog log = Tracing.createLoggerFor(QuestionPoolWebService.class); + + @PUT + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + @Consumes({MediaType.MULTIPART_FORM_DATA}) + public Response importQuestionItemsPut(@Context HttpServletRequest request) { + return importQuestionItems(request); + } + + @POST + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + @Consumes({MediaType.MULTIPART_FORM_DATA}) + public Response importQuestionItemsPost(@Context HttpServletRequest request) { + return importQuestionItems(request); + } + + private Response importQuestionItems(HttpServletRequest request) { + if(!isQuestionPoolManager(request)) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + + MultipartReader partsReader = null; + try { + Identity identity = RestSecurityHelper.getUserRequest(request).getIdentity(); + partsReader = new MultipartReader(request); + File tmpFile = partsReader.getFile(); + long length = tmpFile.length(); + if(length > 0) { + String filename = partsReader.getValue("filename"); + String language = partsReader.getValue("language"); + QuestionItemVOes voes = importQuestionItem(identity, filename, tmpFile, language); + return Response.ok(voes).build(); + } + return Response.serverError().status(Status.NO_CONTENT).build(); + } catch (Exception e) { + log.error("Error while importing a file",e); + } finally { + MultipartReader.closeQuietly(partsReader); + } + return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build(); + } + + private QuestionItemVOes importQuestionItem(Identity owner, String filename, File tmpFile, String language) { + Locale locale = CoreSpringFactory.getImpl(I18nManager.class).getLocaleOrDefault(language); + + List<QuestionItem> items = CoreSpringFactory.getImpl(QPoolService.class) + .importItems(owner, locale, filename, tmpFile); + QuestionItemVOes voes = new QuestionItemVOes(); + QuestionItemVO[] voArray = new QuestionItemVO[items.size()]; + for(int i=items.size(); i-->0; ) { + voArray[i] = new QuestionItemVO(items.get(i)); + } + voes.setQuestionItems(voArray); + voes.setTotalCount(items.size()); + return voes; + } + + /** + * Delete a question item by id. + * + * @response.representation.200.doc Nothing + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The question item not found + * @param itemKey The question item identifier + * @param request The HTTP request + * @return Nothing + */ + @DELETE + @Path("{itemKey}") + public Response deleteQuestionItem(@PathParam("itemKey") Long itemKey, @Context HttpServletRequest request) { + if(!isQuestionPoolManager(request)) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + QPoolService poolService = CoreSpringFactory.getImpl(QPoolService.class); + QuestionItem item = poolService.loadItemById(itemKey); + if(item == null) { + return Response.serverError().status(Status.NOT_FOUND).build(); + } + List<QuestionItem> itemToDelete = Collections.singletonList(item); + poolService.deleteItems(itemToDelete); + + return Response.ok().build(); + } + + /** + * Get all authors of the question item. + * + * @response.representation.200.qname {http://www.example.com}userVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The array of authors + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The question item not found + * @param itemKey The question item identifier + * @param httpRequest The HTTP request + * @return It returns an array of <code>UserVO</code> + */ + @GET + @Path("{itemKey}/authors") + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response getAuthors(@PathParam("itemKey") Long itemKey, + @Context HttpServletRequest request) { + + if(!isQuestionPoolManager(request)) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + + QPoolService poolService = CoreSpringFactory.getImpl(QPoolService.class); + QuestionItem item = poolService.loadItemById(itemKey); + if(item == null) { + return Response.serverError().status(Status.NOT_FOUND).build(); + } + List<Identity> authorList = poolService.getAuthors(item); + + int count = 0; + UserVO[] authors = new UserVO[authorList.size()]; + for(Identity author:authorList) { + authors[count++] = UserVOFactory.get(author); + } + return Response.ok(authors).build(); + } + + /** + * Get this specific author of the quesiton item. + * + * @response.representation.200.qname {http://www.example.com}userVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The author + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The question item not found or the user is not an author of the course + * @param itemKey The question item identifier + * @param identityKey The user identifier + * @param httpRequest The HTTP request + * @return It returns an <code>UserVO</code> + */ + @GET + @Path("{itemKey}/authors/{identityKey}") + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response getAuthor(@PathParam("itemKey") Long itemKey, @PathParam("identityKey") Long identityKey, + @Context HttpServletRequest request) { + if(!isQuestionPoolManager(request)) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + + QPoolService poolService = CoreSpringFactory.getImpl(QPoolService.class); + QuestionItem item = poolService.loadItemById(itemKey); + if(item == null) { + return Response.serverError().status(Status.NOT_FOUND).build(); + } + List<Identity> authorList = poolService.getAuthors(item); + for(Identity author:authorList) { + if(author.getKey().equals(identityKey)) { + UserVO authorVo = UserVOFactory.get(author); + return Response.ok(authorVo).build(); + } + } + return Response.serverError().status(Status.NOT_FOUND).build(); + } + + /** + * Add an author to the question item. + * + * @response.representation.200.doc The user is an author of the question item + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The question item or the user not found + * @param itemKey The question item identifier + * @param identityKey The user identifier + * @param httpRequest The HTTP request + * @return It returns 200 if the user is added as author of the question item + */ + @PUT + @Path("{itemKey}/authors/{identityKey}") + public Response addAuthor(@PathParam("itemKey") Long itemKey, @PathParam("identityKey") Long identityKey, + @Context HttpServletRequest httpRequest) { + if(!isQuestionPoolManager(httpRequest)) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + + QPoolService poolService = CoreSpringFactory.getImpl(QPoolService.class); + QuestionItem item = poolService.loadItemById(itemKey); + if(item == null) { + return Response.serverError().status(Status.NOT_FOUND).build(); + } + + BaseSecurity securityManager = CoreSpringFactory.getImpl(BaseSecurity.class); + Identity author = securityManager.loadIdentityByKey(identityKey, false); + if(author == null) { + return Response.serverError().status(Status.NOT_FOUND).build(); + } + + List<Identity> authors = Collections.singletonList(author); + List<QuestionItemShort> items = Collections.singletonList(item); + poolService.addAuthors(authors, items); + return Response.ok().build(); + } + + /** + * Remove an author to the question item. + * + * @response.representation.200.doc The user was successfully removed as author of the question item + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @response.representation.404.doc The question item or the user not found + * @param itemKey The question item identifier + * @param identityKey The user identifier + * @param httpRequest The HTTP request + * @return It returns 200 if the user is removed as author of the question item + */ + @DELETE + @Path("{itemKey}/authors/{identityKey}") + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response removeAuthor(@PathParam("itemKey") Long itemKey, @PathParam("identityKey") Long identityKey, + @Context HttpServletRequest httpRequest) { + if(!isQuestionPoolManager(httpRequest)) { + return Response.serverError().status(Status.UNAUTHORIZED).build(); + } + + QPoolService poolService = CoreSpringFactory.getImpl(QPoolService.class); + QuestionItem item = poolService.loadItemById(itemKey); + if(item == null) { + return Response.serverError().status(Status.NOT_FOUND).build(); + } + + BaseSecurity securityManager = CoreSpringFactory.getImpl(BaseSecurity.class); + Identity author = securityManager.loadIdentityByKey(identityKey, false); + if(author == null) { + return Response.serverError().status(Status.NOT_FOUND).build(); + } + + List<Identity> authors = Collections.singletonList(author); + List<QuestionItemShort> items = Collections.singletonList(item); + poolService.removeAuthors(authors, items); + return Response.ok().build(); + } +} diff --git a/src/main/java/org/olat/modules/qpool/ui/ImportSourcesController.java b/src/main/java/org/olat/modules/qpool/ui/ImportSourcesController.java index 827cc0a6a12baa8a9f7aba493e85d180e56c253d..0781fc21c921d5dded8f8710e2a9aa438625f9d9 100644 --- a/src/main/java/org/olat/modules/qpool/ui/ImportSourcesController.java +++ b/src/main/java/org/olat/modules/qpool/ui/ImportSourcesController.java @@ -27,6 +27,8 @@ import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.ims.qti.QTIModule; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -42,7 +44,11 @@ public class ImportSourcesController extends BasicController { public static final String IMPORT_EXCEL_QTI_12 = "qpool.import.excellike.12"; public static final String IMPORT_EXCEL_QTI_21 = "qpool.import.excellike.21"; - private final Link importRepository, importFile, importExcelLikeQTI12, importExcelLikeQTI21; + private Link importExcelLikeQTI12; + private final Link importRepository, importFile, importExcelLikeQTI21; + + @Autowired + private QTIModule qtiModule; public ImportSourcesController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); @@ -52,8 +58,10 @@ public class ImportSourcesController extends BasicController { importRepository.setIconLeftCSS("o_icon o_icon-fw o_FileResource-TEST_icon"); importFile = LinkFactory.createLink("import.file", mainVC, this); importFile.setIconLeftCSS("o_icon o_icon-fw o_filetype_file"); - importExcelLikeQTI12 = LinkFactory.createLink("import.excellike.12", mainVC, this); - importExcelLikeQTI12.setIconLeftCSS("o_icon o_icon-fw o_icon_table"); + if(qtiModule.isCreateResourcesEnabled()) { + importExcelLikeQTI12 = LinkFactory.createLink("import.excellike.12", mainVC, this); + importExcelLikeQTI12.setIconLeftCSS("o_icon o_icon-fw o_icon_table"); + } importExcelLikeQTI21 = LinkFactory.createLink("import.excellike.21", mainVC, this); importExcelLikeQTI21.setIconLeftCSS("o_icon o_icon-fw o_icon_table"); putInitialPanel(mainVC); diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java index bf514598fcc1862cee85f2cfc21fecbda0ce1b89..7d24952f4142aca4a9f71583ca1f7cde0a212cfc 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java @@ -28,6 +28,7 @@ import java.util.Map; import org.olat.NewControllerFactory; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; +import org.olat.core.commons.persistence.DB; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.FormItem; @@ -61,6 +62,7 @@ import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.group.BusinessGroup; import org.olat.group.model.BusinessGroupSelectionEvent; import org.olat.group.ui.main.SelectBusinessGroupController; +import org.olat.ims.qti.QTIModule; import org.olat.ims.qti.fileresource.SurveyFileResource; import org.olat.ims.qti.fileresource.TestFileResource; import org.olat.ims.qti.qpool.QTIQPoolServiceProvider; @@ -144,6 +146,10 @@ public class QuestionListController extends AbstractItemListController implement private boolean itemCollectionDirty = false; + @Autowired + private DB dbInstance; + @Autowired + private QTIModule qtiModule; @Autowired private QuestionPoolModule qpoolModule; @Autowired @@ -570,6 +576,9 @@ public class QuestionListController extends AbstractItemListController implement getSource().postImport(newItems, false); getItemsTable().reset(); + dbInstance.commit(); + qpoolService.index(newItems); + QPoolEvent qce = new QPoolEvent(QPoolEvent.ITEM_CREATED); fireEvent(ureq, qce); @@ -639,7 +648,12 @@ public class QuestionListController extends AbstractItemListController implement private void doOpenRepositoryImport(UserRequest ureq) { removeAsListenerAndDispose(importTestCtrl); - String[] allowed = new String[]{ ImsQTI21Resource.TYPE_NAME, TestFileResource.TYPE_NAME, SurveyFileResource.TYPE_NAME }; + String[] allowed; + if(qtiModule.isCreateResourcesEnabled()) { + allowed = new String[]{ ImsQTI21Resource.TYPE_NAME, TestFileResource.TYPE_NAME, SurveyFileResource.TYPE_NAME }; + } else { + allowed = new String[]{ ImsQTI21Resource.TYPE_NAME }; + } importTestCtrl = new ReferencableEntriesSearchController(getWindowControl(), ureq, allowed, null, translate("import.repository"), false, false, false, true, Can.copyable); listenTo(importTestCtrl); diff --git a/src/main/java/org/olat/modules/qpool/ui/_content/import_sources.html b/src/main/java/org/olat/modules/qpool/ui/_content/import_sources.html index 1344fe148d6634a07bc7c1d790a40c9ed4183011..df7541ebc93511e7cf8e1b8523d385038f916a12 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_content/import_sources.html +++ b/src/main/java/org/olat/modules/qpool/ui/_content/import_sources.html @@ -1,6 +1,8 @@ <ul class="o_dropdown list-unstyled"> <li>$r.render("import.file")</li> <li>$r.render("import.repository")</li> - <li>$r.render("import.excellike.12")</li> + #if($r.available("import.excellike.12")) + <li>$r.render("import.excellike.12")</li> + #end <li>$r.render("import.excellike.21")</li> </ul> diff --git a/src/main/java/org/olat/modules/reminder/Reminder.java b/src/main/java/org/olat/modules/reminder/Reminder.java index aeaa21b2d6e619e10fe91183fae865e35bdd3f6b..6adb4979cc1cb4a7482cef51a88047aaf93332da 100644 --- a/src/main/java/org/olat/modules/reminder/Reminder.java +++ b/src/main/java/org/olat/modules/reminder/Reminder.java @@ -42,7 +42,11 @@ public interface Reminder extends CreateInfo, ModifiedInfo { public String getConfiguration(); public void setConfiguration(String configuration); - + + public String getEmailSubject(); + + public void setEmailSubject(String emailSubject); + public String getEmailBody(); public void setEmailBody(String emailBody); diff --git a/src/main/java/org/olat/modules/reminder/ReminderModule.java b/src/main/java/org/olat/modules/reminder/ReminderModule.java index 41d5017bbf883a1983a775ac93451501a37bd2bd..7c800102df5aa077b85c05def2626f4f3880eb05 100644 --- a/src/main/java/org/olat/modules/reminder/ReminderModule.java +++ b/src/main/java/org/olat/modules/reminder/ReminderModule.java @@ -19,7 +19,8 @@ */ package org.olat.modules.reminder; -import java.text.ParseException; +import static org.quartz.CronScheduleBuilder.cronSchedule; + import java.util.ArrayList; import java.util.List; import java.util.TimeZone; @@ -32,8 +33,8 @@ import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.modules.reminder.model.SendTime; import org.quartz.CronTrigger; import org.quartz.Scheduler; -import org.quartz.SchedulerException; import org.quartz.Trigger; +import org.quartz.TriggerKey; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -48,6 +49,8 @@ import org.springframework.stereotype.Service; public class ReminderModule extends AbstractSpringModule { private static final OLog log = Tracing.createLoggerFor(ReminderModule.class); + + private final TriggerKey reminderTriggerKey = new TriggerKey("reminderTrigger", Scheduler.DEFAULT_GROUP); private static final String REMINDER_ENABLED = "remiNder.enabled"; private static final String SMS_ENABLED = "sms.enabled"; @@ -129,24 +132,28 @@ public class ReminderModule extends AbstractSpringModule { } return selectedSpi; } + /** * Default 0 0 9/1 * * ? * */ private void configureQuartzJob() { try { - Trigger trigger = scheduler.getTrigger("reminderTrigger", Scheduler.DEFAULT_GROUP); + Trigger trigger = scheduler.getTrigger(reminderTriggerKey); if(trigger instanceof CronTrigger) { CronTrigger cronTrigger = (CronTrigger)trigger; String currentCronExpression = cronTrigger.getCronExpression(); String cronExpression = getCronExpression(); if(!cronExpression.equals(currentCronExpression)) { log.info("Start reminder with this cron expression: " + cronExpression); - cronTrigger.setCronExpression(cronExpression); - scheduler.rescheduleJob("reminderTrigger", Scheduler.DEFAULT_GROUP, (Trigger)cronTrigger.clone()); + + Trigger newTrigger = cronTrigger.getTriggerBuilder() + .withSchedule(cronSchedule(cronExpression)) + .build(); + scheduler.rescheduleJob(reminderTriggerKey, newTrigger); } } - } catch (SchedulerException | ParseException e) { + } catch (Exception e) { log.error("", e); } } diff --git a/src/main/java/org/olat/modules/reminder/_spring/reminderContext.xml b/src/main/java/org/olat/modules/reminder/_spring/reminderContext.xml index 2e6f5480c794f64c8f3dcc10daba90984f2b900e..e5e946533e80fb41c60e01b971ab35a166351541 100644 --- a/src/main/java/org/olat/modules/reminder/_spring/reminderContext.xml +++ b/src/main/java/org/olat/modules/reminder/_spring/reminderContext.xml @@ -25,12 +25,12 @@ </property> </bean> - <bean id="reminderTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="reminderTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="reminderJobDetail" /> <property name="cronExpression" value="0 0 9 * * ?" /> </bean> - <bean id="reminderJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="reminderJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.modules.reminder.manager.ReminderJob"/> </bean> diff --git a/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java b/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java index d25dcc173c99e8625def453c216cad4e36f4bd57..3437eb5b894178277937ccab20ceb7a8f41132c2 100644 --- a/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java +++ b/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java @@ -100,6 +100,7 @@ public class ReminderDAO { reminder.setCreator(creator); reminder.setDescription(toCopy.getDescription() + " (Copy)"); reminder.setConfiguration(toCopy.getConfiguration()); + reminder.setEmailSubject(toCopy.getEmailSubject()); reminder.setEmailBody(toCopy.getEmailBody()); dbInstance.getCurrentEntityManager().persist(reminder); return reminder; diff --git a/src/main/java/org/olat/modules/reminder/manager/ReminderServiceImpl.java b/src/main/java/org/olat/modules/reminder/manager/ReminderServiceImpl.java index e60bbf8398e1453d81d704f468bd863bccae890e..36f1ac4e71ca120e76d1aa96ac7ef604564a9323 100644 --- a/src/main/java/org/olat/modules/reminder/manager/ReminderServiceImpl.java +++ b/src/main/java/org/olat/modules/reminder/manager/ReminderServiceImpl.java @@ -210,6 +210,7 @@ public class ReminderServiceImpl implements ReminderService { Reminder reminder = reminderDao.createReminder(newEntry, creator); reminder.setDescription(importReminder.getDescription()); reminder.setEmailBody(importReminder.getEmailBody()); + reminder.setEmailSubject(importReminder.getEmailSubject() == null ? importReminder.getDescription() : importReminder.getEmailSubject()); reminder.setConfiguration(importReminder.getConfiguration()); reminders.add(reminder); } @@ -243,8 +244,13 @@ public class ReminderServiceImpl implements ReminderService { MailContext context = new MailContextImpl("[RepositoryEntry:" + entry.getKey() + "]"); Translator trans = Util.createPackageTranslator(ReminderAdminController.class, I18nModule.getDefaultLocale()); - String subject = trans.translate("reminder.subject"); + String subject = reminder.getEmailSubject(); String body = reminder.getEmailBody(); + if (body.contains("$courseurl")) { + body = body.replace("$courseurl", "<a href=\"$courseurl\">$courseurl</a>"); + } else { + body = body + "<p>---<br />" + trans.translate("reminder.from.course", new String[] {"<a href=\"$courseurl\">$coursename</a>"}) + "</p>"; + } String metaId = UUID.randomUUID().toString(); String url = Settings.getServerContextPathURI() + "/url/RepositoryEntry/" + entry.getKey(); diff --git a/src/main/java/org/olat/modules/reminder/model/ImportExportReminder.java b/src/main/java/org/olat/modules/reminder/model/ImportExportReminder.java index 48b21dc393791124f8605089207918b4bd9d44cf..c1eeba7c1278798033a6e46e834d0dfb268b1602 100644 --- a/src/main/java/org/olat/modules/reminder/model/ImportExportReminder.java +++ b/src/main/java/org/olat/modules/reminder/model/ImportExportReminder.java @@ -35,6 +35,7 @@ public class ImportExportReminder implements Serializable { private String description; private String configuration; + private String emailSubject; // added in OO 12.0 private String emailBody; public ImportExportReminder() { @@ -44,6 +45,7 @@ public class ImportExportReminder implements Serializable { public ImportExportReminder(Reminder reminder) { description = reminder.getDescription(); configuration = reminder.getConfiguration(); + emailSubject = reminder.getEmailSubject(); emailBody = reminder.getEmailBody(); } @@ -63,6 +65,14 @@ public class ImportExportReminder implements Serializable { this.configuration = configuration; } + public String getEmailSubject() { + return emailSubject; + } + + public void setEmailSubject(String emailSubject) { + this.emailSubject = emailSubject; + } + public String getEmailBody() { return emailBody; } diff --git a/src/main/java/org/olat/modules/reminder/model/ReminderImpl.java b/src/main/java/org/olat/modules/reminder/model/ReminderImpl.java index 2dbc078efcd9a6903d8f365800eb997f484ec5ab..1090aaf6026ecd13af87be565726aabeb5b45f4d 100644 --- a/src/main/java/org/olat/modules/reminder/model/ReminderImpl.java +++ b/src/main/java/org/olat/modules/reminder/model/ReminderImpl.java @@ -93,6 +93,8 @@ public class ReminderImpl implements Reminder, Persistable { private Date startDate; @Column(name="r_configuration", nullable=true, insertable=true, updatable=true) private String configuration; + @Column(name="r_email_Subject", nullable=true, insertable=true, updatable=true) + private String emailSubject; @Column(name="r_email_body", nullable=true, insertable=true, updatable=true) private String emailBody; @@ -172,6 +174,16 @@ public class ReminderImpl implements Reminder, Persistable { this.configuration = configuration; } + @Override + public String getEmailSubject() { + return emailSubject; + } + + @Override + public void setEmailSubject(String emailSubject) { + this.emailSubject = emailSubject; + } + @Override public String getEmailBody() { return emailBody; diff --git a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_de.properties index 9d79a70eae1c295a43acde05de81944df9980c52..8daac4313e42e61f60b57ed47edd203a72e97808 100644 --- a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_de.properties @@ -17,7 +17,7 @@ interval.4=Alle vier Stunden interval.2=Alle zwei Stunden interval.1=Jede Stunde reminder.admin.title=Kurserinnerungen -reminder.subject=Kurserinnerung +reminder.from.course=Erinnerung aus Kurs {0} rule.after.date=Nach Datum rule.course.enrollment.date=Einschreibedatum rule.course.role=Kursrolle diff --git a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_en.properties index 2a185d8f5a6ad53c4de5413e6ae5a9f76879f8dd..92b22ac4fededdddd8f944bf03aa575d3ef821ea 100644 --- a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_en.properties @@ -17,7 +17,7 @@ interval.4=Every 4 hours interval.2=Every 2 hours interval.1=Every hour reminder.admin.title=Course reminders -reminder.subject=Course reminder +reminder.from.course=Reminder from course {0} rule.after.date=After date rule.course.enrollment.date=Enrollment date rule.course.role=Course role diff --git a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_fr.properties index e417adb7147aed4e84857e50a7fb18a705a5b010..8d2f7df4111dd43659e832ee95e64d2ebade435a 100644 --- a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Sun Nov 08 12:23:43 CET 2015 +#Tue Aug 15 17:27:13 CEST 2017 admin.menu.title=Rappels du cours admin.menu.title.alt=Rappels de cours after.validfrom=apr\u00E8s le d\u00E9but du cours @@ -17,7 +17,7 @@ interval.4=Toutes les quatre heures interval.6=Quatre fois par jour interval.8=Trois fois par jour reminder.admin.title=Rappels des cours -reminder.subject=Rappel +reminder.from.course=Rappel du cours {0} rule.after.date=Fonction de la date rule.course.enrollment.date=Date d'inscription rule.course.role=R\u00F4le au sein du cours diff --git a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_it.properties index 8b3716266780dcce2afda126b4476869c663c887..264f346d3e34a4dc8c2142f4c7ce9f0cb4beecf3 100644 --- a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_it.properties @@ -17,7 +17,6 @@ interval.4=Ogni 4 ore interval.6=Quattro volte al giorno interval.8=Tre volte al giorno reminder.admin.title=Promemoria dei corsi -reminder.subject=Promemoria di corso rule.after.date=Dopo la data rule.course.enrollment.date=Data di iscrizione rule.course.role=Ruolo nel corso diff --git a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_pt_BR.properties index b4bd61fc6154f6b122da201311cd0b24743f3597..a8d38a595f0ddbf01b207eb5df7439a9ad710547 100644 --- a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Mon Feb 08 20:00:30 CET 2016 +#Tue Sep 05 22:44:54 CEST 2017 admin.menu.title=Lembretes de curso admin.menu.title.alt=Lembretes de Curso after.validfrom=Ap\u00F3s o in\u00EDcio @@ -17,7 +17,7 @@ interval.4=A cada 4 horas interval.6=4 vezes ao dia interval.8=3 vezes ao dia reminder.admin.title=Lembretes de Curso -reminder.subject=Lembrete +reminder.from.course=Lembrete de curso {0} rule.after.date=Ap\u00F3s data rule.course.enrollment.date=Data de inscri\u00E7\u00E3o rule.course.role=Fun\u00E7\u00E3o curso diff --git a/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java b/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java index 6454c4021d080df9116d824e8e29d84bea50a7a9..3a41494cb6fde67267eee3e222319df64a749b79 100644 --- a/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java +++ b/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java @@ -55,6 +55,7 @@ import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.user.UserManager; /** @@ -199,14 +200,14 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable { // </OLATEE-27> boolean increment = !attemptsIncremented && finish; ScoreEvaluation sceval = new ScoreEvaluation(new Float(0.0f), Boolean.valueOf(passed)); - scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment); + scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user); if(increment) { attemptsIncremented = true; } } else if (!config.getBooleanSafe(ScormEditController.CONFIG_ATTEMPTSDEPENDONSCORE, false)) { boolean increment = !attemptsIncremented && finish; ScoreEvaluation sceval = scormNode.getUserScoreEvaluation(userCourseEnv); - scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment); + scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user); if(increment) { attemptsIncremented = true; } @@ -214,7 +215,7 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable { } else { boolean increment = !attemptsIncremented && finish; ScoreEvaluation sceval = new ScoreEvaluation(new Float(0.0f), Boolean.valueOf(passed)); - scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, false); + scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, false, Role.user); if(increment) { attemptsIncremented = true; } @@ -254,14 +255,14 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable { // </OLATEE-27> boolean increment = !attemptsIncremented && finish; ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), Boolean.valueOf(passed)); - scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment); + scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user); if(increment) { attemptsIncremented = true; } } else if (!config.getBooleanSafe(ScormEditController.CONFIG_ATTEMPTSDEPENDONSCORE, false)) { boolean increment = !attemptsIncremented && finish; ScoreEvaluation sceval = scormNode.getUserScoreEvaluation(userCourseEnv); - scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment); + scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user); if(increment) { attemptsIncremented = true; } @@ -274,7 +275,7 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable { // </OLATEE-27> boolean increment = !attemptsIncremented && finish; ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), Boolean.valueOf(passed)); - scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, false); + scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, false, Role.user); if(increment) { attemptsIncremented = true; } diff --git a/src/main/java/org/olat/modules/video/VideoManager.java b/src/main/java/org/olat/modules/video/VideoManager.java index 70b8124218b89b76c0c2f51b83603291fb6e9f11..1f50f82fe7b20154a956cacd370471d1eef7790b 100644 --- a/src/main/java/org/olat/modules/video/VideoManager.java +++ b/src/main/java/org/olat/modules/video/VideoManager.java @@ -45,6 +45,9 @@ import org.olat.resource.OLATResource; */ public interface VideoManager { + public static final String FILETYPE_SRT = "srt"; + public static final String DOT = "." ; + /** * Checks for video file. * diff --git a/src/main/java/org/olat/modules/video/VideoModule.java b/src/main/java/org/olat/modules/video/VideoModule.java index 5de25406d858c347c7fe8bed609aaed191322104..bce9862581dff150803e924edc92683cd01b2e6b 100644 --- a/src/main/java/org/olat/modules/video/VideoModule.java +++ b/src/main/java/org/olat/modules/video/VideoModule.java @@ -72,6 +72,8 @@ public class VideoModule extends AbstractSpringModule { private String transcodingDir; @Value("${video.transcoding.resolution.preferred}") private String transcodingPreferredResolutionConf; + @Value("${video.transcoding.profile}") + private String transcodingProfile; private int[] transcodingResolutionsArr; //= new int[] { 1080,720,480,360 }; private Integer preferredDefaultResolution;// = new Integer(720); @@ -133,6 +135,9 @@ public class VideoModule extends AbstractSpringModule { preferredDefaultResolution = getIntPropertyValue(PREFERRED_RESOLUTION); } + // clean setting of injected config + setVideoTranscodingProfile(this.transcodingProfile); + log.info("video.enabled=" + isEnabled()); log.info("video.coursenode.enabled=" + isCoursenodeEnabled()); @@ -141,6 +146,7 @@ public class VideoModule extends AbstractSpringModule { log.info("video.transcoding.resolution.preferred=" + getPreferredDefaultResolution()); log.info("video.transcoding.taskset.cpuconfig=" + getTranscodingTasksetConfig()); log.info("video.transcoding.local=" + isTranscodingLocal()); + log.info("video.transcoding.profile=" + getVideoTranscodingProfile()); // Register video site for activation in top navigation NewControllerFactory.getInstance().addContextEntryControllerCreator(VideoSite.class.getSimpleName(), @@ -262,5 +268,22 @@ public class VideoModule extends AbstractSpringModule { this.transcodingLocal = transcodingLocal; setStringProperty(VIDEOTRANSCODING_LOCAL, Boolean.toString(transcodingLocal), true); } + + public void setVideoTranscodingProfile(String profile) { + if (StringHelper.containsNonWhitespace(profile)) { + if (profile.equals("Fast")) { + this.transcodingProfile = "Fast"; + return; + } else if (profile.equals("Very Fast")) { + this.transcodingProfile = "Very Fast"; + return; + } + } + this.transcodingProfile = "Fast"; // default; + } + + public String getVideoTranscodingProfile() { + return this.transcodingProfile; + } } diff --git a/src/main/java/org/olat/modules/video/_spring/videoContext.xml b/src/main/java/org/olat/modules/video/_spring/videoContext.xml index 7d962b2e32c01c259aa459566014c20995063764..80ba9aafa16efe8fcc0d395237d6e2f167c58ea8 100644 --- a/src/main/java/org/olat/modules/video/_spring/videoContext.xml +++ b/src/main/java/org/olat/modules/video/_spring/videoContext.xml @@ -6,7 +6,7 @@ http://www.springframework.org/schema/beans/spring-beans.xsd"> - <bean id="videoTranscodingTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="videoTranscodingTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="videoTranscodingJobDetail" /> <!-- adjust cron style syntax for your notification needs "0 10 0 * *" e.g. 10 minutes after midnight @@ -30,8 +30,9 @@ <property name="startDelay" value="350000" /> </bean> - <bean id="videoTranscodingJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean"> + <bean id="videoTranscodingJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="org.olat.modules.video.manager.VideoTranscodingJob" /> + <property name="durability" value="true" /> </bean> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> diff --git a/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java b/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java index 28d716d331bdb941e33f368a739c93495e1941d2..99352c0c15fcbe743ae918dbf102db81c6dcb68a 100644 --- a/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java +++ b/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java @@ -86,7 +86,7 @@ import org.olat.repository.RepositoryEntryImportExport; import org.olat.repository.RepositoryEntryImportExport.RepositoryEntryImport; import org.olat.repository.RepositoryManager; import org.olat.resource.OLATResource; -import org.quartz.JobDetail; +import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; @@ -105,17 +105,18 @@ public class VideoManagerImpl implements VideoManager { protected static final String DIRNAME_REPOENTRY = "repoentry"; public static final String FILETYPE_MP4 = "mp4"; private static final String FILETYPE_JPG = "jpg"; - private static final String FILETYPE_SRT = "srt"; private static final String FILENAME_POSTER_JPG = "poster.jpg"; private static final String FILENAME_VIDEO_MP4 = "video.mp4"; private static final String FILENAME_CHAPTERS_VTT = "chapters.vtt"; private static final String FILENAME_VIDEO_METADATA_XML = "video_metadata.xml"; private static final String DIRNAME_MASTER = "master"; public static final String TRACK = "track_"; - public static final String DOT = "." ; + private static final SimpleDateFormat displayDateFormat = new SimpleDateFormat("HH:mm:ss"); private static final SimpleDateFormat vttDateFormat = new SimpleDateFormat("HH:mm:ss.SSS"); + + private final JobKey videoJobKey = new JobKey("videoTranscodingJobDetail", Scheduler.DEFAULT_GROUP); @Autowired private MovieService movieService; @@ -427,8 +428,7 @@ public class VideoManagerImpl implements VideoManager { // 3) Start transcoding immediately, force job execution if (videoModule.isTranscodingLocal()) { try { - JobDetail detail = scheduler.getJobDetail("videoTranscodingJobDetail", Scheduler.DEFAULT_GROUP); - scheduler.triggerJob(detail.getName(), detail.getGroup()); + scheduler.triggerJob(videoJobKey); } catch (SchedulerException e) { log.error("Error while starting video transcoding job", e); } diff --git a/src/main/java/org/olat/modules/video/manager/VideoTranscodingJob.java b/src/main/java/org/olat/modules/video/manager/VideoTranscodingJob.java index 8bb6cfd3d270d9f1d1e26e5d31f24497beb86c4a..65c39bd95abe1def5df8fe5b75d285f2d0cba922 100644 --- a/src/main/java/org/olat/modules/video/manager/VideoTranscodingJob.java +++ b/src/main/java/org/olat/modules/video/manager/VideoTranscodingJob.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.hibernate.ObjectDeletedException; @@ -41,7 +42,6 @@ import org.olat.modules.video.VideoTranscoding; import org.olat.resource.OLATResource; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; -import org.quartz.StatefulJob; /** * @@ -49,7 +49,8 @@ import org.quartz.StatefulJob; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class VideoTranscodingJob extends JobWithDB implements StatefulJob { +public class VideoTranscodingJob extends JobWithDB { + private ArrayList<String> resolutionsWithProfile = new ArrayList<String>(Arrays.asList("1080", "720", "480")); /** * @@ -125,6 +126,12 @@ public class VideoTranscodingJob extends JobWithDB implements StatefulJob { videoTranscoding.setTranscoder(VideoTranscoding.TRANSCODER_LOCAL); videoTranscoding = videoManager.updateVideoTranscoding(videoTranscoding); + String resolution = Integer.toString(videoTranscoding.getResolution()); + String profile = "Normal"; // Legacy fallback + if (resolutionsWithProfile.contains(resolution)) { + profile = videoModule.getVideoTranscodingProfile() + " " + resolution + "p30"; + } + ArrayList<String> cmd = new ArrayList<>(); String tasksetConfig = videoModule.getTranscodingTasksetConfig(); if (tasksetConfig != null && !"Mac OS X".equals(System.getProperty("os.name"))) { @@ -137,13 +144,12 @@ public class VideoTranscodingJob extends JobWithDB implements StatefulJob { cmd.add(masterFile.getAbsolutePath()); cmd.add("-o"); cmd.add(transcodedFile.getAbsolutePath()); - cmd.add("--optimize"); + cmd.add("--optimize"); // add video infos to header for web "fast start" cmd.add("--preset"); - cmd.add("Normal"); + cmd.add(profile); cmd.add("--height"); - cmd.add(Integer.toString(videoTranscoding.getResolution())); - cmd.add("--deinterlace"); - cmd.add("--crop"); + cmd.add(resolution); + cmd.add("--crop"); // do not crop cmd.add("0:0:0:0"); Process process = null; diff --git a/src/main/java/org/olat/modules/video/ui/QualityTableRow.java b/src/main/java/org/olat/modules/video/ui/QualityTableRow.java index c6f0cdb11065143b6a897cc0d864c9fa17474517..b3f7b750c08ee98e49dca7b78c0e1cc47d0348ca 100644 --- a/src/main/java/org/olat/modules/video/ui/QualityTableRow.java +++ b/src/main/java/org/olat/modules/video/ui/QualityTableRow.java @@ -19,7 +19,6 @@ */ package org.olat.modules.video.ui; -import org.olat.core.gui.components.form.flexible.FormUIFactory; import org.olat.core.gui.components.form.flexible.elements.FormLink; /** @@ -37,8 +36,6 @@ public class QualityTableRow { private String format; private FormLink deleteLink; - protected FormUIFactory uifactory = FormUIFactory.getInstance(); - /** * * @param resolution diff --git a/src/main/java/org/olat/modules/video/ui/TrackTableRow.java b/src/main/java/org/olat/modules/video/ui/TrackTableRow.java index a61129732e9fd2bcd4e9572cb889a5876b2b36b7..025d1db6127ab8ea0f9baf85e5e78db28a4caba3 100644 --- a/src/main/java/org/olat/modules/video/ui/TrackTableRow.java +++ b/src/main/java/org/olat/modules/video/ui/TrackTableRow.java @@ -19,7 +19,6 @@ */ package org.olat.modules.video.ui; -import org.olat.core.gui.components.form.flexible.FormUIFactory; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.util.vfs.VFSLeaf; @@ -32,30 +31,25 @@ import org.olat.core.util.vfs.VFSLeaf; */ public class TrackTableRow { - private String language; - private VFSLeaf track; - private FormLink deleteLink; - - protected FormUIFactory uifactory = FormUIFactory.getInstance(); + private final String language; + private final VFSLeaf track; + private final FormLink deleteLink; public TrackTableRow(String language, VFSLeaf track, FormLink deleteLink) { this.language = language; this.track = track; this.deleteLink = deleteLink; - this.deleteLink.setIconLeftCSS("o_icon o_icon-fw o_icon_delete_item"); - } - public VFSLeaf getTrack(){ + public VFSLeaf getTrack() { return track; } - public String getLanguage(){ + public String getLanguage() { return language; } - public FormLink getDeleteLink(){ + public FormLink getDeleteLink() { return deleteLink; } - -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/video/ui/TrackUploadEvent.java b/src/main/java/org/olat/modules/video/ui/TrackUploadEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..5341ffb763a2b195d7a5baec138a9159176a02a5 --- /dev/null +++ b/src/main/java/org/olat/modules/video/ui/TrackUploadEvent.java @@ -0,0 +1,50 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.video.ui; + +import org.olat.core.gui.control.Event; +import org.olat.core.util.vfs.VFSLeaf; + +/** + * + * Initial date: 21 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class TrackUploadEvent extends Event { + + private static final long serialVersionUID = -2951558903014424854L; + private final String lang; + private final VFSLeaf track; + + public TrackUploadEvent(String lang, VFSLeaf track) { + super("track-upload"); + this.lang = lang; + this.track = track; + } + + public String getLang() { + return lang; + } + + public VFSLeaf getTrack() { + return track; + } +} diff --git a/src/main/java/org/olat/modules/video/ui/TranscodingQueueTableModel.java b/src/main/java/org/olat/modules/video/ui/TranscodingQueueTableModel.java index d2f8cabbdf0b4ad2cdb0f38ad6bce35a2159c0ce..ff347673fb8e120be7d229ec39533e36e46ea5aa 100644 --- a/src/main/java/org/olat/modules/video/ui/TranscodingQueueTableModel.java +++ b/src/main/java/org/olat/modules/video/ui/TranscodingQueueTableModel.java @@ -19,7 +19,6 @@ */ package org.olat.modules.video.ui; -import org.olat.core.gui.components.form.flexible.FormUIFactory; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; @@ -34,7 +33,6 @@ import org.olat.core.gui.translator.Translator; */ public class TranscodingQueueTableModel extends DefaultFlexiTableDataModel<TranscodingQueueTableRow>{ - protected FormUIFactory uifactory = FormUIFactory.getInstance(); private Translator translator; public TranscodingQueueTableModel(FlexiTableColumnModel columnModel, Translator translator) { super(columnModel); diff --git a/src/main/java/org/olat/modules/video/ui/TranscodingQueueTableRow.java b/src/main/java/org/olat/modules/video/ui/TranscodingQueueTableRow.java index 218bc12be9f4024a8c0bbea43e42cc3f53abfd60..84ca97b8e577e6bee3d7b2c10f80c51bd0d8dae7 100644 --- a/src/main/java/org/olat/modules/video/ui/TranscodingQueueTableRow.java +++ b/src/main/java/org/olat/modules/video/ui/TranscodingQueueTableRow.java @@ -21,7 +21,6 @@ package org.olat.modules.video.ui; import java.util.Date; -import org.olat.core.gui.components.form.flexible.FormUIFactory; import org.olat.core.gui.components.form.flexible.elements.FormLink; /** @@ -42,8 +41,6 @@ public class TranscodingQueueTableRow { private FormLink retranscodeLink; private Object[] failureReason; - protected FormUIFactory uifactory = FormUIFactory.getInstance(); - /** * Instantiates a new transcoding queue table row. diff --git a/src/main/java/org/olat/modules/video/ui/TranscodingTableModel.java b/src/main/java/org/olat/modules/video/ui/TranscodingTableModel.java index d5534291b93abb40aa14f2138db4af953892159d..81f34f0318e63d1641111556fa69b4c775cd51e5 100644 --- a/src/main/java/org/olat/modules/video/ui/TranscodingTableModel.java +++ b/src/main/java/org/olat/modules/video/ui/TranscodingTableModel.java @@ -19,7 +19,6 @@ */ package org.olat.modules.video.ui; -import org.olat.core.gui.components.form.flexible.FormUIFactory; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; @@ -33,7 +32,6 @@ import org.olat.core.gui.translator.Translator; */ public class TranscodingTableModel extends DefaultFlexiTableDataModel<TranscodingRow>{ - protected FormUIFactory uifactory = FormUIFactory.getInstance(); private Translator translator; public TranscodingTableModel(FlexiTableColumnModel columnModel, Translator translator) { super(columnModel); diff --git a/src/main/java/org/olat/modules/video/ui/VideoChapterEditController.java b/src/main/java/org/olat/modules/video/ui/VideoChapterEditController.java index 934ba043d7067e9ec7b8dc8467c6233d95197d44..980857bb3bbdb2c5ffdc335552da0d605d2c1609 100644 --- a/src/main/java/org/olat/modules/video/ui/VideoChapterEditController.java +++ b/src/main/java/org/olat/modules/video/ui/VideoChapterEditController.java @@ -50,6 +50,7 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle import org.olat.core.gui.control.winmgr.JSCommand; import org.olat.core.util.StringHelper; import org.olat.modules.video.VideoManager; +import org.olat.modules.video.VideoMeta; import org.olat.modules.video.ui.VideoChapterTableModel.ChapterTableCols; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; @@ -85,7 +86,6 @@ public class VideoChapterEditController extends BasicController { displayDateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); VelocityContainer mainVC = createVelocityContainer("video_chapter_editor"); - //video preview videoDisplayCtr = new VideoDisplayController(ureq, getWindowControl(), entry, false, false, false, false, null, false, false, null, false); videoDisplayCtr.setTimeUpdateListener(true); @@ -98,9 +98,31 @@ public class VideoChapterEditController extends BasicController { chaptersEditCtrl = new VideoChaptersController(ureq, getWindowControl()); listenTo(chaptersEditCtrl); mainVC.put("chapters", chaptersEditCtrl.getInitialComponent()); - + + initDurationInSeconds(); putInitialPanel(mainVC); } + + private void initDurationInSeconds() { + String duration = entry.getExpenditureOfWork(); + if (!StringHelper.containsNonWhitespace(duration)) { + VideoMeta metadata = videoDisplayCtr.getVideoMetadata(); + if(metadata != null) { + duration = metadata.getLength(); + } + } + + if(StringHelper.containsNonWhitespace(duration)) { + try { + if(duration.indexOf(':') == duration.lastIndexOf(':')) { + duration = "00:" + duration; + } + durationInSeconds = displayDateFormat.parse(duration).getTime() / 1000; + } catch (Exception e) { + logWarn("Cannot parse expenditure of work: " + duration, e); + } + } + } @Override protected void doDispose() { @@ -270,7 +292,7 @@ public class VideoChapterEditController extends BasicController { private void doEditChapter(UserRequest ureq, VideoChapterTableRow videoChapterTableRow, boolean chapterExists) { if(chapterEditCtr != null) return; - + chapterEditCtr = new ChapterEditController(ureq, getWindowControl(), videoChapterTableRow, chapterExists, tableModel.getObjects(), durationInSeconds); listenTo(chapterEditCtr); diff --git a/src/main/java/org/olat/modules/video/ui/VideoDisplayController.java b/src/main/java/org/olat/modules/video/ui/VideoDisplayController.java index 54d3d8c845befe85d2b9cc0f0b427d0bd3fb9e26..1271840f730581ce90904fb1b37263721af1e2d5 100644 --- a/src/main/java/org/olat/modules/video/ui/VideoDisplayController.java +++ b/src/main/java/org/olat/modules/video/ui/VideoDisplayController.java @@ -79,7 +79,7 @@ public class VideoDisplayController extends BasicController { private RepositoryEntry entry; private String descriptionText; private String mediaRepoBaseUrl; - + private VideoMeta videoMetadata; public VideoDisplayController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, boolean autoWidth) { this(ureq, wControl, entry, false, false, false, true, null, false, autoWidth, null, false); @@ -108,7 +108,7 @@ public class VideoDisplayController extends BasicController { VFSLeaf video = videoManager.getMasterVideoFile(entry.getOlatResource()); if(video != null) { - VideoMeta videoMetadata = videoManager.getVideoMetadata(entry.getOlatResource()); + videoMetadata = videoManager.getVideoMetadata(entry.getOlatResource()); if(autoWidth){ mainVC.contextPut("height", 480); mainVC.contextPut("width", "100%"); @@ -145,6 +145,10 @@ public class VideoDisplayController extends BasicController { } } + public VideoMeta getVideoMetadata() { + return videoMetadata; + } + public void setTimeUpdateListener(boolean enable) { mainVC.contextPut("listenTimeUpdate", enable); } @@ -292,6 +296,13 @@ public class VideoDisplayController extends BasicController { // Load video chapter if available mainVC.contextPut("hasChapters", videoManager.hasChapters(entry.getOlatResource())); + + // Add duration without preloading video + String duration = entry.getExpenditureOfWork(); + if (!StringHelper.containsNonWhitespace(duration)) { + duration = "00:00"; + } + mainVC.contextPut("duration", duration); } } diff --git a/src/main/java/org/olat/modules/video/ui/VideoQualityTableModel.java b/src/main/java/org/olat/modules/video/ui/VideoQualityTableModel.java index 9c98528d74fa066b85db16b0f797944987091491..639449e9d79f334e12701c26c39d4540fb0b637c 100644 --- a/src/main/java/org/olat/modules/video/ui/VideoQualityTableModel.java +++ b/src/main/java/org/olat/modules/video/ui/VideoQualityTableModel.java @@ -19,7 +19,6 @@ */ package org.olat.modules.video.ui; -import org.olat.core.gui.components.form.flexible.FormUIFactory; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; @@ -34,7 +33,6 @@ import org.olat.core.gui.translator.Translator; */ public class VideoQualityTableModel extends DefaultFlexiTableDataModel<QualityTableRow>{ - protected FormUIFactory uifactory = FormUIFactory.getInstance(); private Translator translator; public VideoQualityTableModel(FlexiTableColumnModel columnModel, Translator translator) { super(columnModel); diff --git a/src/main/java/org/olat/modules/video/ui/VideoTrackEditController.java b/src/main/java/org/olat/modules/video/ui/VideoTrackEditController.java index 426c69285927e800a203c63f190d106d4b369c19..80035a0dac27ab515cc2ce538c7c80fb6fbed37d 100644 --- a/src/main/java/org/olat/modules/video/ui/VideoTrackEditController.java +++ b/src/main/java/org/olat/modules/video/ui/VideoTrackEditController.java @@ -20,10 +20,9 @@ package org.olat.modules.video.ui; import java.util.ArrayList; -import java.util.HashMap; +import java.util.List; import java.util.Map; -import org.olat.core.commons.modules.bc.FolderEvent; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -58,11 +57,10 @@ public class VideoTrackEditController extends FormBasicController { private VideoTrackUploadForm trackUploadForm; private CloseableModalController cmc; - private Map<String, TrackTableRow> rows; - + private OLATResource videoResource; + @Autowired private VideoManager videoManager; - private OLATResource videoResource; public VideoTrackEditController(UserRequest ureq, WindowControl wControl, OLATResource videoResource) { super(ureq, wControl, LAYOUT_BAREBONE); @@ -87,78 +85,82 @@ public class VideoTrackEditController extends FormBasicController { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, TrackTableCols.file.i18nKey(), TrackTableCols.file.ordinal(), true, TrackTableCols.file.name())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TrackTableCols.language.i18nKey(), TrackTableCols.language.ordinal(), true, TrackTableCols.language.name())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, TrackTableCols.delete.i18nKey(), TrackTableCols.delete.ordinal(),false, TrackTableCols.delete.name())); - tableModel = new VideoTracksTableModel(columnsModel, getTranslator()); + tableModel = new VideoTracksTableModel(columnsModel, getLocale()); tableEl = uifactory.addTableElement(getWindowControl(), "tracks", tableModel, getTranslator(), generalCont); tableEl.setCustomizeColumns(false); Map<String, VFSLeaf> tracks = videoManager.getAllTracks(videoResource); - rows = new HashMap<String,TrackTableRow>(tracks.size()); - if (!tracks.isEmpty()) { - for (Map.Entry<String, VFSLeaf> entry : tracks.entrySet()) { - FormLink delButton = uifactory.addFormLink(entry.getKey(), "deleteTrack", "track.delete", "track.delete", null, Link.BUTTON); - rows.put(entry.getKey(), new TrackTableRow(entry.getKey(), entry.getValue(), delButton)); - - } - tableModel.setObjects(new ArrayList<TrackTableRow>(rows.values())); + List<TrackTableRow> rows = new ArrayList<>(tracks.size()); + for (Map.Entry<String, VFSLeaf> entry : tracks.entrySet()) { + rows.add(forgeRow(entry.getKey(), entry.getValue())); } -// tableEl.setVisible(!videoManager.getAllTracks(videoResource).isEmpty()); - tableEl.setVisible(true); + tableModel.setObjects(rows); tableEl.setEmtpyTableMessageKey("track.notrack"); addButton = uifactory.addFormLink("add.track", generalCont, Link.BUTTON); } - - @Override - protected boolean validateFormLogic(UserRequest ureq) { - - return true; + + private TrackTableRow forgeRow(String language, VFSLeaf track) { + FormLink delButton = uifactory.addFormLink("lang_".concat(language), "deleteTrack", "track.delete", "track.delete", null, Link.LINK); + delButton.setIconLeftCSS("o_icon o_icon-fw o_icon_delete_item"); + TrackTableRow row = new TrackTableRow(language, track, delButton); + delButton.setUserObject(row); + return row; } @Override protected void formOK(UserRequest ureq) { - + // } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if (addButton == source) { doAddTrack(ureq); - }else if (source.getComponent() instanceof Link){ - String lang = rows.get(source.getName()).getLanguage(); - videoManager.removeTrack(videoResource, lang); - rows.remove(rows.get(source.getName()).getLanguage()); - tableModel.setObjects(new ArrayList<TrackTableRow>(rows.values())); - tableEl.reset(); + } else if (source instanceof FormLink) { + FormLink link = (FormLink)source; + if("deleteTrack".equals(link.getCmd())) { + TrackTableRow row = (TrackTableRow)link.getUserObject(); + videoManager.removeTrack(videoResource, row.getLanguage()); + List<TrackTableRow> rows = tableModel.getObjects(); + rows.remove(row); + tableModel.setObjects(rows); + tableEl.reset(true, true, true); + } } } @Override public void event(UserRequest ureq, Controller source, Event event) { - if(source == trackUploadForm){ - rows.put(trackUploadForm.getLang(), new TrackTableRow(trackUploadForm.getLang(), (VFSLeaf) ((FolderEvent) event).getItem(), uifactory.addFormLink(trackUploadForm.getLang(),"deleteTrack", "track.delete", "track.delete", null, Link.BUTTON))); - tableModel.setObjects(new ArrayList<TrackTableRow>(rows.values())); - tableEl.reset(); - tableEl.setVisible(true); - tableEl.setEnabled(true); - cmc.deactivate(); - // cleanup - removeAsListenerAndDispose(trackUploadForm); - removeAsListenerAndDispose(cmc); - } else if(event.getCommand() == "CLOSE_MODAL_EVENT"){ + if(source == trackUploadForm) { + if(event instanceof TrackUploadEvent) { + TrackUploadEvent fEvent = (TrackUploadEvent)event; + TrackTableRow row = forgeRow(fEvent.getLang(), fEvent.getTrack()); + List<TrackTableRow> rows = tableModel.getObjects(); + rows.add(row); + tableModel.setObjects(rows); + tableEl.reset(true, true, true); + } cmc.deactivate(); - // cleanup - removeAsListenerAndDispose(trackUploadForm); - removeAsListenerAndDispose(cmc); + cleanUp(); + } else if(cmc == source){ + cleanUp(); } } - + + private void cleanUp() { + removeAsListenerAndDispose(trackUploadForm); + removeAsListenerAndDispose(cmc); + trackUploadForm = null; + cmc = null; + } private void doAddTrack(UserRequest ureq) { trackUploadForm = new VideoTrackUploadForm(ureq, getWindowControl(), videoResource); listenTo(trackUploadForm); + cmc = new CloseableModalController(getWindowControl(), "close", trackUploadForm.getInitialComponent()); listenTo(cmc); cmc.activate(); } - -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/video/ui/VideoTrackUploadForm.java b/src/main/java/org/olat/modules/video/ui/VideoTrackUploadForm.java index 26cbc5529caed726208d54715aaad998d2a91b38..de9d549906d08a5b237f50993b73e525385040ca 100644 --- a/src/main/java/org/olat/modules/video/ui/VideoTrackUploadForm.java +++ b/src/main/java/org/olat/modules/video/ui/VideoTrackUploadForm.java @@ -21,14 +21,10 @@ package org.olat.modules.video.ui; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Set; import java.util.stream.Collectors; -import org.apache.commons.io.FilenameUtils; -import org.olat.core.commons.modules.bc.FolderEvent; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FileElement; @@ -36,9 +32,10 @@ import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; 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.vfs.Quota; import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.video.VideoManager; import org.olat.modules.video.manager.VideoManagerImpl; import org.olat.resource.OLATResource; @@ -56,17 +53,11 @@ public class VideoTrackUploadForm extends FormBasicController { private FileElement fileEl; private SingleSelection langsItem; - private long remainingSpace; private VFSContainer mediaContainer; @Autowired private VideoManager videoManager; - private static final Set<String> trackMimeTypes = new HashSet<String>(); - static { - trackMimeTypes.add("text/plain"); - } - public VideoTrackUploadForm(UserRequest ureq, WindowControl wControl, OLATResource videoResource) { super(ureq, wControl); mediaContainer = videoManager.getMasterContainer(videoResource); @@ -75,13 +66,10 @@ public class VideoTrackUploadForm extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - remainingSpace = Quota.UNLIMITED; - List<String> langs = new ArrayList<String>(); - List<String> dispLangs = new ArrayList<String>(); - - + List<String> langs = new ArrayList<>(); + List<String> dispLangs = new ArrayList<>(); for(Locale locale : SimpleDateFormat.getAvailableLocales()){ - if(locale.hashCode()!=0){ + if(locale.hashCode() != 0){ langs.add(locale.getLanguage()); dispLangs.add(locale.getDisplayLanguage(getTranslator().getLocale())); } @@ -90,47 +78,57 @@ public class VideoTrackUploadForm extends FormBasicController { List<String> langsWithoutDup = langs.parallelStream().distinct().collect(Collectors.toList()); List<String> dispLangsWithoutDup = dispLangs.parallelStream().distinct().collect(Collectors.toList()); - langsItem = uifactory.addDropdownSingleselect("track.langs", formLayout, langsWithoutDup.toArray(new String[langsWithoutDup.size()]), dispLangsWithoutDup.toArray(new String[dispLangsWithoutDup.size()]), null); + langsItem = uifactory.addDropdownSingleselect("track.langs", formLayout, + langsWithoutDup.toArray(new String[langsWithoutDup.size()]), + dispLangsWithoutDup.toArray(new String[dispLangsWithoutDup.size()]), null); fileEl = uifactory.addFileElement(getWindowControl(), "track.upload", formLayout); -// fileEl.limitToMimeType(trackMimeTypes, "video.config.track.error.type", null); langsItem.setMandatory(true); FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonGroupLayout", getTranslator()); formLayout.add(buttonGroupLayout); buttonGroupLayout.setElementCssClass("o_sel_upload_buttons"); + + uifactory.addFormCancelButton("cancel", buttonGroupLayout, ureq, getWindowControl()); uifactory.addFormSubmitButton("track.upload", buttonGroupLayout); } @Override - protected void formOK(UserRequest ureq) { - if ( fileEl.isUploadSuccess()) { - if (remainingSpace != -1) { - if (fileEl.getUploadFile().length() / 1024 > remainingSpace) { - fileEl.setErrorKey("QuotaExceeded", null); - fileEl.getUploadFile().delete(); - return; - } - } else { - String uploadfilename = VideoManagerImpl.TRACK + langsItem.getSelectedKey() + VideoManagerImpl.DOT - + FilenameUtils.getExtension(fileEl.getUploadFileName()); - fileEl.setUploadFileName(uploadfilename); - fireEvent(ureq, new FolderEvent(FolderEvent.UPLOAD_EVENT, fileEl.moveUploadFileTo(mediaContainer))); + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + fileEl.clearError(); + if (fileEl.isUploadSuccess()) { + String filename = fileEl.getUploadFileName(); + if(!filename.endsWith(VideoManager.FILETYPE_SRT)) { + fileEl.setErrorKey("track.upload.error.filetype", null); + allOk &= false; } } else { fileEl.setErrorKey("track.upload.error.nofile", null); + allOk &= false; } + return allOk & super.validateFormLogic(ureq); } - - protected String getLang(){ - return langsItem.getSelectedKey(); + @Override + protected void formOK(UserRequest ureq) { + if (fileEl.isUploadSuccess()) { + String uploadfilename = VideoManagerImpl.TRACK + langsItem.getSelectedKey() + + VideoManager.DOT + VideoManager.FILETYPE_SRT; + fileEl.setUploadFileName(uploadfilename); + VFSLeaf track = fileEl.moveUploadFileTo(mediaContainer); + fireEvent(ureq, new TrackUploadEvent(langsItem.getSelectedKey(), track)); + } } + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } @Override protected void doDispose() { // nothing to dispose - } } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/video/ui/VideoTracksTableModel.java b/src/main/java/org/olat/modules/video/ui/VideoTracksTableModel.java index b11e79c29193d15636da9814eb442321711c18a1..2a33ec90ade4cb27d770b45eed55cd4d110363f6 100644 --- a/src/main/java/org/olat/modules/video/ui/VideoTracksTableModel.java +++ b/src/main/java/org/olat/modules/video/ui/VideoTracksTableModel.java @@ -21,10 +21,8 @@ package org.olat.modules.video.ui; import java.util.Locale; -import org.olat.core.gui.components.form.flexible.FormUIFactory; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; -import org.olat.core.gui.translator.Translator; /** * table-model for to list de available subtitle-tracks in the metadata @@ -35,16 +33,16 @@ import org.olat.core.gui.translator.Translator; */ public class VideoTracksTableModel extends DefaultFlexiTableDataModel<TrackTableRow>{ - protected FormUIFactory uifactory = FormUIFactory.getInstance(); - private Translator translator; - public VideoTracksTableModel(FlexiTableColumnModel columnModel, Translator translator) { + private final Locale locale; + + public VideoTracksTableModel(FlexiTableColumnModel columnModel, Locale locale) { super(columnModel); - this.translator = translator; + this.locale = locale; } @Override public VideoTracksTableModel createCopyWithEmptyList() { - return new VideoTracksTableModel(getTableColumnModel(), translator); + return new VideoTracksTableModel(getTableColumnModel(), locale); } @@ -53,7 +51,7 @@ public class VideoTracksTableModel extends DefaultFlexiTableDataModel<TrackTable TrackTableRow track = getObject(row); switch(TrackTableCols.values()[col]) { case file: return track.getTrack(); - case language: return new Locale(track.getLanguage()).getDisplayLanguage(this.translator.getLocale()); + case language: return new Locale(track.getLanguage()).getDisplayLanguage(locale); case delete: return track.getDeleteLink(); default: return ""; } @@ -74,5 +72,4 @@ public class VideoTracksTableModel extends DefaultFlexiTableDataModel<TrackTable return i18nKey; } } - } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/video/ui/_content/video_run.html b/src/main/java/org/olat/modules/video/ui/_content/video_run.html index 89a713b52e87b75354a9d7da57c73ce7b405fe79..9cff2931fdd639559cca3b05896fbc8a0bcacf2d 100644 --- a/src/main/java/org/olat/modules/video/ui/_content/video_run.html +++ b/src/main/java/org/olat/modules/video/ui/_content/video_run.html @@ -1,6 +1,6 @@ <div class="o_video_run o_block_large_bottom clearfix"> <div class="olatFlashMovieViewer"> - <video id="$r.getId("o_vid")" width="$width" height="$height" #if($usePoster) poster="$masterUrl/poster.jpg$!nocache" #end controls #if(!$hasChapters) preload="none" #end oncontextmenu="return false;" #if( $autoplay ) autoplay #end class="o_video"> + <video id="$r.getId("o_vid")" #if($usePoster) poster="$masterUrl/poster.jpg$!nocache" #end controls #if(!$hasChapters) preload="none" #end oncontextmenu="return false;" #if( $autoplay ) autoplay #end class="o_video"> #if ($videos.size() == 0 || $addMaster) <source type="video/mp4" src="$masterUrl/video.mp4" title="$masterTitle"/> #end @@ -80,9 +80,12 @@ ## ## Preselect the preferred source #if($useSourceChooser) - jQuery(jQuery('.mejs__source-chooser-selector input')[$preferredResolution]).prop("checked", true).trigger("click"); + jQuery(jQuery('#' + player.id + '.mejs__source-chooser-selector input')[$preferredResolution]).prop("checked", true).trigger("click"); #end + ## Preset the duration without loading the video + jQuery('#' + player.id + ' .mejs__duration').html('$duration'); + mediaElement.addEventListener('loadedmetadata', function(e) { jQuery('#$r.getId("o_vid")').data('playerloaded', true); }, false); diff --git a/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_de.properties index 3b6c48c2d246712c6c6fc503ccd8df8f09fd5cc3..8079baf957e77c9cd73797684d7a0253a74fa6c5 100644 --- a/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_de.properties @@ -27,7 +27,7 @@ number.transcodings.failed=fehlgeschlagen poster.error.filetype=F\u00FCr Poster Bild werden nur Bilder vom Typ JPG unterst\u00FCtzt. poster.help=Bild vom Typ JPG. Bitte \u00FCberpr\u00FCfen Sie, ob das Poster genau die gleiche Aufl\u00F6sung hat wie das Originalvideo (gleiche H\u00F6he und Breite in Pixel). poster.select=W\u00E4hlen Sie ein Posterbild aus -quality.delete=l\u00F6schen +quality.delete=L\u00F6schen quality.master=Master video quality.resolution.1080=1080p Full-HD quality.resolution.2160=2160p 4K @@ -70,13 +70,14 @@ topnav.video.alt=Bibliothek mit frei verf\u00FCgbaren Lernvideos track.delete=L\u00F6schen track.langs=Sprache track.notrack=F\u00FCr dieses Video wurden noch keine Untertitel hinterlegt. W\u00E4hlen Sie den Button "$\:add.track" um Untertiteldateien hinzuzuf\u00FCgen. -track.table.header.delete=l\u00F6schen +track.table.header.delete=L\u00F6schen track.table.header.file=Datei track.table.header.language=Sprache track.table.label=Untertitel track.upload=Hochladen track.upload.error.nofile=Bitte w\u00E4hlen Sie eine Datei aus. track.upload.error.nolang=Bitte w\u00E4hlen Sie eine Sprache aus dieser Liste aus +track.upload.error.filetype=F\u00FCr Untertitel werden nur Dateien vom Typ WebVTT mit der Endung .srt unterst\u00FCtzt. transcoding.processing=In Bearbeitung transcoding.waiting=In Warteschlange transcoding.error=Stammdatei besch\u00E4digt @@ -109,7 +110,7 @@ video.config.track.error.type=nur *.vtt and *.srt Dateien sind erlaubt video.config.track.table.file=Untertitel Datei video.config.tracks=Verf\u00FCgbare Untertiteldateien video.config.tracks.table.add=hinzuf\u00FCgen -video.config.tracks.table.delete=l\u00F6schen +video.config.tracks.table.delete=L\u00F6schen video.config.tracks.table.lang=Sprache video.config.width=Breite video.contact=Kontakt diff --git a/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_en.properties index c1ce0d95a2568b2ae1d10d5625f46133e7a34cea..9f28e08b33f7db9bba551cd0f916b9033ed9f90c 100644 --- a/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_en.properties @@ -77,6 +77,7 @@ track.table.label=Subtitles track.upload=Upload track.upload.error.nofile=Please select a file. track.upload.error.nolang=Please select a language form the list +track.upload.error.filetype=For subtitles only files of type WebVTT with the ending .srt are supported. transcoding.processing=Processing transcoding.waiting=Queuing transcoding.error=Master file damaged diff --git a/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_fr.properties index 812676935265edbf77fd70877693057b54c80434..3e5abeb9b306c434a481fbcfaebb3e9555061873 100644 --- a/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/video/ui/_i18n/LocalStrings_fr.properties @@ -13,7 +13,7 @@ button.refresh=Rafra\u00EEchir chapter.error.already.exists=Un chapitre avec timecode existe d\u00E9j\u00E0. chapter.error.format=Utilisez s'il-vous -pla\u00EEt le format d'heure suivant HH\:mm\:ss chapter.error.name.already.exists=Un chapitre avec ce nom existe d\u00E9j\u00E0. -chapter.error.notime=Entrez s''il-vous-pla\u00EEt une p\u00E9riode de temps. +chapter.error.notime=Entrez s''il vous pla\u00EEt une p\u00E9riode de temps. chapter.error.notitle=Veuillez indiquer un titre de chapitre. chapter.error.out.of.range=Le timecode de votre chapitre exc\u00E8de la dur\u00E9e de la vid\u00E9o. delete.transcodings=Toutes les vid\u00E9os transcod\u00E9es avec cette r\u00E9solution ont \u00E9t\u00E9 effac\u00E9es. @@ -78,6 +78,7 @@ track.table.label=Sous-titres track.upload=T\u00E9l\u00E9charger track.upload.error.nofile=Choisissez un fichier s'il vous pla\u00EEt. track.upload.error.nolang=Choisissez une langue de la liste +track.upload.error.filetype=Pour les sous-titres, seuls les fichiers au format WebVTT avec le suffixe .srt sont support\u00E9s. transcoding.error=Master endommag\u00E9 transcoding.inefficient=Qualit\u00E9 m\u00E9diocre transcoding.processing=En cours @@ -115,7 +116,7 @@ video.config.tracks.table.lang=Langue video.config.width=Largeur video.contact=Contact video.mime.type=Type de ressource -video.mime.type.error=Utilisez s'il-vous-pla\u00EEt seulement des fichiers ".mov" ou ".mp4". +video.mime.type.error=Utilisez s'il vous pla\u00EEt seulement des fichiers ".mov" ou ".mp4". video.not.replaced=Le fichier vid\u00E9o n'a pas pu \u00EAtre remplac\u00E9. Choisissez un fichier valide. video.replace.desc=Veuillez choisir un fichier vid\u00E9o sur votre ordinateur et cliquer le bouton "Remplacer la vid\u00E9o" pour remplacer l'ancien. video.replace.upload=Fichier vid\u00E9o diff --git a/src/main/java/org/olat/modules/vitero/ViteroModule.java b/src/main/java/org/olat/modules/vitero/ViteroModule.java index 4b53ac19524560281f433526a9d538a55d3734c6..69ae3452f0bbc3f3554781b638a60e0d3e2891ee 100644 --- a/src/main/java/org/olat/modules/vitero/ViteroModule.java +++ b/src/main/java/org/olat/modules/vitero/ViteroModule.java @@ -19,8 +19,11 @@ */ package org.olat.modules.vitero; +import static org.quartz.CronScheduleBuilder.cronSchedule; +import static org.quartz.JobBuilder.newJob; +import static org.quartz.TriggerBuilder.newTrigger; + import java.net.URI; -import java.text.ParseException; import java.util.Calendar; import javax.ws.rs.core.UriBuilder; @@ -32,10 +35,10 @@ import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.modules.vitero.manager.ViteroZombieSlayerJob; -import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.Scheduler; -import org.quartz.SchedulerException; +import org.quartz.Trigger; +import org.quartz.TriggerKey; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -146,20 +149,25 @@ public class ViteroModule extends AbstractSpringModule implements ConfigOnOff { private void initCronJob() { try { - if(scheduler.getTrigger("Vitero_Cleaner_Cron_Trigger", Scheduler.DEFAULT_GROUP) == null) { - JobDetail jobDetail = new JobDetail("Vitero_Cleaner_Cron_Job", Scheduler.DEFAULT_GROUP, ViteroZombieSlayerJob.class); - CronTrigger trigger = new CronTrigger(); + TriggerKey triggerKey = new TriggerKey("Vitero_Cleaner_Cron_Trigger", Scheduler.DEFAULT_GROUP); + if(scheduler.getTrigger(triggerKey) == null) { + + // Create job with cron trigger configuration + JobDetail jobDetail = newJob(ViteroZombieSlayerJob.class) + .withIdentity("Vitero_Cleaner_Cron_Job", Scheduler.DEFAULT_GROUP) + .build(); Calendar cal = Calendar.getInstance(); cal.add(Calendar.SECOND, 30); - trigger.setStartTime(cal.getTime()); - trigger.setName("Vitero_Cleaner_Cron_Trigger"); - trigger.setCronExpression(cronExpression); + Trigger trigger = newTrigger() + .withIdentity("Vitero_Cleaner_Cron_Trigger") + .withSchedule(cronSchedule(cronExpression)) + .startAt(cal.getTime()) + .build(); + scheduler.scheduleJob(jobDetail, trigger); } - } catch (ParseException e) { - log.error("Cannot start the Quartz Job which clean the Vitero rooms", e); - } catch (SchedulerException e) { + } catch (Exception e) { log.error("Cannot start the Quartz Job which clean the Vitero rooms", e); } } diff --git a/src/main/java/org/olat/modules/vitero/_spring/viteroContext.xml b/src/main/java/org/olat/modules/vitero/_spring/viteroContext.xml deleted file mode 100644 index e770b7fd4ddf0a588b18b62877bee29172af41d9..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/modules/vitero/_spring/viteroContext.xml +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context.xsd"> - - <context:component-scan base-package="org.olat.modules.vitero" /> - - <!-- vitero admin. panel --> - <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> - <property name="order" value="8228" /> - <property name="actionController"> - <bean class="org.olat.core.gui.control.creator.FactoryControllerCreator" scope="prototype"> - <property name="factoryName" value="org.olat.modules.vitero.ViteroUIFactory"/> - <property name="factoryMethod" value="createViteroAdminController"/> - </bean> - </property> - <property name="navigationKey" value="vitero" /> - <property name="parentTreeNodeIdentifier" value="externalToolsParent" /> - <property name="i18nActionKey" value="admin.menu.title"/> - <property name="i18nDescriptionKey" value="admin.menu.title.alt"/> - <property name="translationPackage" value="org.olat.modules.vitero.ui"/> - <property name="extensionPoints"> - <list> - <value>org.olat.admin.SystemAdminMainController</value> - </list> - </property> - - </bean> -</beans> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/ExternalFeedFetcher.java b/src/main/java/org/olat/modules/webFeed/ExternalFeedFetcher.java index a4683d407b6768cd094b06be1d5546799f5b4d7f..ccf1caa477ad6e52bc0d31ca9a18d3b61632af0f 100644 --- a/src/main/java/org/olat/modules/webFeed/ExternalFeedFetcher.java +++ b/src/main/java/org/olat/modules/webFeed/ExternalFeedFetcher.java @@ -21,26 +21,28 @@ package org.olat.modules.webFeed; import java.util.List; +import org.olat.modules.webFeed.manager.ValidatedURL; + /** - * An ExternalFeedFetcher allows to retrieve feeds and items from + * An ExternalFeedFetcher allows to retrieve feeds and items from * external web sites. It is responsible for the http communication * and the convertation to the internal feed model. - * + * * Initial date: 12.05.2017<br> * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com * */ public interface ExternalFeedFetcher { - + /** * Fetches an feed from an external web sites and updates the feed with * the current attributes - * + * * @param feed * @return the updated feed */ public Feed fetchFeed(Feed feed); - + /** * Fetches the items of a feed and converts it to the internal feed model. * @param feed @@ -48,4 +50,14 @@ public interface ExternalFeedFetcher { */ public List<Item> fetchItems(Feed feed); + /** + * Validates if it is a valid feed URL and if the feed can be fetch from + * this URL. + * + * @param url + * @param enclosuresExpected + * Indicates whether enclosures are expected e.g. in a podcast. + */ + public ValidatedURL validateFeedUrl(String url, boolean enclosuresExpected); + } diff --git a/src/main/java/org/olat/modules/webFeed/FeedChangedEvent.java b/src/main/java/org/olat/modules/webFeed/FeedChangedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..3f872d0aea85dacb9e02ef5ad9ee89dc6cb9a61d --- /dev/null +++ b/src/main/java/org/olat/modules/webFeed/FeedChangedEvent.java @@ -0,0 +1,45 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.webFeed; + +import org.olat.core.util.event.MultiUserEvent; + +/** + * + * Initial date: 14.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class FeedChangedEvent extends MultiUserEvent { + + private static final long serialVersionUID = -1296929662755981989L; + + private Long feedKey; + + public FeedChangedEvent(Long feedKey) { + super("feed-changed-event"); + this.feedKey = feedKey; + } + + public Long getFeedKey() { + return feedKey; + } + +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/RSSFeed.java b/src/main/java/org/olat/modules/webFeed/RSSFeed.java index b00c5d0461a8dcd0e03fc67161e6c012663758b0..573439f016b06ca6a105b26f5e47feab27a24aa7 100644 --- a/src/main/java/org/olat/modules/webFeed/RSSFeed.java +++ b/src/main/java/org/olat/modules/webFeed/RSSFeed.java @@ -66,6 +66,7 @@ public class RSSFeed extends SyndFeedImpl { // According to the rss specification, the feed channel description is not // (explicitly) allowed to contain html tags. String strippedDescription = FilterFactory.getHtmlTagsFilter().filter(feed.getDescription()); + strippedDescription = strippedDescription == null? "": strippedDescription; // TODO: remove when filter does it strippedDescription = strippedDescription.replaceAll(" ", " "); setDescription(strippedDescription); diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedFileStorge.java b/src/main/java/org/olat/modules/webFeed/manager/FeedFileStorge.java index 58e6188e3398f0b6cca7938f0cf7474bb1065e4d..03045a83fbc31594c023293f18a98da1dce6489a 100644 --- a/src/main/java/org/olat/modules/webFeed/manager/FeedFileStorge.java +++ b/src/main/java/org/olat/modules/webFeed/manager/FeedFileStorge.java @@ -27,6 +27,8 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import org.olat.core.commons.modules.bc.meta.MetaInfo; +import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl; import org.olat.core.commons.services.image.ImageService; import org.olat.core.gui.components.form.flexible.elements.FileElement; @@ -40,6 +42,7 @@ import org.olat.core.util.vfs.LocalFileImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.VFSManager; import org.olat.core.util.vfs.filters.VFSItemMetaFilter; import org.olat.core.util.xml.XStreamHelper; import org.olat.fileresource.FileResourceManager; @@ -57,7 +60,7 @@ import com.thoughtworks.xstream.XStream; /** * This class helps to store data like images and videos in the file systems * and handles the storage of Feeds and Items as XML as well. - * + * * The structure of the files of a feed is: * resource * feed @@ -69,30 +72,30 @@ import com.thoughtworks.xstream.XStream; * ________image.jpg * ____/item * ______... - * + * * Initial date: 22.05.2017<br> * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com * */ @Service public class FeedFileStorge { - + private static final OLog log = Tracing.createLoggerFor(FeedFileStorge.class); - + private static final String MEDIA_DIR = "media"; private static final String ITEMS_DIR = "items"; public static final String FEED_FILE_NAME = "feed.xml"; public static final String ITEM_FILE_NAME = "item.xml"; - + // same as in repository metadata image upload private static final int PICTUREWIDTH = 570; - + private FileResourceManager fileResourceManager; private final XStream xstream; - + @Autowired private ImageService imageHelper; - + public FeedFileStorge() { fileResourceManager = FileResourceManager.getInstance(); xstream = new XStream(); @@ -101,6 +104,7 @@ public class FeedFileStorge { xstream.omitField(FeedImpl.class, "id"); xstream.omitField(FeedImpl.class, "itemIds"); xstream.omitField(FeedImpl.class, "key"); + xstream.omitField(FeedImpl.class, "wrappers"); xstream.alias("item", ItemImpl.class); xstream.omitField(ItemImpl.class, "key"); xstream.omitField(ItemImpl.class, "feed"); @@ -109,18 +113,18 @@ public class FeedFileStorge { /** * Get the resource (root) container of the feed. - * + * * @param ores * @return */ public OlatRootFolderImpl getResourceContainer(OLATResourceable ores) { return fileResourceManager.getFileResourceRootImpl(ores); } - + /** * Get the top most folder of a feed. * The container is created if it does not exist. - * + * * @param ores * @return the container or null */ @@ -135,20 +139,20 @@ public class FeedFileStorge { feedContainer = resourceDir.createChildContainer(feedContainerName); } } - + return feedContainer; } - + /** * Get the media container of a feed. * The container is created if it does not exist. - * + * * @param ores * @return the container or null */ public VFSContainer getOrCreateFeedMediaContainer(OLATResourceable ores) { VFSContainer mediaContainer = null; - + if (ores != null) { VFSContainer feedContainer = getOrCreateFeedContainer(ores); mediaContainer = (VFSContainer) feedContainer.resolve(MEDIA_DIR); @@ -156,20 +160,20 @@ public class FeedFileStorge { mediaContainer = feedContainer.createChildContainer(MEDIA_DIR); } } - + return mediaContainer; } - + /** * Get the items container of a feed. * The container is created if it does not exist. - * + * * @param ores * @return the container or null */ public VFSContainer getOrCreateFeedItemsContainer(OLATResourceable ores) { VFSContainer itemsContainer = null; - + if (ores != null) { VFSContainer feedContainer = getOrCreateFeedContainer(ores); itemsContainer = (VFSContainer) feedContainer.resolve(ITEMS_DIR); @@ -177,32 +181,32 @@ public class FeedFileStorge { itemsContainer = feedContainer.createChildContainer(ITEMS_DIR); } } - + return itemsContainer; } - + /** * Get the container of an item. * The container is created if it does not exist. - * + * * @param ores * @return the container or null */ public VFSContainer getOrCreateItemContainer(Item item) { VFSContainer itemContainer = null; - + if (item != null) { Feed feed = item.getFeed(); String guid = item.getGuid(); itemContainer = getOrCreateItemContainer(feed, guid); } - + return itemContainer; } - + /** * Delete the container of the item. - * + * * @param item */ public void deleteItemContainer(Item item) { @@ -211,8 +215,8 @@ public class FeedFileStorge { itemContainer.delete(); } } - - + + /** * Get the container for the guid of an item. * The container is created if it does not exist. @@ -223,7 +227,7 @@ public class FeedFileStorge { */ public VFSContainer getOrCreateItemContainer(Feed feed, String guid) { VFSContainer itemContainer = null; - + if (feed != null && StringHelper.containsNonWhitespace(guid)) { VFSContainer feedContainer = getOrCreateFeedItemsContainer(feed); itemContainer = (VFSContainer) feedContainer.resolve(guid); @@ -231,20 +235,20 @@ public class FeedFileStorge { itemContainer = feedContainer.createChildContainer(guid); } } - + return itemContainer; } - + /** * Get the media container of an item. * The container is created if it does not exist. - * + * * @param ores * @return the container or null */ public VFSContainer getOrCreateItemMediaContainer(Item item) { VFSContainer mediaContainer = null; - + if (item != null) { VFSContainer itemContainer = getOrCreateItemContainer(item); if (itemContainer != null) { @@ -254,13 +258,13 @@ public class FeedFileStorge { } } } - + return mediaContainer; } - + /** * Save the feed as XML into the feed container. - * + * * @param feed */ public void saveFeedAsXML(Feed feed) { @@ -273,40 +277,62 @@ public class FeedFileStorge { XStreamHelper.writeObject(xstream, leaf, feed); } } - + /** * Load the XML file of the feed from the feed container and convert it to * a feed. - * + * * @param ores * @return the feed or null */ public Feed loadFeedFromXML(OLATResourceable ores) { Feed feed = null; - + VFSContainer feedContainer = getOrCreateFeedContainer(ores); if (feedContainer != null) { VFSLeaf leaf = (VFSLeaf) feedContainer.resolve(FEED_FILE_NAME); if (leaf != null) { feed = (FeedImpl) XStreamHelper.readObject(xstream, leaf.getInputStream()); + shorteningFeedToLengthOfDbAttribues(feed); } } else { log.warn("Feed XML-File could not be found on file system. Feed container: " + feedContainer); } - + return feed; } - + + private void shorteningFeedToLengthOfDbAttribues(Feed feed) { + if (feed.getAuthor() != null && feed.getAuthor().length() > 255) { + feed.setAuthor(feed.getAuthor().substring(0, 255)); + } + if (feed.getTitle() != null && feed.getTitle().length() > 1024) { + feed.setTitle(feed.getTitle().substring(0, 1024)); + } + if (feed.getDescription() != null && feed.getDescription().length() > 4000) { + feed.setDescription(feed.getDescription().substring(0, 4000)); + } + if (feed.getImageName() != null && feed.getImageName().length() > 1024) { + feed.setImageName(null); + } + if (feed.getExternalFeedUrl() != null && feed.getExternalFeedUrl().length() > 4000) { + feed.setExternalFeedUrl(null); + } + if (feed.getExternalImageURL() != null && feed.getExternalImageURL().length() > 4000) { + feed.setExternalImageURL(null); + } + } + /** * Load the XML file of the feed from a Path and convert it to * a feed. - * + * * @param feedDir the directory which contains the feed file * @return the feed or null */ public Feed loadFeedFromXML(Path feedDir) { Feed feed = null; - + if (feedDir != null) { Path feedPath = feedDir.resolve(FeedFileStorge.FEED_FILE_NAME); try (InputStream in = Files.newInputStream(feedPath)) { @@ -315,13 +341,13 @@ public class FeedFileStorge { log.warn("Feed XML-File could not be found on file system. Feed path: " + feedPath, e); } } - + return feed; } - + /** * Delete the XML file of the feed from the feed container - * + * * @param feed */ public void deleteFeedXML(Feed feed) { @@ -333,10 +359,10 @@ public class FeedFileStorge { } } } - + /** * Save the item as XML into the item container. - * + * * @param item */ public void saveItemAsXML(Item item) { @@ -349,18 +375,18 @@ public class FeedFileStorge { XStreamHelper.writeObject(xstream, leaf, item); } } - + /** * Load the XML file of the item from the item container and convert it to * an item. - * + * * @param feed * @param guid * @return */ Item loadItemFromXML(VFSContainer itemContainer) { Item item = null; - + if (itemContainer != null) { VFSLeaf leaf = (VFSLeaf) itemContainer.resolve(ITEM_FILE_NAME); if (leaf != null) { @@ -370,23 +396,23 @@ public class FeedFileStorge { log.warn("Item XML-File could not be read. Item container: " + leaf); } } else { - log.error("Item XML-File could not be found on file system." + log.warn("Item XML-File could not be found on file system." + " Item container: " + itemContainer.getName()); } } - + return item; } - + /** * Load the XML file of all items of a feed and convert them to items. - * + * * @param ores * @return */ public List<Item> loadItemsFromXML(OLATResourceable ores) { List<Item> items = new ArrayList<>(); - + VFSContainer itemsContainer = getOrCreateFeedItemsContainer(ores); if (itemsContainer != null) { List<VFSItem> itemContainers = itemsContainer.getItems(new VFSItemMetaFilter()); @@ -394,18 +420,31 @@ public class FeedFileStorge { for (VFSItem itemContainer : itemContainers) { Item item = loadItemFromXML((VFSContainer) itemContainer); if (item != null) { + shorteningItemToLengthOfDbAttributes(item); items.add(item); } } } } - + return items; } - + + private void shorteningItemToLengthOfDbAttributes(Item item) { + if (item.getAuthor() != null && item.getAuthor().length() > 255) { + item.setAuthor(item.getAuthor().substring(0, 255)); + } + if (item.getExternalLink() != null && item.getExternalLink().length() > 4000) { + item.setExternalLink(null); + } + if (item.getTitle() != null && item.getTitle().length() > 1024) { + item.setTitle(item.getTitle().substring(0, 1024)); + } + } + /** * Delete the XML file of the item from the item container - * + * * @param item */ public void deleteItemXML(Item item) { @@ -417,20 +456,19 @@ public class FeedFileStorge { } } } - + /** - * Save the the media element of the feed. If allready a file is in - * the media container, that file is previously deleted. - * If the media is null, this method will do nothing. It does not delete - * the existing media. - * + * Save the media element of the feed. If already a file is in the media + * container, that file is previously deleted. If the media is null, this + * method will do nothing. It does not delete the existing media. + * * @param feed * @param media * @return the file name which is save for the file system */ public String saveFeedMedia(Feed feed, FileElement media) { String saveFileName = null; - + if (media != null) { VFSContainer feedMediaContainer = getOrCreateFeedMediaContainer(feed); if (feedMediaContainer != null) { @@ -446,32 +484,55 @@ public class FeedFileStorge { imageLeaf.rename(saveFileName); } } - + + return saveFileName; + } + + /** + * Save a file as the media element of the feed. If already a file is in + * the media container, that file is previously deleted. + * + * @param feed + * @param media + * @return the file name which is save for the file system + */ + public String saveFeedMedia(Feed feed, VFSLeaf media) { + String saveFileName = null; + + VFSContainer feedMediaContainer = getOrCreateFeedMediaContainer(feed); + if (feedMediaContainer != null) { + deleteFeedMedia(feed); + if (media != null) { + VFSManager.copyContent(media, feedMediaContainer.createChildLeaf(media.getName())); + saveFileName = media.getName(); + } + } + return saveFileName; } - + /** * Load the the media element of the feed. - * + * * @param feed * @return the media alement or null */ public VFSLeaf loadFeedMedia(Feed feed) { VFSLeaf mediaFile = null; - + if (feed != null) { String feedImage = feed.getImageName(); if (feedImage != null) { mediaFile = (VFSLeaf) getOrCreateFeedMediaContainer(feed).resolve(feedImage); } } - + return mediaFile; } - + /** * Delete the the media of the feed. - * + * * @param feed */ public void deleteFeedMedia(Feed feed) { @@ -479,25 +540,31 @@ public class FeedFileStorge { if (feedMediaContainer != null) { for (VFSItem fileItem : feedMediaContainer.getItems()) { if (!fileItem.getName().startsWith(".")) { + if(fileItem instanceof MetaTagged) { + MetaInfo info = ((MetaTagged)fileItem).getMetaInfo(); + if(info != null) { + info.clearThumbnails(); + } + } fileItem.delete(); } } } } - + /** * Save a file (video/audio/image) to the media container of the item. * <p> * If the media is null, this method will do nothing. It does not delete the * existing media files. - * + * * @param item * @param media * @return the file name which is save for the file system */ public String saveItemMedia(Item item, FileElement media) { String saveFileName = null; - + if (media != null) { VFSContainer itemMediaContainer = getOrCreateItemMediaContainer(item); if (itemMediaContainer != null) { @@ -505,19 +572,19 @@ public class FeedFileStorge { saveFileName = media.getUploadFileName(); } } - + return saveFileName; } - + /** * Load the media file of the item. - * + * * @param item * @return */ public File loadItemMedia(Item item) { File file = null; - + Enclosure enclosure = item.getEnclosure(); VFSContainer mediaDir = getOrCreateItemMediaContainer(item); if (mediaDir != null && enclosure != null) { @@ -526,13 +593,13 @@ public class FeedFileStorge { file = ((LocalFileImpl) mediaFile).getBasefile(); } } - + return file; } - + /** * Delete a file from the media container of an item. - * + * * @param item * @param fileName */ diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedManager.java b/src/main/java/org/olat/modules/webFeed/manager/FeedManager.java index 48363e8976fdca3b2ba2de7e1d193679edf2cf54..78b13e236b551cd8af82091fe24f485806fc5c48 100644 --- a/src/main/java/org/olat/modules/webFeed/manager/FeedManager.java +++ b/src/main/java/org/olat/modules/webFeed/manager/FeedManager.java @@ -36,15 +36,16 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.webFeed.Feed; import org.olat.modules.webFeed.FeedSecurityCallback; import org.olat.modules.webFeed.Item; +import org.olat.repository.RepositoryEntry; import org.olat.resource.OLATResource; /** * The <code>FeedManager</code> singleton is responsible for dealing with feed * resources. - * + * * <P> * Initial Date: Feb 11, 2009 <br> - * + * * @author gwassmann */ public abstract class FeedManager { @@ -62,7 +63,7 @@ public abstract class FeedManager { /** * Use this method instead of any constructor to get the singelton object. - * + * * @return INSTANCE */ public static final FeedManager getInstance() { @@ -70,15 +71,15 @@ public abstract class FeedManager { } /** - * Creates a blank OLAT podcast resource - * + * Creates a blank OLAT podcast resource + * * @return The resource */ public abstract OLATResourceable createPodcastResource(); - + /** * Check if a feed has items - * + * * @param feed * @return */ @@ -86,29 +87,47 @@ public abstract class FeedManager { /** * Creates a blank OLAT blog resource - * + * * @return The resource */ public abstract OLATResourceable createBlogResource(); /** * Deletes a feed. - * + * * @param feed */ public abstract void deleteFeed(OLATResourceable feed); /** * Copies a given feed resourceable - * + * * @param feed */ public abstract boolean copy(OLATResource source, OLATResource target); + /** + * Enrich the feed with the properties in the RepositoryEntry. + * + * @param feed + * @param entry + * @return the same Feed object with actualized attributes + */ + public abstract Feed enrichFeedByRepositoryEntry(Feed feed, RepositoryEntry entry); + + /** + * Update the feed with the properties in the RepositoryEntry and save it + * in the database. + * + * @param entry + * @return a new updated Feed object + */ + public abstract Feed updateFeedWithRepositoryEntry(RepositoryEntry entry); + /** * Create the given Item and saves the appropriate file (podcast, video etc.) * on the file system. - * + * * @param feed the item will be added to this feed * @param item the item to add * @param file the file of the item @@ -116,21 +135,21 @@ public abstract class FeedManager { */ public abstract Feed createItem(Feed feed, Item item, FileElement file); - + /** * Removes the given Item from the feed and delete the item from the * database. Additionally the content on the file system (podcast etc.) * and the comments and the ratings of the item are deleted. - * + * * @param item the item to remove * @return the feed without the removed item */ public abstract Feed deleteItem(Item item); - + /** * Update the Item in the database and save the file element in the file * system. - * + * * @param modifiedItem * @param file * @return the updated feed @@ -140,7 +159,7 @@ public abstract class FeedManager { /** * Update the feed source mode. Additionally it deleted all Items of the Feed * if the mode of the Feed changes. - * + * * @param external true: set to be an external feed; false: this is an * internal feed; null: undefined * @param feed @@ -150,79 +169,98 @@ public abstract class FeedManager { /** * Update the feed from the given feed object - * + * * @param feed * @return */ public abstract Feed updateFeed(Feed feed); - + + /** + * Update the external URL of the feed, delete all items of the feed and + * download the items of the new external feed URL. + * + * @param feed + * @param externalFeedUrl + * @return + */ + public abstract Feed updateExternalFeedUrl(Feed feed, String externalFeedUrl); + /** * Load the Item with the given key from the database or NULL if no such * item exists. - * + * * @param key the key of the Item * @return the loaded Item or NULL */ public abstract Item loadItem(Long key); - + /** * Load the Item with the given guid from the database or NULL if no such * item exists. * @param feedKey the key of the feed * @param guid the guid of the Item - * + * * @return the loaded Item or NULL */ public abstract Item loadItemByGuid(Long feedKey, String guid); - + + /** + * Load the Item with the given guid from the database or NULL if no such + * item exists or more then one items with the same guid exist. + * + * @param itemId + * @return + */ + public abstract Item loadItemByGuid(String itemId); + /** * Load all items of the feed (from file system or the external feed) - * + * * @param feed */ public abstract List<Item> loadItems(Feed feed); - + /** * Load the guid of all Items of the feed - * + * * @param feed */ public abstract List<String> loadItemsGuid(Feed feed); - + /** * Load all published Items - * + * * @param feed */ public abstract List<Item> loadPublishedItems(Feed feed); - + /** * Load all Items of a feed and filter them in relation to the identity rights. - * + * * @param feed * @param callback * @param identity * @return */ public abstract List<Item> loadFilteredAndSortedItems(Feed feed, FeedSecurityCallback callback, Identity identity); - + /** * Returns the feed with the provided id or null if not found. - * + * * @param feed The feed to be re-read * @return The newly read feed */ public abstract Feed loadFeed(OLATResourceable feed); - + /** * Returns the feed from the XML file inside the directory or null if not * found. - * + * * @param feedDir the directory which contains the feed file * @return the feed or null */ public abstract Feed loadFeedFromXML(Path feedDir); - + /** * In the early days all information about a feed where stored in XML files. * This method migrates that old feeds from the XML files to the database. @@ -231,7 +269,7 @@ public abstract class FeedManager { * the end the XML files are deleted. If the Feed is imported from an other * system the identity keys should be deleted because they do not * correspondent with the keys in the actual system. - * + * * @param ores * @param removeIdentityKeys * If true, the identity keys of the author and the modifier are @@ -241,7 +279,7 @@ public abstract class FeedManager { /** * Returns the media file of the item - * + * * @param id * @param resourceTypeName * @param itemId @@ -249,10 +287,10 @@ public abstract class FeedManager { * @return The media resource (audio or video file of the feed item) */ public abstract MediaResource createItemMediaFile(OLATResourceable feed, String itemId, String fileName); - + /** * Returns the media file of the feed - * + * * @param id * @param resourceTypeName * @param fileName @@ -263,7 +301,7 @@ public abstract class FeedManager { /** * Returns the base URI of the feed including user identity key and token if * necessary. - * + * * @param feed * @param idKey * @return The base URI of the (RSS) feed @@ -272,7 +310,7 @@ public abstract class FeedManager { /** * Creates the RSS feed resource. - * + * * @param feedId * @param type The resource type name * @param identityKey @@ -282,7 +320,7 @@ public abstract class FeedManager { /** * Creates and returns a zip-file media resource of the given feed resource - * + * * @param resource * @return A zip-file media resource */ @@ -290,7 +328,7 @@ public abstract class FeedManager { /** * Create and returns a zip-file as VFSLeaf of the given feed resourue - * + * * @param ores the resource * @return The VFSLeaf */ @@ -298,40 +336,40 @@ public abstract class FeedManager { /** * Returns the container of the item which belongs to the feed - * + * * @param item * @return The container of the item */ public abstract VFSContainer getItemContainer(Item item); - + /** * Save the item in an XML file in the item container. - * + * * @param item */ public abstract void saveItemAsXML(Item item); - + /** * Delete the item XML file from the item container. - * + * * @param item */ public abstract void deleteItemXML(Item item); /** * Returns the File of the item's enclosure if it exists or null - * + * * @param item * @return The enclosure media file */ public abstract File loadItemEnclosureFile(Item item); - + public abstract Quota getQuota(OLATResourceable feed); /** * Validates a feed url. - * + * * @param url * @return valid url (rss, atom etc.) */ @@ -339,14 +377,14 @@ public abstract class FeedManager { /** * Releases a lock - * + * * @param lock The lock to be released */ public abstract void releaseLock(LockResult lock); /** * Acquires the lock on the specified feed - * + * * @param feed The feed to be locked * @param identity The person who is locking the resource * @return The lock result @@ -355,7 +393,7 @@ public abstract class FeedManager { /** * Acquires the lock of an item - * + * * @param feed The item's feed * @param item The item to be locked * @param identity The person who is locking the resource @@ -370,13 +408,13 @@ public abstract class FeedManager { public boolean isLocked(OLATResourceable feed) { return CoordinatorManager.getInstance().getCoordinator().getLocker().isLocked(feed, null); } - + /** * There are different kinds of web feeds, e.g. podcasts, blogs etc. This * method returns the kind of a resourceType. In contrast to the resource type * name, the kind is a single noun designating the feed. It might be used to * get a comprehensible expression for folder or file names. - * + * * @param ores * @return The kind of the resource type */ @@ -385,16 +423,16 @@ public abstract class FeedManager { /** * Replace the image of the feed. * If the image is null, the existing image is kept. - * + * * @param feed * @param image * @return */ public abstract Feed replaceFeedImage(Feed feed, FileElement image); - + /** * Delete the feed image. - * + * * @param feed * @return */ diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java b/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java index 0fec8bd35daaabb30c77b2f63d56697ce38e018d..b08e864b0f5a11936589dbc581f6eb6d97eb62d1 100644 --- a/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java +++ b/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java @@ -20,10 +20,6 @@ package org.olat.modules.webFeed.manager; import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; import java.nio.file.Path; import java.util.ArrayList; import java.util.Calendar; @@ -37,6 +33,7 @@ import org.olat.basesecurity.BaseSecurityManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl; +import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.commons.services.commentAndRating.CommentAndRatingService; import org.olat.core.commons.services.image.Size; @@ -85,29 +82,24 @@ import org.olat.resource.OLATResourceManager; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; -import com.rometools.rome.feed.synd.SyndEntry; import com.rometools.rome.feed.synd.SyndFeed; -import com.rometools.rome.io.FeedException; -import com.rometools.rome.io.ParsingFeedException; -import com.rometools.rome.io.SyndFeedInput; -import com.rometools.rome.io.XmlReader; /** * This is the actual feed manager implementation. It handles all operations on * the various feeds and items. - * + * * <P> * Initial Date: Feb 17, 2009 <br> - * + * * @author Gregor Wassmann */ public class FeedManagerImpl extends FeedManager { - + private static final OLog log = Tracing.createLoggerFor(FeedManagerImpl.class); - + // 10 minutes private static final int EXTERNAL_FEED_ACTUALIZATION_MILLIS = 10*60*1000; - + public static final String KIND_PODCAST = "podcast"; public static final String KIND_BLOG = "blog"; @@ -115,7 +107,9 @@ public class FeedManagerImpl extends FeedManager { private Coordinator coordinator; private OLATResourceManager resourceManager; private FileResourceManager fileResourceManager; - + + @Autowired + private DB dbInstance; @Autowired private FeedDAO feedDAO; @Autowired @@ -140,9 +134,9 @@ public class FeedManagerImpl extends FeedManager { INSTANCE = this; this.coordinator = coordinatorManager.getCoordinator(); } - + FeedManagerImpl() { - + } public void setRepositoryManager(RepositoryManager repositoryManager) { @@ -164,7 +158,7 @@ public class FeedManagerImpl extends FeedManager { /** * This method creates an OLATResource in the database and * initializes the container on the file system. - * + * * @param feedResource * @return The feed resourcable */ @@ -172,28 +166,26 @@ public class FeedManagerImpl extends FeedManager { // save the resource in the database OLATResource ores = resourceManager.createOLATResourceInstance(feedResource); resourceManager.saveOLATResource(ores); - + // create a feed and save it in the database feedDAO.createFeedForResourcable(feedResource); - + // Create a resource folder for storing the images feedFileStorage.getOrCreateFeedContainer(feedResource); - + return feedResource; } - + /** * Load the Feed from the database. - * + * * Additionally this method triggers the actualization of the external feed - * and his items. The download starts is the last modified time is + * and his items. The download starts is the last modified time is */ @Override public Feed loadFeed(OLATResourceable ores) { Feed feed = feedDAO.loadFeed(ores); - - feed = enrichFeedByRepositoryEntryInfromation(feed); - + // Update the external feed and the items if (feed != null && feed.isExternal() && StringHelper.containsNonWhitespace(feed.getExternalFeedUrl())) { Calendar cal = Calendar.getInstance(); @@ -203,19 +195,23 @@ public class FeedManagerImpl extends FeedManager { Date now = new Date(); if (now.after(nextUpdateDate) || loadItems(feed).isEmpty()) { // time to update or first load after creation of the feed - saveExternalItems(feed); - saveExternalFeed(feed); - notificationsManager.markPublisherNews(ores.getResourceableTypeName(), - feed.getResourceableId().toString(), null, false); + saveExternalFeedIAndtems(feed); } feed.setLastModified(new Date()); feedDAO.updateFeed(feed); } - + return feed; } + private void saveExternalFeedIAndtems(Feed feed) { + saveExternalItems(feed); + saveExternalFeed(feed); + notificationsManager.markPublisherNews(feed.getResourceableTypeName(), + feed.getResourceableId().toString(), null, false); + } + @Override public boolean hasItems(Feed feed) { return itemDAO.hasItems(feed); @@ -223,34 +219,55 @@ public class FeedManagerImpl extends FeedManager { @Override public Feed updateFeed(Feed feed) { - enrichRepositoryEntryByFeedInformation(feed); return feedDAO.updateFeed(feed); } @Override public Feed updateFeedMode(Boolean external, Feed feed) { if (feed == null) return null; - + // first, reload actual version of the feed Feed reloaded = feedDAO.loadFeed(feed); if (reloaded == null) return null; - + // delete all items if the mode changes if (external == null - || feed.isUndefined() + || feed.isUndefined() || external.booleanValue() != feed.getExternal().booleanValue()) { itemDAO.removeItems(feed); reloaded.setExternalImageURL(null); } - + reloaded.setExternal(external); return updateFeed(reloaded); } + @Override + public Feed updateExternalFeedUrl(Feed feed, String externalFeedUrl) { + Feed reloaded = feedDAO.loadFeed(feed); + if (reloaded == null) return null; + if (!feed.isExternal()) return feed; + + if (!StringHelper.isSame(reloaded.getExternalFeedUrl(), externalFeedUrl)) { + itemDAO.removeItems(feed); + } + if (StringHelper.containsNonWhitespace(externalFeedUrl)) { + reloaded.setExternalFeedUrl(externalFeedUrl); + saveExternalFeedIAndtems(feed); + } else { + reloaded.setExternal(null); + reloaded.setExternalFeedUrl(null); + } + reloaded.setLastModified(new Date()); + Feed updated = feedDAO.updateFeed(reloaded); + + return updated; + } + @Override public Feed replaceFeedImage(Feed feed, FileElement image) { String saveFileName = null; - + if (image != null) { saveFileName = feedFileStorage.saveFeedMedia(feed, image); feed = feedDAO.loadFeed(feed.getKey()); @@ -259,21 +276,21 @@ public class FeedManagerImpl extends FeedManager { feed = feedDAO.updateFeed(feed); } } - + return feed; } - + @Override public Feed deleteFeedImage(Feed feed) { String saveFileName = null; - + feedFileStorage.deleteFeedMedia(feed); Feed reloadedFeed = feedDAO.loadFeed(feed.getKey()); if (reloadedFeed != null) { reloadedFeed.setImageName(saveFileName); reloadedFeed = feedDAO.updateFeed(reloadedFeed); } - + return reloadedFeed; } @@ -281,11 +298,11 @@ public class FeedManagerImpl extends FeedManager { public void deleteFeed(OLATResourceable ores) { // delete the container on the file system fileResourceManager.deleteFileResource(ores); - + // delete comments and ratings CommentAndRatingService commentAndRatingService = CoreSpringFactory.getImpl(CommentAndRatingService.class); commentAndRatingService.deleteAllIgnoringSubPath(ores); - + // delete the feed and all items from the database Feed feed = feedDAO.loadFeed(ores); itemDAO.removeItems(feed); @@ -293,30 +310,30 @@ public class FeedManagerImpl extends FeedManager { resourceManager.deleteOLATResourceable(ores); feed = null; } - + @Override public Feed createItem(Feed feed, Item item, FileElement file) { - Feed reloadedFeed = null; - - if (feed != null && feed.isInternal()) { - - // Set the current date as published date. - if (item.getPublishDate() == null) { - item.setPublishDate(new Date()); - } - - // Save the Enclosure - Enclosure enclosure = replaceEnclosure(item, file); - item.setEnclosure(enclosure); - - // Save the Item - itemDAO.createItem(feed, item); - - // Set the modification date of the feed - reloadedFeed = feedDAO.loadFeed(feed.getKey()); - reloadedFeed.setLastModified(new Date()); - reloadedFeed = feedDAO.updateFeed(reloadedFeed); + if (feed == null || item == null || !feed.isInternal()) return null; + + // Set the current date as published date. + if (item.getPublishDate() == null) { + item.setPublishDate(new Date()); } + + // Save the Enclosure + Enclosure enclosure = replaceEnclosure(item, file); + item.setEnclosure(enclosure); + + // Save the Item + itemDAO.createItem(feed, item); + + // Set the modification date of the feed + Feed reloadedFeed = feedDAO.loadFeed(feed.getKey()); + reloadedFeed.setLastModified(new Date()); + reloadedFeed = feedDAO.updateFeed(reloadedFeed); + + markPublisherNews(reloadedFeed); + return reloadedFeed; } @@ -325,22 +342,27 @@ public class FeedManagerImpl extends FeedManager { public Item loadItem(Long key) { return itemDAO.loadItem(key); } - + @Override public Item loadItemByGuid(Long feedKey, String guid) { return itemDAO.loadItemByGuid(feedKey, guid); } + @Override + public Item loadItemByGuid(String guid) { + return itemDAO.loadItemByGuid(guid); + } + @Override public List<Item> loadItems(Feed feed) { return itemDAO.loadItems(feed); } - + @Override public List<String> loadItemsGuid(Feed feed) { return itemDAO.loadItemsGuid(feed); } - + @Override public List<Item> loadPublishedItems(Feed feed) { return itemDAO.loadPublishedItems(feed); @@ -381,28 +403,31 @@ public class FeedManagerImpl extends FeedManager { @Override public Item updateItem(Item item, FileElement file) { + if (item == null) return null; + Item updatedItem = itemDAO.loadItem(item.getKey()); - + if (updatedItem != null) { Enclosure enclosure = replaceEnclosure(item, file); item.setEnclosure(enclosure); updatedItem = itemDAO.updateItem(item); + markPublisherNews(updatedItem.getFeed()); } - + return updatedItem; } /** * Save or delete the media file to the file system and get the appropriate * Enclosure. - * + * * @param item * @param file * @return */ private Enclosure replaceEnclosure(Item item, FileElement file) { Enclosure enclosure = item.getEnclosure(); - + if (file != null) { if (file.isUploadSuccess()) { if (enclosure != null && enclosure.getFileName() != null) { @@ -422,7 +447,7 @@ public class FeedManagerImpl extends FeedManager { enclosure = null; } } - + return enclosure; } @@ -430,21 +455,21 @@ public class FeedManagerImpl extends FeedManager { @Override public Feed deleteItem(Item item) { Feed feed = item.getFeed(); - + // delete the item from the database itemDAO.removeItem(item); - + // delete the item container from the file system feedFileStorage.deleteItemContainer(item); - + // delete comments and ratings CommentAndRatingService commentAndRatingService = CoreSpringFactory .getImpl(CommentAndRatingService.class); commentAndRatingService.deleteAll(feed, item.getGuid()); - + // reload the Feed Feed reloadedFeed = feedDAO.loadFeed(feed.getKey()); - + // If the last item has been removed, set the feed to undefined. // The user can then newly decide whether to add items manually // or from an external source. @@ -454,18 +479,18 @@ public class FeedManagerImpl extends FeedManager { } reloadedFeed.setLastModified(new Date()); reloadedFeed = feedDAO.updateFeed(reloadedFeed); - + return reloadedFeed; } /** * Fetch the external feed and store it in the database. - * + * * @param feed */ private void saveExternalFeed(Feed feed) { feed = externalFeedFetcher.fetchFeed(feed); - + if (feed != null) { feed.setLastModified(new Date()); feedDAO.updateFeed(feed); @@ -474,12 +499,12 @@ public class FeedManagerImpl extends FeedManager { /** * Fetch all items of the external feed and store them in the database. - * + * * @param feed */ private void saveExternalItems(Feed feed) { List<Item> externalItems = externalFeedFetcher.fetchItems(feed); - + for (Item externalItem : externalItems) { Item reloaded = itemDAO.loadItemByGuid(feed.getKey(), externalItem.getGuid()); if (reloaded == null) { @@ -493,6 +518,10 @@ public class FeedManagerImpl extends FeedManager { if (externalItem.getPublishDate() == null) { externalItem.setPublishDate(now); } + + if(dbInstance.isMySQL()) { + mysqlCleanUp(externalItem); + } itemDAO.createItem(feed, externalItem); } else { // Do not overwrite initial values @@ -509,90 +538,65 @@ public class FeedManagerImpl extends FeedManager { reloaded.setContent(externalItem.getContent()); reloaded.setEnclosure(externalItem.getEnclosure()); + if(dbInstance.isMySQL()) { + mysqlCleanUp(externalItem); + } itemDAO.updateItem(reloaded); } } } + + private void mysqlCleanUp(Item item) { + item.setTitle(PersistenceHelper.convert(item.getTitle())); + item.setContent(PersistenceHelper.convert(item.getContent())); + item.setDescription(PersistenceHelper.convert(item.getDescription())); + } - /** - * Update the repository entry with the latest set properties in the feed - * resource. - * <p> - * Properties are: - * <ul> - * <li>Title - * <li>Author - * <li>Descripion (wiki style in repository) - * <li>Image - * </ul> - * - * @param feed - */ - private void enrichRepositoryEntryByFeedInformation(Feed feed) { - RepositoryEntry entry = repositoryManager.lookupRepositoryEntry(feed, false); - if (entry != null && feed != null) { - Date whenTheFeedWasLastModified = feed.getLastModified(); - if (whenTheFeedWasLastModified != null && entry.getLastModified().before(whenTheFeedWasLastModified)) { - // feed is newer than repository entry, update repository entry - String saveTitle = PersistenceHelper.truncateStringDbSave(feed.getTitle(), 100, true); - entry.setDisplayname(saveTitle); - String saveDesc = PersistenceHelper.truncateStringDbSave(feed.getDescription(), 16777210, true); - entry.setDescription(saveDesc); - // Update the image - VFSLeaf oldEntryImage = repositoryManager.getImage(entry); - if (oldEntryImage != null) { - // Delete the old File - oldEntryImage.delete(); - } - // Copy the feed image to the repository home folder - VFSItem newImage = feedFileStorage.loadFeedMedia(feed); - if (newImage == null) { - // huh? image defined but not found on disk - remove - // image from feed - feed.setImageName(null); - } else { - repositoryManager.setImage((VFSLeaf) newImage, entry); - } - } - } + private void markPublisherNews(Feed feed) { + if (feed == null) return; + + notificationsManager.markPublisherNews( + feed.getResourceableTypeName(), + feed.getResourceableId().toString(), + null, + false); } - - /** - * Update the feed resource with the latest set properties in the repository - * entry. - * <p> - * Properties are: - * <ul> - * <li>Title (if not already set) - * <li>Author - * </ul> - * - * @param feed - */ - private Feed enrichFeedByRepositoryEntryInfromation(Feed feed) { - RepositoryEntry entry = repositoryManager.lookupRepositoryEntry(feed, false); - if (entry != null && feed != null) { - Date whenTheFeedWasLastModified = feed.getLastModified(); - if (feed.getTitle() == null || whenTheFeedWasLastModified == null || entry.getLastModified().after(whenTheFeedWasLastModified)) { - // Copy the title (only) initially - if (feed.getTitle() == null) { - feed.setTitle(entry.getDisplayname()); - } - if (StringHelper.containsNonWhitespace(entry.getAuthors())) { - feed.setAuthor(entry.getAuthors()); - } else { - feed.setAuthor(null); - } - feed = updateFeed(feed); - } + + @Override + public Feed updateFeedWithRepositoryEntry(RepositoryEntry entry) { + Feed feed = loadFeed(entry.getOlatResource()); + feed = enrichFeedByRepositoryEntry(feed, entry); + feed = updateFeed(feed); + return feed; + } + + @Override + public Feed enrichFeedByRepositoryEntry(Feed feed, RepositoryEntry entry) { + if (feed == null) return null; + if (entry == null) return feed; + + // copy the metadata + feed.setTitle(entry.getDisplayname()); + feed.setDescription(entry.getDescription()); + + // Some old feeds have an author but it is not in the RespositoryEntry. + // Keep the author of the feed in this case. + if (entry.getAuthors() != null) { + feed.setAuthor(entry.getAuthors()); } + + // copy the image + VFSLeaf image = repositoryManager.getImage(entry); + String imageName = feedFileStorage.saveFeedMedia(feed, image); + feed.setImageName(imageName); + return feed; } /** * A unique key for the item of the feed. Can be used e.g. for locking and * caching. - * + * * @param string * @param string2 * @return A unique key for the item of the feed @@ -607,7 +611,7 @@ public class FeedManagerImpl extends FeedManager { /** * A unique key for the item of the feed. Can be used e.g. for locking and * caching. (Protected for performance reasons) - * + * * @param item * @param feed * @return A unique key for the item of the feed @@ -621,12 +625,12 @@ public class FeedManagerImpl extends FeedManager { public VFSContainer getItemContainer(Item item) { return feedFileStorage.getOrCreateItemContainer(item); } - + @Override public void saveItemAsXML(Item item) { feedFileStorage.saveItemAsXML(item); } - + @Override public void deleteItemXML(Item item) { feedFileStorage.deleteItemXML(item); @@ -695,51 +699,8 @@ public class FeedManagerImpl extends FeedManager { @Override public ValidatedURL validateFeedUrl(String url, String type) { - SyndFeedInput input = new SyndFeedInput(); - - boolean modifiedProtocol = false; - try { - if (url != null) { - url = url.trim(); - } - if (url.startsWith("feed") || url.startsWith("itpc")) { - // accept feed(s) urls like generated in safari browser - url = "http" + url.substring(4); - modifiedProtocol = true; - } - URL realUrl = new URL(url); - SyndFeed feed = input.build(new XmlReader(realUrl)); - if (!feed.getEntries().isEmpty()) { - // check for enclosures - SyndEntry entry = feed.getEntries().get(0); - if (type != null && type.indexOf("BLOG") >= 0) { - return new ValidatedURL(url, ValidatedURL.State.VALID); - } - if (entry.getEnclosures().isEmpty()) { - return new ValidatedURL(url, ValidatedURL.State.NO_ENCLOSURE); - } - } - // The feed was read successfully - return new ValidatedURL(url, ValidatedURL.State.VALID); - } catch (ParsingFeedException e) { - if (modifiedProtocol) { - // fallback for SWITCHcast itpc -> http -> https - url = "https" + url.substring(4); - return validateFeedUrl(url, type); - } - return new ValidatedURL(url, ValidatedURL.State.NOT_FOUND); - } catch (FileNotFoundException e) { - return new ValidatedURL(url, ValidatedURL.State.NOT_FOUND); - } catch (MalformedURLException e) { - // The url is invalid - } catch (FeedException e) { - // The feed couldn't be read - } catch (IOException e) { - // Maybe network or file problems - } catch (IllegalArgumentException e) { - // something very wrong with the feed - } - return new ValidatedURL(url, ValidatedURL.State.MALFORMED); + boolean enclosuresExpected = type != null && type.indexOf("BLOG") >= 0? false: true; + return externalFeedFetcher.validateFeedUrl(url, enclosuresExpected); } @Override @@ -753,10 +714,10 @@ public class FeedManagerImpl extends FeedManager { // load the feed and the items from the database Feed sourceFeed = feedDAO.loadFeed(sourceResource); List<Item> items = itemDAO.loadItems(sourceFeed); - + // copy the feed in the database Feed targetFeed = feedDAO.copyFeed(sourceResource, targetResource); - + // copy the items in the database for (Item item : items) { itemDAO.copyItem(targetFeed, item); @@ -775,12 +736,12 @@ public class FeedManagerImpl extends FeedManager { public VFSLeaf getFeedArchive(OLATResourceable resource) { VFSContainer rootContainer = feedFileStorage.getResourceContainer(resource); VFSContainer feedContainer = feedFileStorage.getOrCreateFeedContainer(resource); - + // Load the feed from database an store it to the XML file. Feed feed = feedDAO.loadFeed(resource); feed.setModelVersion(FeedImpl.CURRENT_MODEL_VERSION); feedFileStorage.saveFeedAsXML(feed); - + // Load the items from the database, make it export safe and store them // to XML files. List<Item> items = loadItems(feed); @@ -814,20 +775,20 @@ public class FeedManagerImpl extends FeedManager { return (VFSLeaf) rootContainer.resolve(zipFileName); } }); - + // delete the XML files again. They are only needed for the export. for (Item item : items) { feedFileStorage.deleteItemXML(item); } feedFileStorage.deleteFeedXML(feed); - + return zip; } /** * Returns the file name of the archive that is to be exported. Depends on * the kind of the resource. - * + * * @param resource * @return The zip archive file name */ @@ -844,9 +805,9 @@ public class FeedManagerImpl extends FeedManager { public void importFeedFromXML(OLATResource ores, boolean removeIdentityKeys) { Feed feedFromXml = feedFileStorage.loadFeedFromXML(ores); if (feedFromXml == null) return; - + // Check if the feed already exits or create it. The feed exists - // possibly, if a previous migration from an XML feed was not + // possibly, if a previous migration from an XML feed was not // successful. Feed feed = feedDAO.loadFeed(ores); if (feed == null) { @@ -861,11 +822,11 @@ public class FeedManagerImpl extends FeedManager { feed = feedDAO.createFeed(feedFromXml); log.info("Feed imported " + "(" + ores.getResourceableTypeName() + "): " + ores.getResourceableId()); } - + List<Item> itemsFromXml = feedFileStorage.loadItemsFromXML(ores); itemsFromXml = fixFeedVersionIssues(feedFromXml, itemsFromXml); for (Item itemFromXml : itemsFromXml) { - // Check if the item already exits or create it. + // Check if the item already exits or create it. Item item = itemDAO.loadItemByGuid(feed.getKey(), itemFromXml.getGuid()); if (item == null) { if (removeIdentityKeys) { @@ -887,12 +848,12 @@ public class FeedManagerImpl extends FeedManager { } feedFileStorage.deleteItemXML(itemFromXml); } - + if (feed.isExternal()) { saveExternalItems(feed); saveExternalFeed(feed); } - + feedFileStorage.deleteFeedXML(feed); } @@ -901,7 +862,7 @@ public class FeedManagerImpl extends FeedManager { * necessary fixes to the model. Since feeds can be exported and imported * this fixes must apply on the fly and can't be implemented with the system * upgrade mechanism. - * + * * @param feed * @return the fixed items */ diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedNotificationsHandler.java b/src/main/java/org/olat/modules/webFeed/manager/FeedNotificationsHandler.java index 43d894f210998e8801782aa002f33f82523b343b..bef6e18d21c1ec2225864a3a326660aeedce24d2 100644 --- a/src/main/java/org/olat/modules/webFeed/manager/FeedNotificationsHandler.java +++ b/src/main/java/org/olat/modules/webFeed/manager/FeedNotificationsHandler.java @@ -24,6 +24,8 @@ import java.util.Date; import java.util.List; import java.util.Locale; +import org.olat.core.commons.services.commentAndRating.CommentAndRatingService; +import org.olat.core.commons.services.commentAndRating.model.UserComment; import org.olat.core.commons.services.notifications.NotificationsHandler; import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.commons.services.notifications.Publisher; @@ -48,34 +50,37 @@ import org.olat.modules.webFeed.Item; import org.olat.modules.webFeed.ui.FeedMainController; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; +import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; /** - * + * * Initial date: 6 juin 2017<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public abstract class FeedNotificationsHandler implements NotificationsHandler { - + private static final OLog log = Tracing.createLoggerFor(FeedNotificationsHandler.class); private static final String NOTIFICATIONS_HEADER_COURSE = "notifications.header.course"; protected static final String NOTIFICATIONS_HEADER = "notifications.header"; - + @Autowired private FeedManager feedManager; @Autowired private RepositoryManager repoManager; @Autowired private NotificationsManager notificationsManager; - + @Autowired + private CommentAndRatingService commentAndRatingService; + @Override public SubscriptionInfo createSubscriptionInfo(Subscriber subscriber, Locale locale, Date compareDate) { SubscriptionInfo si; Publisher p = subscriber.getPublisher(); Date latestNews = p.getLatestNewsDate(); - + try { final Translator translator = Util.createPackageTranslator(FeedMainController.class, locale); if (notificationsManager.isPublisherValid(p) && compareDate.before(latestNews)) { @@ -102,7 +107,7 @@ public abstract class FeedNotificationsHandler implements NotificationsHandler { log.error("Unknown Exception", e); return notificationsManager.getNoSubscriptionInfo(); } - + OLATResourceable feedOres = OresHelper.createOLATResourceableInstance(p.getType(), new Long(p.getData())); Feed feed = feedManager.loadFeed(feedOres); List<Item> listItems = feedManager.loadItems(feed); @@ -123,7 +128,7 @@ public abstract class FeedNotificationsHandler implements NotificationsHandler { } return si; } - + private void appendSubscriptionItem(Item item, Publisher p, Date compareDate, Translator translator, List<SubscriptionListItem> items) { String title = item.getTitle(); String author = item.getAuthor(); @@ -137,7 +142,7 @@ public abstract class FeedNotificationsHandler implements NotificationsHandler { String desc = translator.translate("notifications.entry.published", new String[] { title, author }); items.add(new SubscriptionListItem(desc, urlToSend, businessPath, publishDate, iconCssClass)); } - + // Internal items are modified when the modifier key is present. // External items are modified when the creation date is unequal the // last modified date and the published date is after the last @@ -156,20 +161,34 @@ public abstract class FeedNotificationsHandler implements NotificationsHandler { items.add(new SubscriptionListItem(desc, urlToSend, businessPath, modDate, iconCssClass)); } } + + List<UserComment> comments = commentAndRatingService.getComments(item.getFeed(), item.getGuid()); + for (UserComment comment : comments) { + if (compareDate.before(comment.getCreationDate())) { + String desc; + String modifier = UserManager.getInstance().getUserDisplayName(comment.getCreator().getKey()); + if(StringHelper.containsNonWhitespace(modifier)) { + desc = translator.translate("notifications.entry.commented", new String[] { title, modifier }); + } else { + desc = translator.translate("notifications.entry.commented", new String[] { title, "???" }); + } + items.add(new SubscriptionListItem(desc, urlToSend, businessPath, comment.getCreationDate(), iconCssClass)); + } + } } } - + protected abstract String getCssClassIcon(); - + protected abstract String getHeader(Translator translator, String title); - + @Override public String createTitleInfo(Subscriber subscriber, Locale locale) { Translator translator = Util.createPackageTranslator(FeedMainController.class, locale); TitleItem title = getTitleItem(subscriber.getPublisher(), translator); return title.getInfoContent("text/plain"); } - + protected TitleItem getTitleItem(Publisher p, Translator translator) { String title; try { @@ -182,11 +201,11 @@ public abstract class FeedNotificationsHandler implements NotificationsHandler { } return new TitleItem(title, CSSHelper.CSS_CLASS_FILETYPE_FOLDER); } - + protected void checkPublisher(Publisher p) { try { RepositoryEntry entry = repoManager.lookupRepositoryEntry(OresHelper.createOLATResourceableInstance(p.getResName(), p.getResId()), false); - if (entry == null) { + if (entry == null) { notificationsManager.deactivate(p); } } catch (Exception e) { diff --git a/src/main/java/org/olat/modules/webFeed/manager/ItemDAO.java b/src/main/java/org/olat/modules/webFeed/manager/ItemDAO.java index d4dd7b70207612d4ba3d484f5eabb6dc07422ea5..41dd27346edf73843483e519d0ae9b6654b20b4d 100644 --- a/src/main/java/org/olat/modules/webFeed/manager/ItemDAO.java +++ b/src/main/java/org/olat/modules/webFeed/manager/ItemDAO.java @@ -151,7 +151,31 @@ public class ItemDAO { return item; } - + + /** + * Loads an item by GUID. This method is not safe because a GUID is only + * unique inside a feed. If more then one item have the same GUID, it return + * null. + * + * @param guid + * @return + */ + public Item loadItemByGuid(String guid) { + if (guid == null) return null; + + Item item = null; + try { + item = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadItemByGuidWithoutFeed", ItemImpl.class) + .setParameter("guid", guid) + .getSingleResult(); + } catch (Exception e) { + // nothing to do, return null + } + + return item; + } + /** * Loads all items of a feed. * diff --git a/src/main/java/org/olat/modules/webFeed/manager/RomeFeedFetcher.java b/src/main/java/org/olat/modules/webFeed/manager/RomeFeedFetcher.java index b1f1fd38b86a7bb61ba199ace8ace2eede9c4eee..a452104577dbf262acc55d5e39b93f1b6f6b6ed3 100644 --- a/src/main/java/org/olat/modules/webFeed/manager/RomeFeedFetcher.java +++ b/src/main/java/org/olat/modules/webFeed/manager/RomeFeedFetcher.java @@ -19,6 +19,7 @@ */ package org.olat.modules.webFeed.manager; +import java.io.FileNotFoundException; import java.io.Reader; import java.net.URL; import java.util.ArrayList; @@ -40,13 +41,14 @@ import com.rometools.rome.feed.synd.SyndContent; import com.rometools.rome.feed.synd.SyndEnclosure; import com.rometools.rome.feed.synd.SyndEntry; import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.ParsingFeedException; import com.rometools.rome.io.SyndFeedInput; import com.rometools.rome.io.XmlReader; /** * This implementation of an ExternalFeedFetcher uses the library Rome to fetch * feeds form an external web site.<br> - * + * * Initial date: 12.05.2017<br> * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com * @@ -55,23 +57,23 @@ import com.rometools.rome.io.XmlReader; public class RomeFeedFetcher implements ExternalFeedFetcher { private static final OLog log = Tracing.createLoggerFor(RomeFeedFetcher.class); - + private final SyndFeedInput syndFeedInput; - + public RomeFeedFetcher() { this(new SyndFeedInput()); } - + public RomeFeedFetcher(SyndFeedInput syndFeedInput) { this.syndFeedInput = syndFeedInput; } - + @Override public Feed fetchFeed(Feed feed) { SyndFeed syndFeed = fetchSyndFeed(feed.getExternalFeedUrl()); return justifyFeed(feed, syndFeed); } - + /** * Takes the values from the SyndFeed and pass them to the Feed. * @param feed @@ -80,7 +82,7 @@ public class RomeFeedFetcher implements ExternalFeedFetcher { */ protected Feed justifyFeed(Feed feed, SyndFeed syndFeed) { if (feed == null) return null; - + String imageUrl = null; if (syndFeed == null) { // keep the old image @@ -89,9 +91,9 @@ public class RomeFeedFetcher implements ExternalFeedFetcher { // take the new image imageUrl = syndFeed.getImage().getUrl(); } - + feed.setExternalImageURL(imageUrl); - + return feed; } @@ -101,12 +103,12 @@ public class RomeFeedFetcher implements ExternalFeedFetcher { if (syndFeed == null) { return new ArrayList<>(); } - + return syndFeed.getEntries().stream() .map(entry -> convertEntry(feed, entry)) .collect(Collectors.toList()); } - + /** * Fetches the SyndFeed of an URL. * @param feedURL @@ -124,34 +126,34 @@ public class RomeFeedFetcher implements ExternalFeedFetcher { return syndFeed; } - - + + /** * Converts a <code>SyndEntry</code> into an <code>Item</code> - * + * * @param entry * @return */ protected Item convertEntry(Feed feed, SyndEntry entry) { Item item = new ItemImpl(feed); - + item.setAuthor(entry.getAuthor()); item.setExternalLink(entry.getLink()); item.setGuid(entry.getUri()); item.setLastModified(entry.getUpdatedDate()); item.setPublishDate(entry.getPublishedDate()); item.setTitle(entry.getTitle()); - + if (entry.getDescription() != null) { item.setDescription(entry.getDescription().getValue()); } - + List<SyndContent> contents = entry.getContents(); item.setContent(joinContents(contents)); List<SyndEnclosure> enclosures = entry.getEnclosures(); item.setEnclosure(convertEnclosures(enclosures)); - + return item; } @@ -161,29 +163,29 @@ public class RomeFeedFetcher implements ExternalFeedFetcher { * first entry is taken. * SyndEnclosures without an URL are not converted, because it is necessary to * fetch the enclosure. - * + * * @param enclosures * @return the enclosure or null */ protected Enclosure convertEnclosures(List<SyndEnclosure> enclosures) { if (enclosures == null || enclosures.isEmpty()) return null; - + SyndEnclosure syndEnclosure = enclosures.get(0); Enclosure enclosure = null; - + if (StringHelper.containsNonWhitespace(syndEnclosure.getUrl())) { enclosure = new EnclosureImpl(); enclosure.setExternalUrl(syndEnclosure.getUrl()); enclosure.setLength(syndEnclosure.getLength()); enclosure.setType(syndEnclosure.getType()); } - + return enclosure; } /** * Joins the values of all SyndContent by a html p. - * + * * @param contents * @return the joined values or null */ @@ -195,4 +197,51 @@ public class RomeFeedFetcher implements ExternalFeedFetcher { .collect(Collectors.joining("<p />")); } + @Override + public ValidatedURL validateFeedUrl(String url, boolean enclosuresExpected) { + SyndFeedInput input = new SyndFeedInput(); + + boolean modifiedProtocol = false; + try { + if (url != null) { + url = url.trim(); + } + if (url.startsWith("feed") || url.startsWith("itpc")) { + // accept feed(s) urls like generated in safari browser + url = "http" + url.substring(4); + modifiedProtocol = true; + } + URL realUrl = new URL(url); + SyndFeed feed = input.build(new XmlReader(realUrl)); + if (!feed.getEntries().isEmpty()) { + if (enclosuresExpected) { + SyndEntry entry = feed.getEntries().get(0); + if (entry.getEnclosures().isEmpty()) { + return new ValidatedURL(url, ValidatedURL.State.NO_ENCLOSURE); + } + } + return new ValidatedURL(url, ValidatedURL.State.VALID); + } + // The feed was read successfully + return new ValidatedURL(url, ValidatedURL.State.VALID); + } catch (ParsingFeedException e) { + if (modifiedProtocol) { + // fallback for SWITCHcast itpc -> http -> https + url = "https" + url.substring(4); + return validateFeedUrl(url, enclosuresExpected); + } + String message = String.format("Validation of the feed url %s failed. %s: %s ", url, e.getClass(), e.getMessage()); + log.debug(message); + return new ValidatedURL(url, ValidatedURL.State.NOT_FOUND); + } catch (FileNotFoundException e) { + String message = String.format("Validation of the feed url %s failed. %s: %s ", url, e.getClass(), e.getMessage()); + log.debug(message); + return new ValidatedURL(url, ValidatedURL.State.NOT_FOUND); + } catch (Exception e) { + String message = String.format("Validation of the feed url %s failed. %s: %s ", url, e.getClass(), e.getMessage()); + log.debug(message); + } + return new ValidatedURL(url, ValidatedURL.State.MALFORMED); + } + } diff --git a/src/main/java/org/olat/modules/webFeed/model/ItemImpl.java b/src/main/java/org/olat/modules/webFeed/model/ItemImpl.java index 3ff58f6f9e56349ed21c277e0489a2732e5f5aed..571d22bc7b4e97dddf0325aef8fc9a943617d9ae 100644 --- a/src/main/java/org/olat/modules/webFeed/model/ItemImpl.java +++ b/src/main/java/org/olat/modules/webFeed/model/ItemImpl.java @@ -58,6 +58,8 @@ import org.olat.user.UserManager; @NamedQueries({ @NamedQuery(name="loadItemByGuid", query="select data from item data where data.feed.key=:feedKey and data.guid=:guid"), + @NamedQuery(name="loadItemByGuidWithoutFeed", + query="select data from item data where data.guid=:guid"), @NamedQuery(name="loadItemsByFeed", query="select data from item data where data.feed=:feed"), @NamedQuery(name="loadItemsGuidByFeed", diff --git a/src/main/java/org/olat/modules/webFeed/model/ItemPublishDateComparator.java b/src/main/java/org/olat/modules/webFeed/model/ItemPublishDateComparator.java index 562654f6a85ece0f3ea65ba7572c226f788d3862..032f2bd45643a2e026260b94d8fa80277ec40592 100644 --- a/src/main/java/org/olat/modules/webFeed/model/ItemPublishDateComparator.java +++ b/src/main/java/org/olat/modules/webFeed/model/ItemPublishDateComparator.java @@ -25,7 +25,9 @@ import java.util.Date; import org.olat.modules.webFeed.Item; /** - * Compares the publish date of two items. + * Comparator to separate the items in drafts and published items. Inside the + * two groups the items are sorted according to the reverse chronological order + * of the publish date. * <P> * Initial Date: Aug 4, 2009 <br> * @@ -33,17 +35,18 @@ import org.olat.modules.webFeed.Item; */ public class ItemPublishDateComparator implements Comparator<Item> { - /** - * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) - */ @Override public int compare(Item a, Item b) { - // reverse chronological order - Date d1 = a.getPublishDate(); - Date d2 = b.getPublishDate(); - if(d1 == null) return 1; - if(d2 == null) return -1; - - return d2.compareTo(d1); + if (a.isDraft() == b.isDraft()) { + Date d1 = a.getPublishDate(); + Date d2 = b.getPublishDate(); + if(d1 == null) return 1; + if(d2 == null) return -1; + return d2.compareTo(d1); + } + if (b.isDraft()) { + return 1; + } + return -1; } } diff --git a/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaController.java b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaController.java index 8999f480a5b0b594f42eae6796d99f3ccd188bb2..57efd0a9d72f75b6ed0c11b7d9e6ab34d92760ae 100644 --- a/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaController.java +++ b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaController.java @@ -38,7 +38,9 @@ import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.xml.XStreamHelper; import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.manager.PortfolioFileStorage; +import org.olat.modules.portfolio.ui.MediaMetadataController; import org.olat.modules.webFeed.Item; import org.olat.modules.webFeed.model.ItemImpl; import org.springframework.beans.factory.annotation.Autowired; @@ -64,7 +66,7 @@ public class BlogEntryMediaController extends BasicController { @Autowired private PortfolioFileStorage fileStorage; - public BlogEntryMediaController(UserRequest ureq, WindowControl wControl, Media media, boolean readOnlyMode) { + public BlogEntryMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { super(ureq, wControl); VelocityContainer mainVC = createVelocityContainer("media_post"); if (StringHelper.containsNonWhitespace(media.getStoragePath())) { @@ -84,11 +86,17 @@ public class BlogEntryMediaController extends BasicController { } mainVC.contextPut("content", content); - mainVC.contextPut("readOnlyMode", readOnlyMode); + mainVC.contextPut("readOnlyMode", Boolean.TRUE); mainVC.contextPut("item", blogItem); String mapperBase = registerMapper(ureq, new VFSContainerMapper(container)); mainVC.contextPut("helper", new ItemHelper(mapperBase)); + + if(hints.isExtendedMetadata()) { + MediaMetadataController metaCtrl = new MediaMetadataController(ureq, wControl, media); + listenTo(metaCtrl); + mainVC.put("meta", metaCtrl.getInitialComponent()); + } } catch(Exception ex) { logError("", ex); } diff --git a/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaHandler.java b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaHandler.java index a7c0a32a4e783c85a6e8f71f2bbb8eac18d04d68..10d1a8983219d2cdc8945c97a29042af00121493 100644 --- a/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaHandler.java +++ b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaHandler.java @@ -34,12 +34,12 @@ import org.olat.fileresource.types.BlogFileResource; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.handler.AbstractMediaHandler; import org.olat.modules.portfolio.manager.MediaDAO; import org.olat.modules.portfolio.manager.PortfolioFileStorage; import org.olat.modules.portfolio.ui.media.StandardEditMediaController; -import org.olat.modules.webFeed.Feed; import org.olat.modules.webFeed.Item; import org.olat.modules.webFeed.manager.FeedManager; import org.olat.portfolio.manager.EPFrontendManager; @@ -97,7 +97,6 @@ public class BlogEntryMediaHandler extends AbstractMediaHandler { @Override public Media createMedia(String title, String description, Object mediaObject, String businessPath, Identity author) { BlogEntryMedia entry = (BlogEntryMedia)mediaObject; - Feed feed = entry.getFeed(); Item item = entry.getItem(); Media media = mediaDao.createMedia(title, description, "", BLOG_ENTRY_HANDLER, businessPath, null, 70, author); @@ -139,10 +138,10 @@ public class BlogEntryMediaHandler extends AbstractMediaHandler { return media; } - + @Override - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { - return new BlogEntryMediaController(ureq, wControl, media, true); + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { + return new BlogEntryMediaController(ureq, wControl, media, hints); } @Override diff --git a/src/main/java/org/olat/modules/webFeed/portfolio/_content/media_post.html b/src/main/java/org/olat/modules/webFeed/portfolio/_content/media_post.html index d0b29b86cbdcdd37073105a2d0490a351788b3e4..693e0a49aec810e14edd95603cfa1d842fe21320 100644 --- a/src/main/java/org/olat/modules/webFeed/portfolio/_content/media_post.html +++ b/src/main/java/org/olat/modules/webFeed/portfolio/_content/media_post.html @@ -23,5 +23,10 @@ </div> #end </div> + #if($r.available("meta")) + <div class="panel panel-default o_artefact_metadata"> + $r.render("meta") + </div> + #end </div> </div></div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/ui/ExternalUrlController.java b/src/main/java/org/olat/modules/webFeed/ui/ExternalUrlController.java new file mode 100644 index 0000000000000000000000000000000000000000..5673d6e8e12a79bfa16b0bdffb229747960be3e5 --- /dev/null +++ b/src/main/java/org/olat/modules/webFeed/ui/ExternalUrlController.java @@ -0,0 +1,140 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.webFeed.ui; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +import org.olat.core.gui.components.form.flexible.elements.TextElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.link.Link; +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.modules.webFeed.Feed; +import org.olat.modules.webFeed.manager.FeedManager; +import org.olat.modules.webFeed.manager.ValidatedURL; + +/** + * + * Initial date: 18.09.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class ExternalUrlController extends FormBasicController { + + private Feed feed; + + private TextElement externalFeedUrlEl; + private FormLink cancelButton; + + public ExternalUrlController(UserRequest ureq, WindowControl windowControl, Feed feedResource) { + super(ureq, windowControl); + this.feed = feedResource; + initForm(ureq); + } + + public String getExternalFeedUrlEl() { + String externalFeedUrl = externalFeedUrlEl.getValue(); + if (StringHelper.containsNonWhitespace(externalFeedUrl)) { + return externalFeedUrl; + } + return null; + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + externalFeedUrlEl = uifactory.addTextElement("externalFeedUrlEl", "feed.form.feedurl", 5000, feed.getExternalFeedUrl(), flc); + externalFeedUrlEl.setElementCssClass("o_sel_feed_url"); + externalFeedUrlEl.setDisplaySize(70); + + String type = feed.getResourceableTypeName(); + if(type != null && type.indexOf("BLOG") >= 0) { + externalFeedUrlEl.setExampleKey("feed.form.feedurl.example", null); + } else { + externalFeedUrlEl.setExampleKey("feed.form.feedurl.example_podcast", null); + } + + final FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator()); + formLayout.add(buttonLayout); + uifactory.addFormSubmitButton("submit", buttonLayout); + cancelButton = uifactory.addFormLink("cancel", buttonLayout, Link.BUTTON); + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + return validateExternalFeedUrl() & super.validateFormLogic(ureq); + } + + private boolean validateExternalFeedUrl(){ + boolean validUrl = false; + if(externalFeedUrlEl.isEmpty()) { + //allowed + externalFeedUrlEl.clearError(); + validUrl = true; + } else { + //validated feed url + String url = externalFeedUrlEl.getValue(); + String type = feed.getResourceableTypeName(); + ValidatedURL validatedUrl = FeedManager.getInstance().validateFeedUrl(url, type); + if(!validatedUrl.getUrl().equals(url)) { + externalFeedUrlEl.setValue(validatedUrl.getUrl()); + } + switch(validatedUrl.getState()) { + case VALID: + externalFeedUrlEl.clearError(); + validUrl = true; + break; + case NO_ENCLOSURE: + externalFeedUrlEl.setErrorKey("feed.form.feedurl.invalid.no_media", null); + break; + case NOT_FOUND: + externalFeedUrlEl.setErrorKey("feed.form.feedurl.invalid.not_found", null); + break; + case MALFORMED: + externalFeedUrlEl.setErrorKey("feed.form.feedurl.invalid", null); + break; + } + } + return validUrl; + } + + @Override + protected void formOK(UserRequest ureq) { + fireEvent(ureq, Event.CHANGED_EVENT); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if (source == cancelButton) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } + } + + @Override + protected void doDispose() { + // + } + +} diff --git a/src/main/java/org/olat/modules/webFeed/ui/FeedFormController.java b/src/main/java/org/olat/modules/webFeed/ui/FeedFormController.java index e77cbe9fe09c7602cb35b0f9f7109cb2c45f0657..62372055235e555a8be156ca7d2b8193cd47648f 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/FeedFormController.java +++ b/src/main/java/org/olat/modules/webFeed/ui/FeedFormController.java @@ -230,9 +230,7 @@ class FeedFormController extends FormBasicController { description = uifactory.addRichTextElementForStringDataMinimalistic("description", "feed.form.description", feed .getDescription(), 5, -1, formLayout, getWindowControl()); - description.setMandatory(true); description.setMaxLength(4000); - description.setNotEmptyCheck("feed.form.field.is_mandatory"); RichTextConfiguration richTextConfig = description.getEditorConfiguration(); // set upload dir to the media dir richTextConfig.setFileBrowserUploadRelPath("media"); diff --git a/src/main/java/org/olat/modules/webFeed/ui/FeedMainController.java b/src/main/java/org/olat/modules/webFeed/ui/FeedMainController.java index 08095f2f6e104192fcda10aeb64de80919bde5e6..e10335c2702bd58bce4cc23ca1ef7ea867094b26 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/FeedMainController.java +++ b/src/main/java/org/olat/modules/webFeed/ui/FeedMainController.java @@ -19,6 +19,7 @@ */ package org.olat.modules.webFeed.ui; +import java.time.ZonedDateTime; import java.util.List; import org.olat.core.commons.services.notifications.PublisherData; @@ -46,10 +47,13 @@ import org.olat.core.util.coordinate.LockResult; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.resource.OLATResourceableJustBeforeDeletedEvent; import org.olat.modules.webFeed.Feed; +import org.olat.modules.webFeed.FeedChangedEvent; import org.olat.modules.webFeed.FeedSecurityCallback; import org.olat.modules.webFeed.FeedViewHelper; import org.olat.modules.webFeed.Item; import org.olat.modules.webFeed.manager.FeedManager; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; import org.olat.user.UserManager; import org.olat.util.logging.activity.LoggingResourceable; import org.springframework.beans.factory.annotation.Autowired; @@ -83,6 +87,8 @@ public class FeedMainController extends BasicController implements Activateable2 private SubscriptionContext subsContext; private OLATResourceable ores; + @Autowired + private RepositoryManager repositoryManager; @Autowired private UserManager userManager; @Autowired @@ -170,9 +176,8 @@ public class FeedMainController extends BasicController implements Activateable2 vcRightCol = uiFactory.createRightColumnVelocityContainer(this); vcMain.put("rightColumn", vcRightCol); - // The current user has edit rights if he/she is an administrator or an - // owner of the resource. - if (callback.mayEditMetadata()) { + RepositoryEntry repositoryEntry = repositoryManager.lookupRepositoryEntry(feed, false); + if (repositoryEntry == null && callback.mayEditMetadata()) { editFeedButton = LinkFactory.createButtonSmall("feed.edit", vcInfo, this); editFeedButton.setElementCssClass("o_sel_feed_edit"); } @@ -326,17 +331,18 @@ public class FeedMainController extends BasicController implements Activateable2 String itemId = entries.get(0).getOLATResourceable().getResourceableTypeName(); if(itemId != null && itemId.startsWith("item=")) { itemId = itemId.substring(5, itemId.length()); - Long itemKey = Long.parseLong(itemId); - item = FeedManager.getInstance().loadItem(itemKey); + try { + Long itemKey = Long.parseLong(itemId); + item = FeedManager.getInstance().loadItem(itemKey); + } catch (Exception e) { + item = FeedManager.getInstance().loadItemByGuid(itemId); + } } if (item != null) { itemsCtr.activate(ureq, item); } } - /** - * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event) - */ @Override public void event(Event event) { if (event instanceof OLATResourceableJustBeforeDeletedEvent) { @@ -346,6 +352,14 @@ public class FeedMainController extends BasicController implements Activateable2 if (ojde.targetEquals(feed, true)) { dispose(); } + } else if (event instanceof FeedChangedEvent) { + FeedChangedEvent fce = (FeedChangedEvent) event; + if (fce.getFeedKey().equals(feed.getKey())) { + feed = feedManager.loadFeed(feed); + vcInfo.contextPut("supressCache", "&" + ZonedDateTime.now().toInstant().toEpochMilli()); + vcInfo.contextPut("feed", feed); + vcInfo.setDirty(true); + } } } } diff --git a/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java b/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java index c0a85a738a9d7583497c142a0f398fc90434a5a7..cafacc1898e322ed35abb1d60ad3efd625ca372d 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java +++ b/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java @@ -99,7 +99,7 @@ public class FeedRuntimeController extends RepositoryEntryRuntimeController { RepositoryEntry entry = getRepositoryEntry(); OlatRootFolderImpl feedRoot = FileResourceManager.getInstance().getFileResourceRootImpl(entry.getOlatResource()); WindowControl bwControl = getSubWindowControl("Quota"); - Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), feedRoot.getRelPath(), false); + Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), feedRoot.getRelPath()); pushController(ureq, translate("tab.quota.edit"), quotaCtrl); setActiveTool(quotaLink); } diff --git a/src/main/java/org/olat/modules/webFeed/ui/FeedUIFactory.java b/src/main/java/org/olat/modules/webFeed/ui/FeedUIFactory.java index bc58efd58be8c7568bc37c90b1e6cc9b45f4fb72..59de744aee5552572d886cded11393e0b996964f 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/FeedUIFactory.java +++ b/src/main/java/org/olat/modules/webFeed/ui/FeedUIFactory.java @@ -32,15 +32,16 @@ import org.olat.core.id.OLATResourceable; import org.olat.course.ICourse; import org.olat.course.nodes.AbstractFeedCourseNode; import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.webFeed.Feed; import org.olat.modules.webFeed.FeedSecurityCallback; import org.olat.modules.webFeed.Item; /** * Abstract Factory Pattern for the user interface of different feed types. - * + * * <P> * Initial Date: Jul 30, 2009 <br> - * + * * @author gwassmann */ public abstract class FeedUIFactory { @@ -53,7 +54,7 @@ public abstract class FeedUIFactory { public abstract Translator getTranslator(); public abstract void setTranslator(Locale locale); - + public abstract VelocityContainer createInfoVelocityContainer(BasicController controller); public abstract VelocityContainer createItemsVelocityContainer(BasicController controller); @@ -71,7 +72,7 @@ public abstract class FeedUIFactory { public final FeedMainController createMainController(OLATResourceable ores, UserRequest ureq, WindowControl wControl, FeedSecurityCallback callback) { return new FeedMainController(ores, ureq, wControl, null, null, this, callback, null); } - + // with specific FeedItemDisplayConfig public final FeedMainController createMainController(final OLATResourceable ores, final UserRequest ureq, final WindowControl wControl, final FeedSecurityCallback callback, FeedItemDisplayConfig displayConfig) { return new FeedMainController(ores, ureq, wControl, null, null, this, callback, displayConfig); @@ -81,6 +82,9 @@ public abstract class FeedUIFactory { public abstract TabbableController createNodeEditController(AbstractFeedCourseNode courseNode, ICourse course, UserCourseEnvironment uce, UserRequest ureq, WindowControl control); - - + + public ExternalUrlController createExternalUrlController(UserRequest ureq, WindowControl windowControl, Feed feedResource) { + return new ExternalUrlController(ureq, windowControl, feedResource); + } + } diff --git a/src/main/java/org/olat/modules/webFeed/ui/ItemFormController.java b/src/main/java/org/olat/modules/webFeed/ui/ItemFormController.java index eca16f32ee54d35164a6286a7e4cf56d2bfbe0a0..ebd95a14c0f699a5fcb0da4a3d86613fc85db802 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/ItemFormController.java +++ b/src/main/java/org/olat/modules/webFeed/ui/ItemFormController.java @@ -24,7 +24,6 @@ import java.util.Calendar; import java.util.Date; import org.olat.core.commons.services.image.Size; -import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.commons.services.video.MovieService; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; @@ -59,17 +58,17 @@ import org.springframework.beans.factory.annotation.Autowired; /** * This Controller is responsible for editing a single feed item. - * + * * Initial date: 16.06.2017<br> * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com * */ public abstract class ItemFormController extends FormBasicController { - + private final String ALLOWED_MIME_TYPES = ".*[.](flv|mp3|mp4|m4v|m4a|aac)"; private Item item; - + private TextElement title; private RichTextElement description; private RichTextElement content; @@ -80,12 +79,10 @@ public abstract class ItemFormController extends FormBasicController { private DateChooser publishDateChooser; private FormLink draftButton; private FormLink cancelButton; - + @Autowired private MovieService movieService; - @Autowired - private NotificationsManager notificationsManager; - + public ItemFormController(UserRequest ureq, WindowControl control, Item item, Translator translator) { super(ureq, control); this.item = item; @@ -94,23 +91,23 @@ public abstract class ItemFormController extends FormBasicController { Quota quota = FeedManager.getInstance().getQuota(item.getFeed()); baseDir.setLocalSecurityCallback(new FullAccessWithQuotaCallback(quota)); } - + setTranslator(translator); initForm(ureq); } - + protected abstract String getType(); - + protected abstract boolean hasContent(); - + protected abstract boolean hasMandatoryMedia(); - + protected abstract boolean hasDraftMode(); - + @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { formLayout.setElementCssClass("o_sel_feed_form"); - + title = uifactory.addTextElement("title", "feed.title.label", 256, item.getTitle(), this.flc); title.setElementCssClass("o_sel_feed_title"); title.setMandatory(true); @@ -123,7 +120,7 @@ public abstract class ItemFormController extends FormBasicController { descRichTextConfig.setFileBrowserUploadRelPath("media"); // disable XSS unsave buttons for movie (no media in standard profile) descRichTextConfig.disableMedia(); - + content = uifactory.addRichTextElementForStringData("content", "feed.form.content", item.getContent(), 18, -1, false, baseDir, null, formLayout, ureq.getUserSession(), getWindowControl()); RichTextConfiguration richTextConfig = content.getEditorConfiguration(); @@ -148,7 +145,7 @@ public abstract class ItemFormController extends FormBasicController { String supportAddr = WebappHelper.getMailConfig("mailQuota"); file.setMaxUploadSizeKB(uploadLimitKB.intValue(), "ULLimitExceeded", new String[] { Formatter.roundToString((uploadLimitKB.floatValue() / 1000f), 1), supportAddr }); } - + String width = item.getWidth() != null && item.getWidth() > 0 ? Integer.toString(item.getWidth()) : ""; widthEl = uifactory.addTextElement("video-width", "feed.item.file.width", 12, width, flc); String height = item.getHeight() != null && item.getHeight() > 0 ? Integer.toString(item.getHeight()) : ""; @@ -177,28 +174,27 @@ public abstract class ItemFormController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { setValues(ureq); - + item.setDraft(false); - + fireEvent(ureq, Event.CHANGED_EVENT); - notificationsManager.markPublisherNews(getType(), item.getFeed().getResourceableId().toString(), null, false); } /** * Transfer the values from the form to the item object. - * + * * @param ureq */ private void setValues(UserRequest ureq) { item.setTitle(title.getValue()); item.setDescription(description.getValue()); - + if (hasContent()) { item.setContent(content.getValue()); } - + item.setMediaFile(file); - + String width = widthEl.getValue(); if(StringHelper.containsNonWhitespace(width)) { try { @@ -207,7 +203,7 @@ public abstract class ItemFormController extends FormBasicController { // already checked in validateFormLogic() } } - + String height = heightEl.getValue(); if(StringHelper.containsNonWhitespace(height)) { try { @@ -216,27 +212,27 @@ public abstract class ItemFormController extends FormBasicController { // already checked in validateFormLogic() } } - + /** * Set the modifier key it is required. The modifier key is updated if: * - the item was no draft * - the modifier key was set once - * - the item was a draft and has an other author + * - the item was a draft and has an other author */ if (!item.isDraft() || item.getModifierKey() != null || (item.isDraft() && !ureq.getIdentity().getKey().equals(item.getAuthorKey()))) { item.setModifierKey(ureq.getIdentity().getKey()); } - + item.setPublishDate(publishDateChooser.getDate()); item.setLastModified(new Date()); } - + @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; - + String name = file.getUploadFileName(); if (name != null) { if (!validateFilename(name)) { @@ -244,7 +240,7 @@ public abstract class ItemFormController extends FormBasicController { } else { flc.setDirty(true); } - + // quota check whole feed if(baseDir.getLocalSecurityCallback() == null || baseDir.getLocalSecurityCallback().getQuota() != null) { Quota feedQuota = baseDir.getLocalSecurityCallback().getQuota(); @@ -257,7 +253,7 @@ public abstract class ItemFormController extends FormBasicController { } } } - + String width = widthEl.getValue(); if(StringHelper.containsNonWhitespace(width)) { try { @@ -267,7 +263,7 @@ public abstract class ItemFormController extends FormBasicController { allOk = false; } } - + String height = heightEl.getValue(); if(StringHelper.containsNonWhitespace(height)) { try { @@ -277,19 +273,19 @@ public abstract class ItemFormController extends FormBasicController { allOk = false; } } - + return allOk & super.validateFormLogic(ureq); } - + private boolean validateFilename(String filename) { boolean allOk = true; - + boolean isFilenameValid = FileUtils.validateFilename(filename); if(!isFilenameValid) { file.setErrorKey("feed.item.file.name.notvalid", null); allOk = false; } - + // Since mimetype restrictions have been proved to be problematic, let // us validate the file ending instead as a pragmatic solution. boolean isFiletypeValid = filename.toLowerCase().matches(ALLOWED_MIME_TYPES); @@ -300,7 +296,7 @@ public abstract class ItemFormController extends FormBasicController { return allOk; } - + @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if (source == cancelButton && event.wasTriggerdBy(FormEvent.ONCLICK)) { @@ -330,17 +326,17 @@ public abstract class ItemFormController extends FormBasicController { .replaceAll(" ", "_"); file.setUploadFileName(newFilename); VFSLeaf movie = new LocalFileImpl(file.getUploadFile()); - + if (newFilename.endsWith("mov") || newFilename.endsWith("m4v")) { // Check if it actually is a mp4 file, if so rename file to - // mp4 to make later processes work smoothly. MOV is used + // mp4 to make later processes work smoothly. MOV is used // when uploading a video from an iOS device. if (movieService.isMP4(movie, newFilename)) { newFilename = newFilename.substring(0, newFilename.length() - 3) + "mp4"; file.setUploadFileName(newFilename); } } - + if (validateFilename(newFilename)){ // try to detect width and height for movies, prefill for user if possible Size size = movieService.getSize(movie, FileUtils.getFileSuffix(newFilename)); diff --git a/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java b/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java index fc553541425d6ffb3a17b108b4b6dad52ea30629..96f75b887593c582e23dc11fcf78ae2d0dfd0cb5 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java +++ b/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java @@ -77,9 +77,9 @@ import org.springframework.beans.factory.annotation.Autowired; /** * This class is responsible for dealing with items. For internal podcasts, * items can be created, edited and deleted. - * + * * Initial Date: Mar 2, 2009 <br> - * + * * @author gwassmann */ public class ItemsController extends BasicController implements Activateable2 { @@ -91,7 +91,9 @@ public class ItemsController extends BasicController implements Activateable2 { private Map<Item, Controller> artefactLinks; private Map<Item, Controller> commentsLinks; private Link addItemButton, makeInternalButton, makeExternalButton, olderItemsLink, newerItemsLink, startpageLink; + private Link externalUrlButton; private FormBasicController itemFormCtr; + private ExternalUrlController externalUrlCtr; private CloseableModalController cmc; private DialogBoxController confirmDialogCtr; private Feed feedResource; @@ -122,7 +124,7 @@ public class ItemsController extends BasicController implements Activateable2 { /** * default constructor, with full FeedItemDisplayConfig - * + * * @param ureq * @param wControl * @param feed @@ -139,7 +141,7 @@ public class ItemsController extends BasicController implements Activateable2 { /** * load items with a given displayconfig - * + * * @param ureq * @param wControl * @param feed @@ -172,13 +174,13 @@ public class ItemsController extends BasicController implements Activateable2 { vcItems.contextPut("helper", helper); olderItemsLink = LinkFactory.createLink("feed.older.items", vcItems, this); - olderItemsLink.setCustomDisplayText("«"); + olderItemsLink.setCustomDisplayText("« " + translate("feed.older.items")); olderItemsLink.setCustomEnabledLinkCSS("o_backward"); olderItemsLink.setTitle("feed.older.items"); newerItemsLink = LinkFactory.createLink("feed.newer.items", vcItems, this); newerItemsLink.setCustomEnabledLinkCSS("o_forward"); - newerItemsLink.setCustomDisplayText("»"); + newerItemsLink.setCustomDisplayText(translate("feed.newer.items") + " »"); newerItemsLink.setTitle("feed.newer.items"); startpageLink = LinkFactory.createLink("feed.startpage", vcItems, this); @@ -227,7 +229,7 @@ public class ItemsController extends BasicController implements Activateable2 { /** * Creates all necessary buttons for editing the feed's items - * + * * @param feed * the current feed object */ @@ -243,6 +245,9 @@ public class ItemsController extends BasicController implements Activateable2 { createButtonsForItem(ureq, feed, item); } } + } else if (feed.isExternal()) { + externalUrlButton = LinkFactory.createButtonSmall("feed.external.url", vcItems, this); + externalUrlButton.setElementCssClass("o_sel_feed_item_new"); } else if (feed.isUndefined()) { // The feed is whether internal nor external: // That is, @@ -258,7 +263,7 @@ public class ItemsController extends BasicController implements Activateable2 { /** * Create the comments and rating components for each feed item - * + * * @param ureq * @param feed */ @@ -273,7 +278,7 @@ public class ItemsController extends BasicController implements Activateable2 { /** * Create comments and rating component link for given feed item - * + * * @param ureq * @param feed * @param item @@ -303,7 +308,7 @@ public class ItemsController extends BasicController implements Activateable2 { /** * Create a GUI component to display a nicely formatted date - * + * * @param ureq * @param feed */ @@ -384,7 +389,7 @@ public class ItemsController extends BasicController implements Activateable2 { && getIdentity().getKey().equals(item.getAuthorKey())) { String businessPath = BusinessControlFactory.getInstance() .getAsString(getWindowControl().getBusinessControl()); - businessPath += "[item=" + item.getGuid() + ":0]"; + businessPath += "[item=" + item.getKey() + ":0]"; if (portfolioModule.isEnabled()) { String name = "feed.artefact.item.".concat(guid); @@ -480,10 +485,15 @@ public class ItemsController extends BasicController implements Activateable2 { if (item != null) { displayItemController(ureq, item); } + } else if (source == externalUrlButton) { + externalUrlCtr = uiFactory.createExternalUrlController(ureq, getWindowControl(), feedResource); + activateModalDialog(externalUrlCtr, uiFactory.getTranslator().translate("feed.external.url")); } else if (source == makeInternalButton) { if (feedResource.isUndefined()) { feedResource = feedManager.updateFeedMode(Boolean.FALSE, feedResource); } else if (feedResource.isExternal()) { + externalUrlButton = LinkFactory.createButtonSmall("feed.external.url", vcItems, this); + externalUrlButton.setElementCssClass("o_sel_feed_item_new"); // Very special case: another user concurrently changed feed to // external. Do nothing vcItems.setDirty(true); @@ -508,6 +518,8 @@ public class ItemsController extends BasicController implements Activateable2 { } else if (source == makeExternalButton) { if (feedResource.isUndefined()) { + externalUrlButton = LinkFactory.createButtonSmall("feed.external.url", vcItems, this); + externalUrlButton.setElementCssClass("o_sel_feed_item_new"); feedResource = feedManager.updateFeedMode(Boolean.TRUE, feedResource); vcItems.setDirty(true); // Ask listening FeedMainController to open and handle a new @@ -518,8 +530,6 @@ public class ItemsController extends BasicController implements Activateable2 { ThreadLocalUserActivityLogger.log(FeedLoggingAction.FEED_EDIT, getClass(), LoggingResourceable.wrap(feedResource)); } - // else nothing to do, already set to external by a concurrent user - } else if (source == olderItemsLink) { helper.olderItems(); createEditButtons(ureq, feedResource); @@ -719,6 +729,18 @@ public class ItemsController extends BasicController implements Activateable2 { removeAsListenerAndDispose(itemFormCtr); itemFormCtr = null; } + } else if (source == externalUrlCtr) { + if (event.equals(Event.CHANGED_EVENT)) { + String externalUrl = externalUrlCtr.getExternalFeedUrlEl(); + feedManager.updateExternalFeedUrl(feedResource, externalUrl); + } else if (event.equals(Event.CHANGED_EVENT)) { + // nothing to do + } + cmc.deactivate(); + removeAsListenerAndDispose(cmc); + cmc = null; + removeAsListenerAndDispose(externalUrlCtr); + externalUrlCtr = null; } else if (source == naviCtr && event instanceof NavigationEvent) { List<? extends Dated> selItems = ((NavigationEvent) event).getSelectedItems(); List<Item> items = new ArrayList<>(); @@ -763,13 +785,13 @@ public class ItemsController extends BasicController implements Activateable2 { /** * Private helper to remove any temp media files created for this feed - * + * * @param tmpItem */ private void cleanupTmpItemMediaDir(Item tmpItem) { String guid = tmpItem.getGuid(); if (guid == null) return; - + // delete the dir only if the item is not saved. Long key = tmpItem.getKey(); if (key == null) { @@ -792,7 +814,7 @@ public class ItemsController extends BasicController implements Activateable2 { /** * Sets the items view dirty. - * + * * @param ureq * @param feed * the current feed @@ -819,7 +841,7 @@ public class ItemsController extends BasicController implements Activateable2 { /** * Displays the item in the mainPanel of this controller. - * + * * @param ureq * @param item */ @@ -848,8 +870,12 @@ public class ItemsController extends BasicController implements Activateable2 { String itemId = entries.get(0).getOLATResourceable().getResourceableTypeName(); if(itemId != null && itemId.startsWith("item=")) { itemId = itemId.substring(5, itemId.length()); - Long itemKey = Long.parseLong(itemId); - item = FeedManager.getInstance().loadItem(itemKey); + try { + Long itemKey = Long.parseLong(itemId); + item = FeedManager.getInstance().loadItem(itemKey); + } catch (Exception e) { + item = FeedManager.getInstance().loadItemByGuid(itemId); + } } if (item != null) { activate(ureq, item); diff --git a/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_de.properties index 474d6e78d86d498054487daa3ff8f64d126603b3..984fd2fdccb58b0a11864311fe2ece9fe2104f02 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_de.properties @@ -49,3 +49,4 @@ notifications.header.podcast=Neue Eintr\u00E4ge im Podcast "{0}" notifications.header.course=Neue Eintr\u00E4ge im Kurs "{0}" notifications.entry.published=Der Post "{0}" wurde von "{1}" publiziert. notifications.entry.modified=Der Post "{0}" wurde von "{1}" ge\u00E4ndert. +notifications.entry.commented=Der Post "{0}" wurde von "{1}" kommentiert. diff --git a/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_en.properties index 90e02b898995011a8dd8cf619a9109c022e0c5f5..50f9b19f9557f482423e58c900369de2073e1176 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_en.properties @@ -50,3 +50,4 @@ notifications.header.podcast=New entries in podcast "{0}" notifications.header.course=New entries in course "{0}" notifications.entry.published=The post "{0}" was published by {1}. notifications.entry.modified=The post "{0}" was modified by {1}. +notifications.entry.commented=The post "{0}" was commented by {1}. diff --git a/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_fr.properties index 37229f0bfb97c5ab4006113d75ca669135b99d64..e5c421cdf4d5098b89168d4a4858844ae71fb7f0 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Thu Jun 08 21:21:38 CEST 2017 +#Tue Aug 15 17:27:55 CEST 2017 ULLimitExceeded=$org.olat.core.commons.modules.bc\:ULLimitExceeded feed.author=Auteur feed.error=Malheureusement, il s'est produit une erreur inattendue et le flux ne pourra pas \u00EAtre pr\u00E9sent\u00E9. @@ -21,10 +21,10 @@ feed.item.confirm.delete=Voulez-vous vraiment effacer cette entr\u00E9e? feed.item.draft=Ceci est un brouillon. feed.item.file.height=Hauteur feed.item.file.label=Fichier audio ou vid\u00E9o -feed.item.file.size.error=Format de nombre incorrect -feed.item.file.width=largeur feed.item.file.mandatory=Un \u00E9pisode demande un fichier audio ou video capable d'\u00EAtre jou\u00E9 avec flash. feed.item.file.name.notvalid=$org.olat.core.commons.modules.bc\:cfile.name.notvalid +feed.item.file.size.error=Format de nombre incorrect +feed.item.file.width=largeur feed.item.is.being.edited.by=Cette entr\u00E9e est en train d'\u00EAtre \u00E9dti\u00E9 par {0}. feed.item.original=Entr\u00E9e originale feed.item.scheduled.for=Publication pr\u00E9vue le {0} @@ -44,6 +44,7 @@ feed.startpage=Page de d\u00E9part feed.title.label=Titre feed.url.is.personal.warning=Cette URL est priv\u00E9e et ne doit pas \u00EAtre communiqu\u00E9 \u00E0 de tierces personnes. feed.url.label=Feed URL\: +notifications.entry.commented=La contribution "{0}" a \u00E9t\u00E9 comment\u00E9e par "{1}". notifications.entry.modified=La contribution "{0}" a \u00E9t\u00E9 modifi\u00E9e par {1} notifications.entry.published=La contribution "{0}" a \u00E9t\u00E9 publi\u00E9e par {1}. notifications.header=Nouvelles contributions du blog diff --git a/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_pt_BR.properties index 93900350a1d4abc21605358ee0a490e85ec162f6..2b382a0d81af655472177084f27a640f3386ddc6 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/webFeed/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Thu Jun 22 17:00:47 CEST 2017 +#Tue Sep 05 22:45:49 CEST 2017 ULLimitExceeded=$org.olat.core.commons.modules.bc\:ULLimitExceeded feed.author=Autor feed.error=Infelizmente, o "Feed" n\u00E3o pode ser exibido devido a um erro inesperado. @@ -21,9 +21,10 @@ feed.item.confirm.delete=Voc\u00EA realmente quer apagar esta entrada? feed.item.draft=Este \u00E9 apenas um rascunho. feed.item.file.height=altura feed.item.file.label=arquivo de \u00E1udio ou v\u00EDdeo +feed.item.file.mandatory=Um epis\u00F3dio requer um arquivo de \u00E1udio ou v\u00EDdeo que possa ser usado com o Flash. +feed.item.file.name.notvalid=$org.olat.core.commons.modules.bc\:cfile.name.notvalid feed.item.file.size.error=Formato de n\u00FAmero errado feed.item.file.width=largura -feed.item.file.name.notvalid=$org.olat.core.commons.modules.bc\:cfile.name.notvalid feed.item.is.being.edited.by=Esta entrada est\u00E1 sendo editada por {0}. feed.item.original=Entrada original feed.item.scheduled.for=Publica\u00E7\u00E3o prevista em {0} @@ -43,6 +44,7 @@ feed.startpage=Tela principal feed.title.label=T\u00EDtulo feed.url.is.personal.warning=Este URL \u00E9 privado e n\u00E3o deve ser transferido para terceiros. feed.url.label=Feed URL\: +notifications.entry.commented=A postagem "{0}" foi comentada por {1}. notifications.entry.modified=A postagem "{0}" foi modificada por {1}. notifications.entry.published=A publica\u00E7\u00E3o "{0}" foi publicada por {1}. notifications.header=Novas entradas do blog diff --git a/src/main/java/org/olat/modules/webFeed/ui/blog/BlogUIFactory.java b/src/main/java/org/olat/modules/webFeed/ui/blog/BlogUIFactory.java index 40baf9c5d6105a93f6adf4a2b90274ed9cb069da..cbb3812891ab12036e0c2f9b206f9aee76b459ca 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/blog/BlogUIFactory.java +++ b/src/main/java/org/olat/modules/webFeed/ui/blog/BlogUIFactory.java @@ -39,10 +39,10 @@ import org.olat.modules.webFeed.ui.FeedUIFactory; /** * UI factory for blogs. - * + * * <P> * Initial Date: Jun 8, 2009 <br> - * + * * @author gwassmann */ public class BlogUIFactory extends FeedUIFactory { @@ -102,4 +102,5 @@ public class BlogUIFactory extends FeedUIFactory { UserRequest ureq, WindowControl control) { return new BlogNodeEditController(courseNode, course, uce, ureq, control); } + } diff --git a/src/main/java/org/olat/modules/webFeed/ui/blog/_content/info.html b/src/main/java/org/olat/modules/webFeed/ui/blog/_content/info.html index 5b16a68fb687266d95053bc5712132cdb124bead..4b9a9f5c33b43c72b606d781a528d08b521766f1 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/blog/_content/info.html +++ b/src/main/java/org/olat/modules/webFeed/ui/blog/_content/info.html @@ -1,5 +1,5 @@ <div class="o_blog_info"> - #if ($callback.mayEditMetadata()) + #if ($r.available("feed.edit")) <div class="o_edit pull-right">$r.render("feed.edit")</div> #end <h2> @@ -7,18 +7,18 @@ $r.escapeHtml($!feed.getTitle()) </h2> #if ($helper.getImageUrl($feed) && $helper.getImageUrl($feed) != "") - <img class="o_media" src="$helper.getImageUrl($feed)?thumbnail=180x121" alt="Blog Image" /> + <img class="o_media" src="$helper.getImageUrl($feed)?thumbnail=180x121{$!supressCache}" alt="Blog Image" /> #end <div class="o_block"> #if ($!feed.getAuthor()) <div class="o_author">$r.translate("feed.author"): $r.escapeHtml($feed.getAuthor())</div> #end <div class="o_date">$r.translate("feed.last.change") $!helper.getLastModified($feed)</div> - #if ($feed.getDescription() != "") + #if ($!feed.getDescription() && $feed.getDescription() != "") <div class="o_desc o_info">$!helper.getFeedDescriptionForBrowser($feed)</div> #end - #if (!$feed.isUndefined() && $!feed.getDescription()) + #if (!$feed.isUndefined()) <div class="o_subscription"> <a href="$!helper.getFeedUrl()" class="o_nowrap" target="_blank"> <i class="o_icon o_icon-fw o_icon_rss"></i> diff --git a/src/main/java/org/olat/modules/webFeed/ui/blog/_content/posts.html b/src/main/java/org/olat/modules/webFeed/ui/blog/_content/posts.html index bb6371a33afdc1a8f33d9f4baafb242d560096be..7b0f07b2ae635ead99e88c26c49eed0c80f5c697 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/blog/_content/posts.html +++ b/src/main/java/org/olat/modules/webFeed/ui/blog/_content/posts.html @@ -4,8 +4,12 @@ $r.render("feed.add.item") </div> #end +#if ($callback.mayCreateItems() && $feed.isExternal()) + <div class="pull-right"> + $r.render("feed.external.url") + </div> +#end <div class="clearfix"></div> - #if ($items.size() == 0) <div class="o_blog_no_posts o_important"> <p> @@ -22,7 +26,7 @@ #end </div> #else - #foreach( $post in $helper.getItemsOnPage($items) ) + #foreach( $post in $helper.getItemsOnPage($items) ) <div class="o_post o_block_with_datecomp clearfix $!post.extraCSSClass()"> <div class="o_head"> #if (( $helper.isAuthor($post) && !$post.isDraft()) && $feed.isInternal() && $r.available("feed.artefact.item.$post.getGuid()")) @@ -42,7 +46,7 @@ </small> #end </h3> - <div class="o_meta"> + <div class="o_meta"> #set ( $info = $helper.getInfo($post) ) #if ( $info ) $info @@ -52,32 +56,32 @@ #end </div> </div> - + <div class="o_content o_user_content_block"> - $!helper.getItemDescriptionForBrowser($post) + $!helper.getItemDescriptionForBrowser($post) </div> - + <div class="o_block_footer"> <div class="clearfix"> <ul class="o_readmore list-inline pull-right"> - #if ( ($post.getContent() && $post.getContent() != "") + #if ( ($post.getContent() && $post.getContent() != "") || ($post.getEnclosure() && $post.getEnclosure() != "" ) ) <li>$r.render("link.to.$post.getGuid()")</li> #end #if ($feed.isExternal() && $post.getExternalLink()) <li><a href="$!post.getExternalLink()" target="_blank"> - $r.translate("feed.item.original") + $r.translate("feed.item.original") <i class="o_icon o_icon_start"></i> </a></li> #end </ul> - + #if ($r.available("commentsAndRating.${post.getGuid()}")) $r.render("commentsAndRating.${post.getGuid()}") #end </div> </div> - + #if($feed.isInternal()) <div class="o_button_group"> #if ($r.available("feed.edit.item.$post.getGuid()") && $r.visible("feed.edit.item.$post.getGuid()")) @@ -90,21 +94,34 @@ #end </div> #end - - <ul class="pagination"> - #if ( $helper.hasOlderItems($items) ) - <li> - $r.render("feed.older.items") - </li> - #end - #if ( $helper.hasNewerItems() ) - <li> - $r.render("feed.startpage") - </li> - <li> - $r.render("feed.newer.items") - </li> - #end - </ul> + + <div class="o_button_group"> + <ul class="pagination"> + <li> + #if ( $helper.hasOlderItems($items) ) + $r.getComponent("feed.older.items").setEnabled($true) + #else + $r.getComponent("feed.older.items").setEnabled($false) + #end + $r.render("feed.older.items") + </li> + <li> + #if ( $helper.hasNewerItems() ) + $r.getComponent("feed.startpage").setEnabled($true) + #else + $r.getComponent("feed.startpage").setEnabled($false) + #end + $r.render("feed.startpage") + </li> + <li> + #if ( $helper.hasNewerItems() ) + $r.getComponent("feed.newer.items").setEnabled($true) + #else + $r.getComponent("feed.newer.items").setEnabled($false) + #end + $r.render("feed.newer.items") + </li> + </ul> + </div> #end </div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/ui/blog/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/webFeed/ui/blog/_i18n/LocalStrings_de.properties index 1feb04fc5071a37fa6a5760b096e20b4e0b1a127..a463e301d0f7539c2e36e92f9b226cc39616f12c 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/blog/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/webFeed/ui/blog/_i18n/LocalStrings_de.properties @@ -6,24 +6,11 @@ blog.subscribe.to.this.feed = Diesen Blog abonnieren feed.author = Von feed.last.change = Letzte \u00c4nderung am -feed.make.internal = Eintr\u00E4ge selbst erstellen +feed.make.internal = Eintr\u00E4ge selbst erstellen feed.make.external = Einen bestehenden externen Blog einbinden feed.edit = Blog bearbeiten feed.add.item = Neuen Eintrag erstellen feed.edit.item = Eintrag bearbeiten feed.older.items = \u00c4ltere Eintr\u00E4ge feed.newer.items = Neuere Eintr\u00E4ge - - - - - - - - - - - - - - +feed.external.url=URL bearbeiten diff --git a/src/main/java/org/olat/modules/webFeed/ui/blog/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/webFeed/ui/blog/_i18n/LocalStrings_en.properties index dabd154432d96769320e252a78eebe616493d00c..964e064656fbb658c44753027e4ed7890d9a9ed9 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/blog/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/webFeed/ui/blog/_i18n/LocalStrings_en.properties @@ -4,17 +4,6 @@ blog.has.no.episodes=There are no entries for this blog. blog.internal.or.external=You can either create your own entries or include an external blog. When including an external blog its entries will be displayed. blog.is.being.edited.by=This blog is being edited by {0}. blog.subscribe.to.this.feed=Subscribe to this blog - - - - - - - - - - - feed.add.item=Create new entry feed.author=By feed.edit=Edit blog @@ -24,3 +13,4 @@ feed.make.external=Embed an already existing external blog feed.make.internal=Create your own entries feed.newer.items=Recent entries feed.older.items=Older entries +feed.external.url=Change URL \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/ui/podcast/PodcastUIFactory.java b/src/main/java/org/olat/modules/webFeed/ui/podcast/PodcastUIFactory.java index acf069cf0c5e8753697e81dcd01ffde9e70c7d8d..e7fe9ea960dadee220fe06f6240c1e2a915a518a 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/podcast/PodcastUIFactory.java +++ b/src/main/java/org/olat/modules/webFeed/ui/podcast/PodcastUIFactory.java @@ -39,10 +39,10 @@ import org.olat.modules.webFeed.ui.FeedUIFactory; /** * UI factory for podcast controllers. - * + * * <P> * Initial Date: Jun 8, 2009 <br> - * + * * @author gwassmann */ public class PodcastUIFactory extends FeedUIFactory { @@ -62,46 +62,47 @@ public class PodcastUIFactory extends FeedUIFactory { public static PodcastUIFactory getInstance(Locale locale) { return new PodcastUIFactory(locale); } - + @Override public Translator getTranslator() { return translator; } - + @Override public void setTranslator(Locale locale) { final Translator fallbackTans = Util.createPackageTranslator(FeedMainController.class, locale); translator = Util.createPackageTranslator(PodcastUIFactory.class, locale, fallbackTans); } - + @Override public VelocityContainer createInfoVelocityContainer(BasicController controller) { return new VelocityContainer(VC_INFO_NAME, this.getClass(), VC_INFO_NAME, translator, controller); } - + @Override public VelocityContainer createItemsVelocityContainer(BasicController controller) { return new VelocityContainer(VC_ITEMS_NAME, this.getClass(), "episodes", translator, controller); } - + @Override public VelocityContainer createItemVelocityContainer(BasicController controller) { return new VelocityContainer(VC_ITEM_NAME, this.getClass(), "episode", translator, controller); } - + @Override public VelocityContainer createRightColumnVelocityContainer(BasicController controller) { return new VelocityContainer(VC_RIGHT_NAME, this.getClass(), VC_RIGHT_NAME, translator, controller); } - + @Override public FormBasicController createItemFormController(UserRequest ureq, WindowControl wControl, Item item) { return new EpisodeFormController(ureq, wControl, item, getTranslator()); } - + @Override public TabbableController createNodeEditController(AbstractFeedCourseNode courseNode, ICourse course, UserCourseEnvironment uce, UserRequest ureq, WindowControl control) { return new PodcastNodeEditController(courseNode, course, uce, ureq, control); } + } diff --git a/src/main/java/org/olat/modules/webFeed/ui/podcast/_content/episodes.html b/src/main/java/org/olat/modules/webFeed/ui/podcast/_content/episodes.html index f7f0e5d1bfdad74053fe7262af604b7170b7080c..ecb79a686627c6807c0b74c2a9903c827d1ed875 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/podcast/_content/episodes.html +++ b/src/main/java/org/olat/modules/webFeed/ui/podcast/_content/episodes.html @@ -4,7 +4,11 @@ $r.render("feed.add.item") </div> #end -<h4 class="o_title">$r.translate("podcast.episodes")</h4> +#if ($callback.mayCreateItems() && $feed.isExternal()) + <div class="pull-right"> + $r.render("feed.external.url") + </div> +#end <div class="clearfix"></div> #if ($items.size() == 0) @@ -39,14 +43,14 @@ $r.escapeHtml($episode.getTitle()) #end <i class="o_icon o_icon_$helper.getMediaType($episode.getEnclosure())"></i> - + #if($r.available("date.$episode.getGuid()")) <small> $r.render("date.$episode.getGuid()") </small> #end </h3> - <div class="o_meta"> + <div class="o_meta"> #set ( $info = $helper.getInfo($episode) ) #if ( $info ) $info @@ -56,18 +60,18 @@ #end </div> </div> - + <div class="o_content o_user_content_block"> $!helper.getItemDescriptionForBrowser($episode) - + #set($podId = $r.getUniqueId()) - #if ($!episode.getEnclosure()) + #if ($!episode.getEnclosure()) <div class="o_block_large_top o_enclosure"> <div id="o_podcast_${podId}_episode" class="o_podcast_$!helper.getMediaType($episode.getEnclosure())"></div> - + <div class="o_block_top"> <a href="$!helper.getMediaUrl($episode)" target="_blank"> - <i class="o_icon o_icon-fw o_filetype_$!helper.getMediaType($episode.getEnclosure())"></i> + <i class="o_icon o_icon-fw o_filetype_$!helper.getMediaType($episode.getEnclosure())"></i> $r.translate("podcast.episode.download") </a> </div> @@ -85,7 +89,7 @@ #end </div> - + <div class="o_block_footer"> <div class="clearfix"> <ul class="o_readmore list-inline pull-right"> @@ -94,18 +98,18 @@ #end #if ($feed.isExternal() && $episode.getExternalLink()) <li><a href="$!episode.getExternalLink()" target="_blank"> - $r.translate("feed.item.original") + $r.translate("feed.item.original") <i class="o_icon o_icon_start"></i> </a></li> #end </ul> - + #if ($r.available("commentsAndRating.${episode.getGuid()}")) $r.render("commentsAndRating.${episode.getGuid()}") #end </div> </div> - + #if($feed.isInternal()) <div class="o_button_group"> #if ($r.available("feed.edit.item.$episode.getGuid()") && $r.visible("feed.edit.item.$episode.getGuid()")) @@ -118,21 +122,34 @@ #end </div> #end - - <ul class="pagination"> - #if ( $helper.hasOlderItems($items) ) - <li> - $r.render("feed.older.items") - </li> - #end - #if ( $helper.hasNewerItems() ) - <li> - $r.render("feed.startpage") - </li> - <li> - $r.render("feed.newer.items") - </li> - #end - </ul> + + <div class="o_button_group"> + <ul class="pagination"> + <li> + #if ( $helper.hasOlderItems($items) ) + $r.getComponent("feed.older.items").setEnabled($true) + #else + $r.getComponent("feed.older.items").setEnabled($false) + #end + $r.render("feed.older.items") + </li> + <li> + #if ( $helper.hasNewerItems() ) + $r.getComponent("feed.startpage").setEnabled($true) + #else + $r.getComponent("feed.startpage").setEnabled($false) + #end + $r.render("feed.startpage") + </li> + <li> + #if ( $helper.hasNewerItems() ) + $r.getComponent("feed.newer.items").setEnabled($true) + #else + $r.getComponent("feed.newer.items").setEnabled($false) + #end + $r.render("feed.newer.items") + </li> + </ul> + </div> #end </div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/ui/podcast/_content/info.html b/src/main/java/org/olat/modules/webFeed/ui/podcast/_content/info.html index 146817fc8cb50f38b975e7353fc1df3d576f5ea8..71d0fa39c67f9b21ffeb7b758ec14fcc6b92704d 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/podcast/_content/info.html +++ b/src/main/java/org/olat/modules/webFeed/ui/podcast/_content/info.html @@ -1,5 +1,5 @@ <div class="o_podcast_info"> - #if ($callback.mayEditMetadata()) + #if ($r.available("feed.edit")) <div class="o_feed_edit pull-right">$r.render("feed.edit")</div> #end <h2> @@ -7,18 +7,18 @@ $r.escapeHtml($!feed.getTitle()) </h2> #if ($helper.getImageUrl($feed) && $helper.getImageUrl($feed) != "") - <img class="o_media" src="$helper.getImageUrl($feed)?thumbnail=180x121" alt="Podcast Icon" /> + <img class="o_media" src="$helper.getImageUrl($feed)?thumbnail=180x121{$!supressCache}" alt="Podcast Icon" /> #end <div class="o_block"> #if ($!feed.getAuthor()) <div class="o_author">$r.translate("feed.author"): $r.escapeHtml($feed.getAuthor())</div> #end <div class="o_date">$r.translateWithPackage("org.olat.modules.webFeed.ui.blog","feed.last.change") $!helper.getLastModified($feed) </div> - #if ($!feed.getDescription()) + #if ($!feed.getDescription() && $feed.getDescription() != "") <div class="o_desc o_info">$!helper.getFeedDescriptionForBrowser($feed)</div> #end - #if ( !$feed.isUndefined() && $helper.getFeedUrl() && $!feed.getDescription() ) + #if ( !$feed.isUndefined() && $helper.getFeedUrl() ) <div class="o_subscription"> $r.render("feedUrlComponent") </div> diff --git a/src/main/java/org/olat/modules/webFeed/ui/podcast/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/webFeed/ui/podcast/_i18n/LocalStrings_de.properties index 986a5530116d099b92342022fa3f051c22f0e91b..224580e2138e981a8b9154a4095c398bcc5d7318 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/podcast/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/webFeed/ui/podcast/_i18n/LocalStrings_de.properties @@ -9,13 +9,14 @@ podcast.subscribe.feed=iOS podcast.episode.download = Episode herunterladen podcast.episodes = Episoden ULLimitExceeded=$org.olat.core.commons.modules.bc\:ULLimitExceeded -feed.make.internal = Episoden selbst erstellen +feed.make.internal = Episoden selbst erstellen feed.make.external = Einen bestehenden externen Podcast einbinden feed.edit = Podcast bearbeiten feed.add.item = Episode hinzuf\u00FCgen feed.edit.item = Episode bearbeiten feed.older.items = \u00c4ltere Episoden feed.newer.items = Neuere Episoden +feed.external.url=URL bearbeiten diff --git a/src/main/java/org/olat/modules/webFeed/ui/podcast/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/webFeed/ui/podcast/_i18n/LocalStrings_en.properties index 8a5702a522b72bbe7ab4de1617f7a489e682e938..4afc36eec817ee35fabc154005bac69967f17d4c 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/podcast/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/webFeed/ui/podcast/_i18n/LocalStrings_en.properties @@ -19,7 +19,7 @@ feed.make.external=Embed an already existing external podcast feed.make.internal=Create your own episode feed.newer.items=Recent episodes feed.older.items=Older episodes - +feed.external.url=Change URL podcast.episode.download=Download episodes podcast.episodes=Episodes podcast.has.no.episodes=There are no episodes for this podcast. diff --git a/src/main/java/org/olat/modules/wiki/Wiki.java b/src/main/java/org/olat/modules/wiki/Wiki.java index 10b632b2730da7b8c0d7f2494a15efa7b893632a..ed4d92c1c1fb4a42a49dd1bd339692294cd9965e 100644 --- a/src/main/java/org/olat/modules/wiki/Wiki.java +++ b/src/main/java/org/olat/modules/wiki/Wiki.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -100,18 +101,42 @@ public class Wiki implements WikiContainer, Serializable { * @return the wikiPage or null if not found */ public WikiPage getPage(String pageId) { - WikiPage page = null; - page = wikiPages.get(pageId); + WikiPage page = getPageById(pageId); // try also the pageName, may be someone tried to access with the name // instead of the page id - if (page == null) page = wikiPages.get(this.generatePageId(pageId)); - if (page == null) page = wikiPages.get(this.generatePageId(FilterUtil.normalizeWikiLink(pageId))); + if (page == null) { + page = getPageById(generatePageId(pageId)); + } + if (page == null) { + page = getPageById(generatePageId(FilterUtil.normalizeWikiLink(pageId))); + } if (page == null) { page = new WikiPage(WikiPage.WIKI_ERROR); page.setContent("wiki.error.page.not.found"); } return page; } + + /** + * The method check the specified pageId with the + * id in the map and if it doesn't found a page, check + * all pages for an alternative ids. + * + * @param pageId + * @return + */ + private final WikiPage getPageById(String pageId) { + WikiPage page = wikiPages.get(pageId); + if(page == null) { + for(WikiPage wikiPage:wikiPages.values()) { + if(wikiPage.matchIds(pageId)) { + page = wikiPage; + break; + } + } + } + return page; + } /** * @param pageId @@ -123,7 +148,9 @@ public class Wiki implements WikiContainer, Serializable { public WikiPage getPage(String pageId, boolean loadContent) { WikiPage page = getPage(pageId); // if not empty content is already loaded - if (!page.getContent().equals("")) return page; + if (!page.getContent().equals("")) { + return page; + } if (loadContent) { VFSLeaf leaf = (VFSLeaf) pageContainer.resolve(page.getPageId() + "." + WikiManager.WIKI_FILE_SUFFIX); page.setContent(FileUtils.load(leaf.getInputStream(), "utf-8")); @@ -133,7 +160,9 @@ public class Wiki implements WikiContainer, Serializable { public void addPage(WikiPage page) { String pageId = page.getPageId(); - if (!wikiPages.containsKey(pageId)) wikiPages.put(pageId, page); + if (!wikiPages.containsKey(pageId)) { + wikiPages.put(pageId, page); + } } /** @@ -141,6 +170,7 @@ public class Wiki implements WikiContainer, Serializable { * @see WikiPage.generateId(name) as pages are stored by pageId * @return */ + @Override public boolean pageExists(String pageId) { if( log.isDebug() ) { boolean exists = wikiPages.containsKey(pageId); @@ -151,10 +181,24 @@ public class Wiki implements WikiContainer, Serializable { boolean isImage = pageId.startsWith(IMAGE_NAMESPACE); boolean isMedia = pageId.startsWith(MEDIA_NAMESPACE); if ( isImage || isMedia ) { - if (isImage) return mediaFileExists(pageId.substring(IMAGE_NAMESPACE.length(), pageId.length())); - if (isMedia) return mediaFileExists(pageId.substring(MEDIA_NAMESPACE.length(), pageId.length())); + if (isImage) { + return mediaFileExists(pageId.substring(IMAGE_NAMESPACE.length(), pageId.length())); + } + if (isMedia) { + return mediaFileExists(pageId.substring(MEDIA_NAMESPACE.length(), pageId.length())); + } } - return wikiPages.containsKey(pageId); + + boolean exists = wikiPages.containsKey(pageId); + if(!exists) { + for(WikiPage wikiPage:wikiPages.values()) { + if(wikiPage.matchIds(pageId)) { + exists = true; + break; + } + } + } + return exists; } protected void removePage(WikiPage page) { @@ -164,7 +208,7 @@ public class Wiki implements WikiContainer, Serializable { } protected int getNumberOfPages() { - return this.wikiPages.size(); + return wikiPages.size(); } protected List<ChangeInfo> getDiff(WikiPage page, int version1, int version2) { @@ -181,7 +225,7 @@ public class Wiki implements WikiContainer, Serializable { } protected List<WikiPage> getHistory(WikiPage page) { - List<WikiPage> versions = new ArrayList<WikiPage>(); + List<WikiPage> versions = new ArrayList<>(); List<VFSItem> leafs = versionsContainer.getItems(new VFSLeafFilter()); if (leafs.size() > 0) { for (Iterator<VFSItem> iter = leafs.iterator(); iter.hasNext();) { @@ -220,10 +264,8 @@ public class Wiki implements WikiContainer, Serializable { public static WikiPage assignPropertiesToPage(VFSLeaf leaf) { Properties p = new Properties(); if (leaf != null) { - try { - InputStream is =leaf.getInputStream(); + try(InputStream is =leaf.getInputStream()) { p.load(is); - is.close(); } catch (IOException e) { throw new OLATRuntimeException("Wiki page couldn't be read! Pagename:"+leaf.getName(), e); } @@ -232,7 +274,16 @@ public class Wiki implements WikiContainer, Serializable { log.warn("wiki properties page is persent but without content. Name:"+leaf.getName()); return null; } - WikiPage page = new WikiPage(pageName); + + String initialPageName = p.getProperty(WikiManager.INITIAL_PAGENAME); + WikiPage page = new WikiPage(pageName, initialPageName); + String oldPageNames = p.getProperty(WikiManager.OLD_PAGENAME); + if(StringHelper.containsNonWhitespace(oldPageNames)) { + String[] names = oldPageNames.split("[,]"); + if(names.length > 0) { + page.setOldPageNames(Arrays.asList(names)); + } + } page.setCreationTime(p.getProperty(WikiManager.C_TIME)); page.setVersion(p.getProperty(WikiManager.VERSION)); page.setForumKey(p.getProperty(WikiManager.FORUM_KEY)); @@ -262,17 +313,16 @@ public class Wiki implements WikiContainer, Serializable { } public String getAllPageNamesSorted() { - ArrayList<WikiPage> pages = new ArrayList<WikiPage>(wikiPages.values()); + List<WikiPage> pages = new ArrayList<>(wikiPages.values()); Collections.sort(pages, WikiPageSort.PAGENAME_ORDER); StringBuilder sb = new StringBuilder(); - for (Iterator<WikiPage> iter = pages.iterator(); iter.hasNext();) { - WikiPage page = iter.next(); + for (WikiPage page:pages) { if (!page.getPageName().startsWith("O_")) { sb.append("* "); if(log.isDebug()) sb.append(page.getPageId()).append(" --> "); - sb.append("[["); - sb.append(page.getPageName()); - sb.append("]]\n"); + sb.append("[[") + .append(page.getPageName()) + .append("]]\n"); } } return sb.toString(); @@ -281,7 +331,7 @@ public class Wiki implements WikiContainer, Serializable { protected String getRecentChanges(Locale locale) { if(locale == null) throw new AssertException("param was null which is not allowed"); final int MAX_RESULTS = 5; - ArrayList<WikiPage> pages = new ArrayList<WikiPage>(wikiPages.values()); + List<WikiPage> pages = new ArrayList<>(wikiPages.values()); Collections.sort(pages, WikiPageSort.MODTIME_ORDER); StringBuilder sb = new StringBuilder(512); int counter = 0; @@ -325,6 +375,7 @@ public class Wiki implements WikiContainer, Serializable { /** * @see org.olat.core.commons.modules.wiki.WikiContainer#generatePageId(java.lang.String) */ + @Override public String generatePageId(String pageName) { if(log.isDebug()) log.debug("Generating page id from page name: "+pageName +" to id: "+WikiManager.generatePageId(pageName)); return WikiManager.generatePageId(pageName); diff --git a/src/main/java/org/olat/modules/wiki/WikiMainController.java b/src/main/java/org/olat/modules/wiki/WikiMainController.java index a7c12ceec96435a27e58cdec078c45a2e33fd817..945a00ad300fa1f20db562a8838f21d653d7f6bb 100644 --- a/src/main/java/org/olat/modules/wiki/WikiMainController.java +++ b/src/main/java/org/olat/modules/wiki/WikiMainController.java @@ -98,6 +98,8 @@ import org.olat.modules.fo.manager.ForumManager; import org.olat.modules.fo.ui.ForumController; import org.olat.modules.portfolio.PortfolioV2Module; import org.olat.modules.portfolio.ui.component.MediaCollectorComponent; +import org.olat.modules.wiki.WikiPageSort.WikiFileComparator; +import org.olat.modules.wiki.WikiPageSort.WikiPageNameComparator; import org.olat.modules.wiki.gui.components.wikiToHtml.ErrorEvent; import org.olat.modules.wiki.gui.components.wikiToHtml.FilterUtil; import org.olat.modules.wiki.gui.components.wikiToHtml.RequestImageEvent; @@ -110,6 +112,7 @@ import org.olat.modules.wiki.portfolio.WikiMediaHandler; import org.olat.modules.wiki.versioning.ChangeInfo; import org.olat.modules.wiki.versioning.HistoryTableDateModel; import org.olat.portfolio.EPUIFactory; +import org.olat.search.SearchModule; import org.olat.search.SearchServiceUIFactory; import org.olat.search.SearchServiceUIFactory.DisplayOption; import org.olat.util.logging.activity.LoggingResourceable; @@ -181,6 +184,8 @@ public class WikiMainController extends BasicController implements CloneableCont // indicates if user is already on image-detail-view-page (OLAT-6233) private boolean isImageDetailView = false; @Autowired + private SearchModule searchModule; + @Autowired private WikiMediaHandler wikiMediaHandler; @Autowired private PortfolioV2Module portfolioModule; @@ -193,7 +198,6 @@ public class WikiMainController extends BasicController implements CloneableCont this.ores = ores; this.securityCallback = securityCallback; this.subsContext = securityCallback.getSubscriptionContext(); - boolean guestOnly = ureq.getUserSession().getRoles().isGuestOnly(); WikiPage page = null; Wiki wiki = getWiki(); @@ -212,9 +216,10 @@ public class WikiMainController extends BasicController implements CloneableCont if (initialPageName != null && wiki.pageExists(WikiManager.generatePageId(initialPageName))) { page = wiki.getPage(initialPageName, true); } else { - page = wiki.getPage(WikiPage.WIKI_INDEX_PAGE); - if (initialPageName != null) + page = wiki.getPage(WikiPage.WIKI_INDEX_PAGE, true); + if (initialPageName != null) { showError("wiki.error.page.not.found"); + } } this.pageId = page.getPageId(); @@ -273,7 +278,7 @@ public class WikiMainController extends BasicController implements CloneableCont content.put("navigation", navigationContent); // search - if (!guestOnly) { + if (searchModule.isSearchAllowed(ureq.getUserSession().getRoles())) { SearchServiceUIFactory searchServiceUIFactory = (SearchServiceUIFactory) CoreSpringFactory .getBean(SearchServiceUIFactory.class); searchCtrl = searchServiceUIFactory.createInputController(ureq, wControl, DisplayOption.STANDARD, null); @@ -325,8 +330,8 @@ public class WikiMainController extends BasicController implements CloneableCont JSAndCSSComponent js = new JSAndCSSComponent("js", new String[] { "js/openolat/wiki.js" }, null); content.put("js", js); - editContent.contextPut("fileList", wiki.getMediaFileList()); - editContent.contextPut("linkList", wiki.getListOfAllPageNames()); + + updateFileAndLinkList(wiki); tabs.addTab(translate("tab.edit"), editContent); @@ -361,6 +366,15 @@ public class WikiMainController extends BasicController implements CloneableCont // set pageId to the latest used this.pageId = page.getPageId(); } + + private void updateFileAndLinkList(Wiki wiki) { + List<VFSItem> mediaFiles = wiki.getMediaFileList(); + Collections.sort(mediaFiles, new WikiFileComparator(getLocale())); + editContent.contextPut("fileList", mediaFiles); + List<String> allPages = wiki.getListOfAllPageNames(); + Collections.sort(allPages, new WikiPageNameComparator(getLocale())); + editContent.contextPut("linkList", allPages); + } private void updateWikiMenu(Wiki wiki) { Collection<String> links = wiki.getListOfAllPageNames(); @@ -507,8 +521,9 @@ public class WikiMainController extends BasicController implements CloneableCont && !(event instanceof RequestImageEvent)) { page = wiki.getPage(pageId, true); // set recent page id to the page currently used - if (page != null) + if (page != null) { pageId = page.getPageId(); + } } if (source == content) { @@ -558,7 +573,7 @@ public class WikiMainController extends BasicController implements CloneableCont ************************************************************************/ if (command.equals(ACTION_EDIT_MENU)) { page = wiki.getPage(WikiPage.WIKI_MENU_PAGE); - editContent.contextPut("linkList", wiki.getListOfAllPageNames()); + updateFileAndLinkList(wiki); tryToSetEditLock(page, ureq, ores); updatePageContext(ureq, page); tabs.setSelectedPane(ureq, 2); @@ -571,7 +586,7 @@ public class WikiMainController extends BasicController implements CloneableCont openLastChangesPage(ureq, wiki); } else if (source == editMenuButton) { page = wiki.getPage(WikiPage.WIKI_MENU_PAGE); - editContent.contextPut("linkList", wiki.getListOfAllPageNames()); + updateFileAndLinkList(wiki); tryToSetEditLock(page, ureq, ores); updatePageContext(ureq, page); // wikiEditForm.setPage(page); @@ -634,8 +649,7 @@ public class WikiMainController extends BasicController implements CloneableCont * tabbed pane change to edit tab **********************************************************************/ wikiEditForm.resetUpdateComment(); - editContent.contextPut("linkList", wiki.getListOfAllPageNames()); - editContent.contextPut("fileList", wiki.getMediaFileList()); + updateFileAndLinkList(wiki); // try to edit acquire lock for this page tryToSetEditLock(page, ureq, ores); } else if (command.equals(TabbedPaneChangedEvent.TAB_CHANGED) && compName.equals("vc_versions")) { @@ -880,7 +894,7 @@ public class WikiMainController extends BasicController implements CloneableCont if (event.getCommand().equals(FolderEvent.UPLOAD_EVENT)) { FolderEvent fEvent = (FolderEvent) event; createMediaMetadataFile(fEvent.getFilename(), ureq.getIdentity().getKey()); - editContent.contextPut("fileList", wiki.getMediaFileList()); + updateFileAndLinkList(wiki); } cmc.deactivate(); cleanUp(); @@ -921,7 +935,7 @@ public class WikiMainController extends BasicController implements CloneableCont TableMultiSelectEvent tmse = (TableMultiSelectEvent) event; if (tmse.getAction().equals(ACTION_DELETE_MEDIAS)) { deleteMediaFile(mediaFilesTableModel.getObjects(tmse.getSelection()), ureq); - editContent.contextPut("fileList", wiki.getMediaFileList()); + updateFileAndLinkList(wiki); } } } else if (source == archiveWikiDialogCtr) { diff --git a/src/main/java/org/olat/modules/wiki/WikiManager.java b/src/main/java/org/olat/modules/wiki/WikiManager.java index 5f40239ff40be51af49b0ed2c2e6cce8502703e6..54cf14fdeea3b28e8036af362ae82afa9ac3196a 100644 --- a/src/main/java/org/olat/modules/wiki/WikiManager.java +++ b/src/main/java/org/olat/modules/wiki/WikiManager.java @@ -92,15 +92,19 @@ public class WikiManager { public static final String MODIFY_AUTHOR = "modify.author"; public static final String M_TIME = "mTime"; public static final String INITIAL_AUTHOR = "initial.author"; + public static final String INITIAL_PAGENAME = "initial.pagename"; public static final String FORUM_KEY = "forum.key"; public static final String VERSION = "version"; public static final String C_TIME = "cTime"; public static final String PAGENAME = "pagename"; + public static final String OLD_PAGENAME = "old.pagenames"; private static WikiManager instance; public static final String WIKI_RESOURCE_FOLDER_NAME = "wiki"; public static final String VERSION_FOLDER_NAME = "versions"; public static final String WIKI_FILE_SUFFIX = "wp"; + public static final String WIKI_DOT_FILE_SUFFIX = "." + WIKI_FILE_SUFFIX; public static final String WIKI_PROPERTIES_SUFFIX = "properties"; + public static final String WIKI_DOT_PROPERTIES_SUFFIX = "." + WIKI_PROPERTIES_SUFFIX; public static final String UPDATE_COMMENT = "update.comment"; //o_clusterNOK cache : 08.04.08/cg Not tested in cluster-mode @@ -199,20 +203,19 @@ public class WikiManager { */ private final static void resetAndCopyProperties(Path file, Path destFile) { Properties props = new Properties(); - try(InputStream inStream = Files.newInputStream(file); - OutputStream outStream = Files.newOutputStream(destFile)) { - - props.load(inStream); - props.setProperty(VERSION, "0"); - props.setProperty(FORUM_KEY, "0"); - props.setProperty(MODIFY_AUTHOR, "0"); - props.setProperty(UPDATE_COMMENT, "0"); - props.setProperty(VIEW_COUNT, "0"); - props.setProperty(M_TIME, "0"); - props.store(outStream, ""); - } catch(Exception e) { - log.error("", e); - } + try (InputStream inStream = Files.newInputStream(file); + OutputStream outStream = Files.newOutputStream(destFile)) { + props.load(inStream); + props.setProperty(VERSION, "0"); + props.setProperty(FORUM_KEY, "0"); + props.setProperty(MODIFY_AUTHOR, "0"); + props.setProperty(UPDATE_COMMENT, "0"); + props.setProperty(VIEW_COUNT, "0"); + props.setProperty(M_TIME, "0"); + props.store(outStream, ""); + } catch (Exception e) { + log.error("", e); + } } /** @@ -248,9 +251,8 @@ public class WikiManager { String filename = file.getFileName().toString(); if(filename.endsWith(WikiManager.WIKI_PROPERTIES_SUFFIX)) { - final Path destFile = Paths.get(destDir.toString(), relFile.toString()); - resetAndCopyProperties(file, destFile); - + final Path destFile = Paths.get(destDir.toString(), relFile.toString()); + resetAndCopyProperties(file, destFile); } else if (filename.endsWith(WIKI_FILE_SUFFIX)) { final Path destFile = Paths.get(destDir.toString(), relFile.toString()); Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING); @@ -305,10 +307,12 @@ public class WikiManager { throws IOException { String filename = file.getFileName().toString(); if(filename.endsWith(WikiManager.WIKI_PROPERTIES_SUFFIX)) { - final Path destFile = Paths.get(wikiDir.toString(), file.toString()); - resetAndCopyProperties(file, destFile); + String f = convertAlternativeFilename(file.toString()); + final Path destFile = Paths.get(wikiDir.toString(), f); + resetAndCopyProperties(file, destFile); } else if (filename.endsWith(WIKI_FILE_SUFFIX)) { - final Path destFile = Paths.get(wikiDir.toString(), file.toString()); + String f = convertAlternativeFilename(file.toString()); + final Path destFile = Paths.get(wikiDir.toString(), f); Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING); } else if (!filename.contains(WIKI_FILE_SUFFIX + "-") && !filename.contains(WIKI_PROPERTIES_SUFFIX + "-")) { @@ -321,9 +325,9 @@ public class WikiManager { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - final Path dirToCreate = Paths.get(destDir.toString(), dir.toString()); + final Path dirToCreate = Paths.get(destDir.toString(), dir.toString()); if(Files.notExists(dirToCreate)){ - Files.createDirectory(dirToCreate); + Files.createDirectory(dirToCreate); } return FileVisitResult.CONTINUE; } @@ -449,7 +453,7 @@ public class WikiManager { // due to a bug we have to rename some pages that start with an non // ASCII lowercase letter String idOutOfFileName = propertiesFile.getName().substring(0, propertiesFile.getName().indexOf(".")); - if (!page.getPageId().equals(idOutOfFileName)) { + if (!page.matchIds(idOutOfFileName)) { // rename corrupt prop file propertiesFile.rename(page.getPageId() + "." + WikiManager.WIKI_PROPERTIES_SUFFIX); // load content and delete corrupt content file @@ -665,6 +669,31 @@ public class WikiManager { throw new OLATRuntimeException(WikiManager.class, "Encoding UTF-8 not supported by your platform!", e); } } + + public static String convertAlternativeFilename(String id) { + String convertedId = id; + if(id != null) { + if(id.endsWith(WIKI_DOT_FILE_SUFFIX)) { + convertedId = convertAlternativeFilename(id, WIKI_DOT_FILE_SUFFIX); + } else if(id.endsWith(WIKI_DOT_PROPERTIES_SUFFIX)) { + convertedId = convertAlternativeFilename(id, WIKI_DOT_PROPERTIES_SUFFIX); + } + } + return convertedId; + } + + private static String convertAlternativeFilename(String id, String suffix) { + char[] idChars = id.toCharArray(); + int indexLast = idChars.length - suffix.length() - 1; + if(idChars[indexLast] == '_') { + idChars[indexLast] = '='; + if(idChars[indexLast - 1] == '_') { + idChars[indexLast - 1] = '='; + } + return new String(idChars); + } + return id; + } /** * @param ores diff --git a/src/main/java/org/olat/modules/wiki/WikiPage.java b/src/main/java/org/olat/modules/wiki/WikiPage.java index fefbab8380bd699e6aebca5567e5db89b17f3dfc..683c3eecc36a84d143ce214eae231ba04b717a5c 100644 --- a/src/main/java/org/olat/modules/wiki/WikiPage.java +++ b/src/main/java/org/olat/modules/wiki/WikiPage.java @@ -25,6 +25,10 @@ package org.olat.modules.wiki; +import java.util.ArrayList; +import java.util.List; + +import org.olat.core.util.StringHelper; import org.olat.modules.wiki.gui.components.wikiToHtml.FilterUtil; /** @@ -43,6 +47,9 @@ public class WikiPage { public static final String WIKI_ERROR = "O_error"; private String content = ""; private String pageName; + private String initialPageName; + private List<String> oldPageNames; + private List<String> alternativeIds; private String pageId; private long forumKey = 0; private boolean dirty = false; @@ -58,13 +65,24 @@ public class WikiPage { // remove or find better solution which works also in a cluster cache scenario private int viewCount = 0; + public WikiPage(String name) { + this(name, null); + } + /** * @param id * @param name */ - public WikiPage(String name) { - this.pageName = FilterUtil.normalizeWikiLink(name); - this.pageId = WikiManager.generatePageId(pageName); + public WikiPage(String name, String initialPageName) { + pageName = FilterUtil.normalizeWikiLink(name); + if(StringHelper.containsNonWhitespace(initialPageName)) { + pageId = WikiManager.generatePageId(initialPageName); + if(StringHelper.containsNonWhitespace(pageName)) { + addAlternativeId(WikiManager.generatePageId(pageName)); + } + } else { + pageId = WikiManager.generatePageId(pageName); + } } public String getContent() { @@ -97,6 +115,52 @@ public class WikiPage { return pageName; } + public String getInitialPageName() { + return initialPageName; + } + + public List<String> getOldPageNames() { + return oldPageNames; + } + + public void setOldPageNames(List<String> oldPageNames) { + this.oldPageNames = oldPageNames; + if(oldPageNames != null) { + for(String oldPageName:oldPageNames) { + addAlternativeId(WikiManager.generatePageId(oldPageName)); + } + } + } + + private void addAlternativeId(String id) { + if(alternativeIds == null) { + alternativeIds = new ArrayList<>(); + } + alternativeIds.add(id); + } + + /** + * + * Check if the specified id matchs the id + * generated from the pagename, initial pagen name or + * the old page names properties. + * + * @param id + * @return + */ + public boolean matchIds(String id) { + boolean found = pageId.equals(id); + if(!found && alternativeIds != null) { + for(String alternativeId:alternativeIds) { + if(alternativeId.equals(id)) { + found = true; + break; + } + } + } + return found; + } + public boolean isDirty() { return dirty; } @@ -110,7 +174,13 @@ public class WikiPage { * filesystem. */ protected String getPageId() { - if (pageId == null) pageId = WikiManager.generatePageId(pageName); + if (pageId == null) { + if(StringHelper.containsNonWhitespace(initialPageName)) { + pageId = WikiManager.generatePageId(initialPageName); + } else { + pageId = WikiManager.generatePageId(pageName); + } + } return pageId; } @@ -202,6 +272,7 @@ public class WikiPage { this.updateComment = updateComment; } + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("\n"); diff --git a/src/main/java/org/olat/modules/wiki/WikiPageSort.java b/src/main/java/org/olat/modules/wiki/WikiPageSort.java index 3b0e34d1cc00dc9eb696c222bb468b798b60f6b6..2c0b69c3020c450425f97324e9970d21f99c818d 100644 --- a/src/main/java/org/olat/modules/wiki/WikiPageSort.java +++ b/src/main/java/org/olat/modules/wiki/WikiPageSort.java @@ -25,7 +25,11 @@ package org.olat.modules.wiki; +import java.text.Collator; import java.util.Comparator; +import java.util.Locale; + +import org.olat.core.util.vfs.VFSItem; /** * Description:<br> @@ -40,7 +44,7 @@ public class WikiPageSort { * use this comparator if you like a list of sorted pages by pageName */ protected static final Comparator<WikiPage> PAGENAME_ORDER = new Comparator<WikiPage>() { - + @Override public int compare(WikiPage p1, WikiPage p2) { return p1.getPageName().compareTo(p2.getPageName()); } @@ -50,10 +54,57 @@ public class WikiPageSort { * use this comparator if you like a list of sorted pages by mod time */ protected static final Comparator<WikiPage> MODTIME_ORDER = new Comparator<WikiPage>() { - + @Override public int compare(WikiPage p1, WikiPage p2) { // the "-" in from of the Long return negative int and therefore realizes an descending order return - Long.valueOf(p1.getModificationTime()).compareTo(Long.valueOf(p2.getModificationTime())); } }; + + public static class WikiPageNameComparator implements Comparator<String> { + + private final Collator collator; + + public WikiPageNameComparator(Locale locale) { + collator = Collator.getInstance(locale); + } + + @Override + public int compare(String n1, String n2) { + if(n1 == null) { + return n2 == null ? 0 : 1; + } else if(n2 == null) { + return -1; + } + return collator.compare(n1, n2); + } + } + + public static class WikiFileComparator implements Comparator<VFSItem> { + + private final Collator collator; + + public WikiFileComparator(Locale locale) { + collator = Collator.getInstance(locale); + } + + @Override + public int compare(VFSItem v1, VFSItem v2) { + if(v1 == null) { + return v2 == null ? 0 : 1; + } else if(v2 == null) { + return -1; + } + + String n1 = v1.getName(); + String n2 = v2.getName(); + + if(n1 == null) { + return n2 == null ? 0 : 1; + } else if(n2 == null) { + return -1; + } + return collator.compare(n1, n2); + } + }; } diff --git a/src/main/java/org/olat/modules/wiki/WikiToCPResource.java b/src/main/java/org/olat/modules/wiki/WikiToCPResource.java index ee965d6e2d13ff5b7ac37c42fb0beec2079c4b87..f69a908fd995e968bdfcccc29ef1b98a37f1a2e3 100644 --- a/src/main/java/org/olat/modules/wiki/WikiToCPResource.java +++ b/src/main/java/org/olat/modules/wiki/WikiToCPResource.java @@ -125,7 +125,7 @@ public class WikiToCPResource implements MediaResource { // create the ims manifest String manifest = export.createIMSManifest(wiki, identity); zout.putNextEntry(new ZipEntry("imsmanifest.xml")); - IOUtils.write(manifest, zout); + IOUtils.write(manifest, zout, "UTF-8"); zout.closeEntry(); VFSContainer mediaContainer = WikiManager.getInstance().getMediaFolder(ores); @@ -137,7 +137,7 @@ public class WikiToCPResource implements MediaResource { // create the javascript mapping file String jsContent = export.createJsMappingContent(wiki); zout.putNextEntry(new ZipEntry("mapping.js")); - IOUtils.write(jsContent, zout); + IOUtils.write(jsContent, zout, "UTF-8"); zout.closeEntry(); @@ -145,7 +145,7 @@ public class WikiToCPResource implements MediaResource { for (WikiPage page: pages) { String htmlPage = export.wikiPageToHtml(page); zout.putNextEntry(new ZipEntry(page.getPageId() + ".html")); - IOUtils.write(htmlPage, zout); + IOUtils.write(htmlPage, zout, "UTF-8"); zout.closeEntry(); } diff --git a/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java b/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java index 820d12134b47a56179f732c81484a5d078dc8a5e..93a600da00a913a3fc6f8b3f1b18b7bfdc0785e6 100644 --- a/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java +++ b/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java @@ -126,7 +126,7 @@ public class WikiToZipUtils { String overviewPage = WikiToZipUtils.createIndexPageForExport(items); if(overviewPage != null){ exportStream.putNextEntry(new ZipEntry(currentPath + "/index.html")); - IOUtils.write(overviewPage, exportStream); + IOUtils.write(overviewPage, exportStream, "UTF-8"); exportStream.closeEntry(); } for(VFSItem wikiItem:items) { diff --git a/src/main/java/org/olat/modules/wiki/portfolio/WikiMediaHandler.java b/src/main/java/org/olat/modules/wiki/portfolio/WikiMediaHandler.java index b46d596933f0c7f0f04e63927f9c30c1afcd264e..b2cdead0e0b48b14565fd202177e8d4bd373bfb2 100644 --- a/src/main/java/org/olat/modules/wiki/portfolio/WikiMediaHandler.java +++ b/src/main/java/org/olat/modules/wiki/portfolio/WikiMediaHandler.java @@ -1,4 +1,6 @@ /** + + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -30,6 +32,7 @@ import org.olat.fileresource.types.WikiResource; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; +import org.olat.modules.portfolio.MediaRenderingHints; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.handler.AbstractMediaHandler; import org.olat.modules.portfolio.manager.MediaDAO; @@ -113,8 +116,8 @@ public class WikiMediaHandler extends AbstractMediaHandler { } @Override - public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { - return new WikiPageMediaController(ureq, wControl, media); + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { + return new WikiPageMediaController(ureq, wControl, media, hints); } @Override diff --git a/src/main/java/org/olat/modules/wiki/portfolio/WikiPageMediaController.java b/src/main/java/org/olat/modules/wiki/portfolio/WikiPageMediaController.java index 283c5d8c114109690040b390292380aa4d0cf52e..a403017341d2e642d2e6e799af85398488a77381 100644 --- a/src/main/java/org/olat/modules/wiki/portfolio/WikiPageMediaController.java +++ b/src/main/java/org/olat/modules/wiki/portfolio/WikiPageMediaController.java @@ -36,8 +36,15 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; import org.olat.core.util.filter.FilterFactory; import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.MediaRenderingHints; +import org.olat.modules.portfolio.ui.MediaMetadataController; +import org.olat.modules.portfolio.ui.PortfolioHomeController; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -49,12 +56,30 @@ public class WikiPageMediaController extends BasicController { private static final OLog log = Tracing.createLoggerFor(WikiPageMediaController.class); - public WikiPageMediaController(UserRequest ureq, WindowControl wControl, Media media) { + @Autowired + private UserManager userManager; + + public WikiPageMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) { super(ureq, wControl); + setTranslator(Util.createPackageTranslator(PortfolioHomeController.class, getLocale(), getTranslator())); VelocityContainer mainVC = createVelocityContainer("details"); String wikiText = getContent(media.getContent()); mainVC.contextPut("text", wikiText); + + String desc = media.getDescription(); + mainVC.contextPut("description", StringHelper.containsNonWhitespace(desc) ? desc : null); + String title = media.getTitle(); + mainVC.contextPut("title", StringHelper.containsNonWhitespace(title) ? title : null); + + mainVC.contextPut("creationdate", media.getCreationDate()); + mainVC.contextPut("author", userManager.getUserDisplayName(media.getAuthor())); + + if(hints.isExtendedMetadata()) { + MediaMetadataController metaCtrl = new MediaMetadataController(ureq, wControl, media); + listenTo(metaCtrl); + mainVC.put("meta", metaCtrl.getInitialComponent()); + } putInitialPanel(mainVC); } diff --git a/src/main/java/org/olat/modules/wiki/portfolio/_content/details.html b/src/main/java/org/olat/modules/wiki/portfolio/_content/details.html index 3c14a84019d0e6f7efa9396767a6dc2e58f588b9..5cc820155025edbb23685590fa70846b3dae5179 100644 --- a/src/main/java/org/olat/modules/wiki/portfolio/_content/details.html +++ b/src/main/java/org/olat/modules/wiki/portfolio/_content/details.html @@ -1 +1,14 @@ -$!text \ No newline at end of file +<div class="o_wiki"> + #if($title) + <h5> + $title + <small>$r.translate("document.by",$author)</small> + </h5> + #end + $!text + #if($r.available("meta")) + <div class="clearfix"><div class="panel panel-default o_artefact_metadata"> + $r.render("meta") + </div></div> + #end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/portfolio/_spring/portfolioContext.xml b/src/main/java/org/olat/portfolio/_spring/portfolioContext.xml index 94c3cbd3be925d0957624b772c96520516fab6be..5d5f9f883bd55a2a65c628ca7740a47f9d34b5b5 100644 --- a/src/main/java/org/olat/portfolio/_spring/portfolioContext.xml +++ b/src/main/java/org/olat/portfolio/_spring/portfolioContext.xml @@ -69,7 +69,7 @@ </bean> <!-- Deadline Job --> - <bean id="epDeadlineTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="epDeadlineTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="epDeadlineJob.${cluster.singleton.services}" /> <!-- adjust cron style syntax for your notification needs "0 10 0 * *" e.g. 10 minutes after midnight @@ -88,16 +88,16 @@ <property name="startDelay" value="60000" /> </bean> - <bean id="epDeadlineJob.enabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="epDeadlineJob.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.portfolio.manager.EPDeadlineJob" /> </bean> <!-- dummy bean --> - <bean id="epDeadlineJob.disabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="epDeadlineJob.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" /> </bean> - <bean id="invitationCleanupTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="invitationCleanupTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="invitationCleanupJob.${cluster.singleton.services}" /> <!-- adjust cron style syntax for your notification needs "0 10 0 * *" e.g. 10 minutes after midnight @@ -119,11 +119,11 @@ <property name="startDelay" value="150000" /> </bean> - <bean id="invitationCleanupJob.enabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="invitationCleanupJob.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.portfolio.manager.InvitationCleanupJob" /> </bean> <!-- dummy bean --> - <bean id="invitationCleanupJob.disabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="invitationCleanupJob.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" /> </bean> diff --git a/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java b/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java index 694ee888bb3489b39211e029b18b0915d2f21328..1fa0c11ea1a99dcb2dc711c724d3a47d7608f5c2 100755 --- a/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java +++ b/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java @@ -54,6 +54,7 @@ import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.group.BusinessGroup; import org.olat.group.DeletableGroupData; import org.olat.modules.assessment.AssessmentService; +import org.olat.modules.assessment.Role; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.modules.webFeed.portfolio.LiveBlogArtefactHandler; import org.olat.portfolio.PortfolioModule; @@ -1148,10 +1149,10 @@ public class EPFrontendManager implements UserDataDeletable, DeletableGroupData * @param map */ public void submitMap(PortfolioStructureMap map) { - submitMap(map, true); + submitMap(map, true, Role.user); } - private void submitMap(PortfolioStructureMap map, boolean logActivity) { + private void submitMap(PortfolioStructureMap map, boolean logActivity, Role by) { if(!(map instanceof EPStructuredMap)) return;//add an exception EPStructuredMap submittedMap = (EPStructuredMap)map; @@ -1170,7 +1171,7 @@ public class EPFrontendManager implements UserDataDeletable, DeletableGroupData ienv.setIdentity(owner); UserCourseEnvironment uce = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment()); if(logActivity) { - am.incrementNodeAttempts(courseNode, owner, uce); + am.incrementNodeAttempts(courseNode, owner, uce, by); } else { am.incrementNodeAttemptsInBackground(courseNode, owner, uce); } @@ -1192,7 +1193,7 @@ public class EPFrontendManager implements UserDataDeletable, DeletableGroupData List<PortfolioStructureMap> mapsToClose = structureManager.getOpenStructuredMapAfterDeadline(); int count = 0; for(PortfolioStructureMap mapToClose:mapsToClose) { - submitMap(mapToClose, false); + submitMap(mapToClose, false, Role.auto); if(count % 5 == 0) { // this possibly takes longer than connection timeout, so do intermediatecommits. dbInstance.intermediateCommit(); diff --git a/src/main/java/org/olat/registration/LanguageChooserController.java b/src/main/java/org/olat/registration/LanguageChooserController.java index a321d1cfa268bb6104646886e244b3571a97df7b..4c06a4c99f2fe1e92958942f226f05fffab430c5 100644 --- a/src/main/java/org/olat/registration/LanguageChooserController.java +++ b/src/main/java/org/olat/registration/LanguageChooserController.java @@ -41,12 +41,10 @@ import org.olat.core.util.event.MultiUserEvent; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.resource.OresHelper; import org.olat.dispatcher.LocaleNegotiator; +import org.springframework.beans.factory.annotation.Autowired; /** - * Description:<br> - * TODO: srosse Class Description for LanguageChooserController - * * <P> * Initial Date: 17 nov. 2009 <br> * @author srosse, stephane.rosse@frentix.com, www.frentix.com @@ -59,6 +57,8 @@ public class LanguageChooserController extends FormBasicController { private boolean fireStandardEvent = true; + @Autowired + private I18nManager i18nManager; /** * @param ureq @@ -94,7 +94,7 @@ public class LanguageChooserController extends FormBasicController { @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(source == langs) { - Locale loc = I18nManager.getInstance().getLocaleOrDefault(getSelectedLanguage()); + Locale loc = i18nManager.getLocaleOrDefault(getSelectedLanguage()); MultiUserEvent mue = new LanguageChangedEvent(loc, ureq); setLocale(loc, true); ureq.getUserSession().setLocale(loc); @@ -124,7 +124,7 @@ public class LanguageChooserController extends FormBasicController { */ @Override protected void initForm(FormItemContainer formLayout, Controller listener, final UserRequest ureq) { - Map<String, String> languages = I18nManager.getInstance().getEnabledLanguagesTranslated(); + Map<String, String> languages = i18nManager.getEnabledLanguagesTranslated(); String[] langKeys = StringHelper.getMapKeysAsStringArray(languages); String[] langValues = StringHelper.getMapValuesAsStringArray(languages); ArrayHelper.sort(langKeys, langValues, false, true, false); diff --git a/src/main/java/org/olat/registration/PwChangeController.java b/src/main/java/org/olat/registration/PwChangeController.java index 5b10fd76a14db962f71eb427f5d0a274b3d7050d..1a4f1e29d81582959fb104738c4d00d08d370e99 100644 --- a/src/main/java/org/olat/registration/PwChangeController.java +++ b/src/main/java/org/olat/registration/PwChangeController.java @@ -54,6 +54,7 @@ import org.olat.core.id.UserConstants; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.i18n.I18nModule; import org.olat.core.util.mail.MailBundle; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailManager; @@ -70,8 +71,6 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class PwChangeController extends BasicController { - private static String SEPARATOR = "____________________________________________________________________\n"; - private Panel passwordPanel; private Link pwchangeHomelink; private final VelocityContainer myContent; @@ -85,6 +84,10 @@ public class PwChangeController extends BasicController { private String pwKey; private TemporaryKey tempKey; + @Autowired + private I18nModule i18nModule; + @Autowired + private I18nManager i18nManager; @Autowired private UserModule userModule; @Autowired @@ -248,7 +251,7 @@ public class PwChangeController extends BasicController { return null; } Preferences prefs = identity.getUser().getPreferences(); - Locale locale = I18nManager.getInstance().getLocaleOrDefault(prefs.getLanguage()); + Locale locale = i18nManager.getLocaleOrDefault(prefs.getLanguage()); ureq.getUserSession().setLocale(locale); myContent.contextPut("locale", locale); @@ -274,8 +277,8 @@ public class PwChangeController extends BasicController { .append("<div class='o_body'>") .append(userTrans.translate("pwchange.headline")) .append(userTrans.translate("pwchange.intro", new String[] { identity.getName() })) - .append(userTrans.translate("pwchange.body", new String[] { serverpath, tk.getRegistrationKey(), I18nManager.getInstance().getLocaleKey(ureq.getLocale()) })) - .append(userTrans.translate("pwchange.body.alt", new String[] { serverpath, tk.getRegistrationKey(), I18nManager.getInstance().getLocaleKey(ureq.getLocale()) })) + .append(userTrans.translate("pwchange.body", new String[] { serverpath, tk.getRegistrationKey(), i18nModule.getLocaleKey(ureq.getLocale()) })) + .append(userTrans.translate("pwchange.body.alt", new String[] { serverpath, tk.getRegistrationKey(), i18nModule.getLocaleKey(ureq.getLocale()) })) .append("</div>") .append("<div class='o_footer'>") .append(userTrans.translate("reg.wherefrom", new String[] { serverpath, today, ip })) diff --git a/src/main/java/org/olat/registration/RegistrationController.java b/src/main/java/org/olat/registration/RegistrationController.java index b37da45a021499b2690065ee61d2d304436789af..4fde7fa7f95ac97daf490fc66d0d854244e8fca7 100644 --- a/src/main/java/org/olat/registration/RegistrationController.java +++ b/src/main/java/org/olat/registration/RegistrationController.java @@ -97,6 +97,8 @@ public class RegistrationController extends BasicController implements Activatea private String uniqueRegistrationKey; private TemporaryKey tempKey; + @Autowired + private I18nModule i18nModule; @Autowired private I18nManager i18nManager; @Autowired @@ -131,7 +133,7 @@ public class RegistrationController extends BasicController implements Activatea // support for legacy lang parameter lang = ureq.getParameter("lang"); } - if (lang != null && ! lang.equals(i18nManager.getLocaleKey(getLocale()))) { + if (lang != null && ! lang.equals(i18nModule.getLocaleKey(getLocale()))) { Locale loc = i18nManager.getLocaleOrDefault(lang); ureq.getUserSession().setLocale(loc); setLocale(loc, true); @@ -154,7 +156,7 @@ public class RegistrationController extends BasicController implements Activatea // render in a modal dialog, no need to add the 3cols layout controller // wrapper //fxdiff FXOLAT-113: business path in DMZ - if(I18nModule.getEnabledLanguageKeys().size() == 1) { + if(i18nModule.getEnabledLanguageKeys().size() == 1) { wizInfoController.setCurStep(2); createEmailForm(ureq); } else { @@ -169,7 +171,7 @@ public class RegistrationController extends BasicController implements Activatea // error, there should be an entry showError("regkey.missingentry"); //fxdiff FXOLAT-113: business path in DMZ - if(I18nModule.getEnabledLanguageKeys().size() == 1) { + if(i18nModule.getEnabledLanguageKeys().size() == 1) { wizInfoController.setCurStep(2); createEmailForm(ureq); } else { @@ -232,7 +234,7 @@ public class RegistrationController extends BasicController implements Activatea } private void createRegForm2(UserRequest ureq, String proposedUsername, boolean userInUse, boolean usernameReadonly) { - registrationForm = new RegistrationForm2(ureq, getWindowControl(), I18nManager.getInstance().getLocaleKey(getLocale()), proposedUsername, userInUse, usernameReadonly); + registrationForm = new RegistrationForm2(ureq, getWindowControl(), i18nModule.getLocaleKey(getLocale()), proposedUsername, userInUse, usernameReadonly); listenTo(registrationForm); regarea.setContent(registrationForm.getInitialComponent()); } @@ -303,11 +305,11 @@ public class RegistrationController extends BasicController implements Activatea if (tk == null) tk = registrationManager.createTemporaryKeyByEmail(email, ip, RegistrationManager.REGISTRATION); myContent.contextPut("regKey", tk.getRegistrationKey()); - String link = serverpath + "/dmz/registration/index.html?key=" + tk.getRegistrationKey() + "&language=" + i18nManager.getLocaleKey(ureq.getLocale()); + String link = serverpath + "/dmz/registration/index.html?key=" + tk.getRegistrationKey() + "&language=" + i18nModule.getLocaleKey(ureq.getLocale()); String[] bodyAttrs = new String[]{ serverpath, //0 tk.getRegistrationKey(), //1 - i18nManager.getLocaleKey(ureq.getLocale()), //2 + i18nModule.getLocaleKey(ureq.getLocale()), //2 "<a href=\"" + link + "\">" + link + "</a>" //3 }; @@ -370,8 +372,8 @@ public class RegistrationController extends BasicController implements Activatea if (event == Event.DONE_EVENT) { String lang = registrationForm.getLangKey(); // change language if different then current language - if (! lang.equals(I18nManager.getInstance().getLocaleKey(ureq.getLocale()))) { - Locale loc = I18nManager.getInstance().getLocaleOrDefault(lang); + if (! lang.equals(i18nModule.getLocaleKey(ureq.getLocale()))) { + Locale loc = i18nManager.getLocaleOrDefault(lang); ureq.getUserSession().setLocale(loc); getTranslator().setLocale(loc); } diff --git a/src/main/java/org/olat/registration/RegistrationForm2.java b/src/main/java/org/olat/registration/RegistrationForm2.java index f4fed839d77d258145de880f55cf7a9dbb532ed4..02bc13267e44f52b01a09a96302cbd3f634e29cf 100644 --- a/src/main/java/org/olat/registration/RegistrationForm2.java +++ b/src/main/java/org/olat/registration/RegistrationForm2.java @@ -77,6 +77,8 @@ public class RegistrationForm2 extends FormBasicController { @Autowired private UserModule userModule; + @Autowired + private I18nManager i18nManager; /** * @param name @@ -174,7 +176,7 @@ public class RegistrationForm2 extends FormBasicController { uifactory.addSpacerElement("lang", formLayout, true); // second the user language - Map<String, String> languages = I18nManager.getInstance().getEnabledLanguagesTranslated(); + Map<String, String> languages = i18nManager.getEnabledLanguagesTranslated(); lang = uifactory.addDropdownSingleselect("user.language", formLayout, StringHelper.getMapKeysAsStringArray(languages), StringHelper.getMapValuesAsStringArray(languages), diff --git a/src/main/java/org/olat/registration/_content/disclaimer.html b/src/main/java/org/olat/registration/_content/disclaimer.html index fa2c326b17e736df17ed362982df964685fc2324..64b4cd14f6ce0b8eab63ed08382c9d96bcf347db 100644 --- a/src/main/java/org/olat/registration/_content/disclaimer.html +++ b/src/main/java/org/olat/registration/_content/disclaimer.html @@ -1,4 +1,4 @@ -<fieldset> +<fieldset class="o_disclaimer"> <legend>$r.translate("disclaimer.terms.of.usage")</legend> <p>$r.translate("disclaimer.paragraph1")</p> <p>$r.translate("disclaimer.paragraph2")</p> diff --git a/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties index 9341031d1510187929b1d7607fb36a7418405793..c49b4657e85a213adbdbf139c2893fad7aec0b49 100644 --- a/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties @@ -1,4 +1,4 @@ -#Tue Feb 07 13:54:14 CET 2017 +#Mon Jul 17 21:16:03 CEST 2017 admin.enableRegistration=Activate self-registration admin.enableRegistration.on=Enabled admin.enableRegistrationLink=Activate self-registration from external web sites @@ -65,9 +65,9 @@ pw.change.confirm.token=SMS authentication code pw.change.sms=Start authentication by SMS pw.change.sms.descr=You have enter a mobile telecom number in OpenOLAT. You can authenticate you by SMS. Choose the button below to start the authentication by SMS\: pw.change.sms.title=Authentication by SMS +pwchange.body=<p>Please click <a href\='{0}/dmz/pwchange/index.html?key\={1}&language\={2}'>here to reset your OpenOLAT password</a>. \nAfterwards you may <a href\='{0}/dmz/1%3A1%3Aomain_loging%3A1%3A0%3Acid%3Alogin/?lp\=OLAT'>sign in OpenOLAT</a>.</p> +pwchange.body.alt=<p>In case your mail program does not support HTML, copy this link to you webbrowser\: </br><a href\='{0}/dmz/pwchange/index.html?key\={1}&language\={2}'>{0}/dmz/pwchange/index.html?key\={1}&language\={2}</a></p> pwchange.headline=<p><b>Key for new OpenOLAT password</b></p> -pwchange.body=<p>Please click <a href='{0}/dmz/pwchange/index.html?key\={1}&language\={2}'>here to reset your OpenOLAT password</a>. \nAfterwards you may <a href='{0}/dmz/1%3A1%3Aomain_loging%3A1%3A0%3Acid%3Alogin/?lp\=OLAT'>sign in OpenOLAT</a>.</p> -pwchange.body.alt=<p>In case your mail program does not support HTML, copy this link to you webbrowser: </br><a href='{0}/dmz/pwchange/index.html?key\={1}&language\={2}'>{0}/dmz/pwchange/index.html?key\={1}&language\={2}</a></p> pwchange.homelink=Please click here to log on pwchange.intro=You have (or somebody else has) asked for a new password regarding the OpenOLAT user account {0}. pwchange.subject=Key to a new OpenOLAT password @@ -126,4 +126,5 @@ user.password=OpenOLAT password user.password2=Repeat OpenOLAT password user.pwlength=At least 4 characters; may contain letters and digits. user.regkey=Registration key +warning.message.not.send=SMS cannot be send. workflow.browsedback=Please do not use the browser to navigate. diff --git a/src/main/java/org/olat/registration/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/registration/_i18n/LocalStrings_fr.properties index ed610d46fc75de031dae9c3f99e72adcff4f533d..13bdae9477214f1a5be32452c7399255a8588cbd 100644 --- a/src/main/java/org/olat/registration/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/registration/_i18n/LocalStrings_fr.properties @@ -60,7 +60,7 @@ password.cantchange=Pour modifier votre mot de passe, veuillez contacter le resp password.notchanged=Le mot de passe OpenOLAT n'a pas \u00E9t\u00E9 modifi\u00E9. password.successful=Votre mot de passe OpenOLAT a \u00E9t\u00E9 modifi\u00E9. pw.change.confirm=V\u00E9rifier le code -pw.change.confirm.descr=Veuillez entrer s'il-vous-pla\u00EEt le code d'authentification que vous avez re\u00E7u par SMS. +pw.change.confirm.descr=Veuillez entrer s'il vous pla\u00EEt le code d'authentification que vous avez re\u00E7u par SMS. pw.change.confirm.token=Code d'authentification pw.change.sms=D\u00E9marrer l'authentification par SMS pw.change.sms.descr=Vous avez entrer un num\u00E9ro de t\u00E9l\u00E9phone portable dans OpenOLAT. vous pouvez vous authentifier par SMS. Veuillez choisir le bouton ci-dessous pour d\u00E9marrer l'authentification par SMS. diff --git a/src/main/java/org/olat/registration/restapi/RegistrationWebService.java b/src/main/java/org/olat/registration/restapi/RegistrationWebService.java index 14be04afef359b690d7dea3392a868c2c4c4d9b5..2305d8c1037ec45f37e6bb3bd320a39a74e05abb 100644 --- a/src/main/java/org/olat/registration/restapi/RegistrationWebService.java +++ b/src/main/java/org/olat/registration/restapi/RegistrationWebService.java @@ -45,7 +45,7 @@ import org.olat.core.helpers.Settings; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.Util; -import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.i18n.I18nModule; import org.olat.core.util.mail.MailBundle; import org.olat.core.util.mail.MailManager; import org.olat.core.util.mail.MailerResult; @@ -126,7 +126,7 @@ public class RegistrationWebService { String[] bodyAttrs = new String[] { serverpath, tk.getRegistrationKey(), - I18nManager.getInstance().getLocaleKey(locale) + CoreSpringFactory.getImpl(I18nModule.class).getLocaleKey(locale) }; String[] whereFromAttrs = new String [] { serverpath, today, ip }; String body = translator.translate("reg.body", bodyAttrs) + SEPARATOR + translator.translate("reg.wherefrom", whereFromAttrs); diff --git a/src/main/java/org/olat/repository/RepositoryEntry.java b/src/main/java/org/olat/repository/RepositoryEntry.java index f7d3d00369d5b391dc93437f1764fc09b1a29aaf..29cfb8ce0b84d63458844e355ef307f631b163d6 100644 --- a/src/main/java/org/olat/repository/RepositoryEntry.java +++ b/src/main/java/org/olat/repository/RepositoryEntry.java @@ -74,6 +74,8 @@ import org.olat.resource.OLATResourceImpl; @NamedQuery(name="filterRepositoryEntryMembership", query="select v.key, membership.identity.key from repositoryentry as v inner join v.groups as relGroup inner join relGroup.group as baseGroup inner join baseGroup.members as membership on membership.role in ('owner','coach','participant') where membership.identity.key=:identityKey and v.key in (:repositoryEntryKey)"), @NamedQuery(name="loadRepositoryEntryByKey", query="select v from repositoryentry as v inner join fetch v.olatResource as ores inner join fetch v.statistics as statistics left join fetch v.lifecycle as lifecycle where v.key = :repoKey"), @NamedQuery(name="loadRepositoryEntryByResourceKey", query="select v from repositoryentry as v inner join fetch v.olatResource as ores inner join fetch v.statistics as statistics left join fetch v.lifecycle as lifecycle where ores.key = :resourceKey"), + @NamedQuery(name="loadRepositoryEntryByResourceId", query="select v from repositoryentry as v inner join fetch v.olatResource as ores inner join fetch v.statistics as statistics left join fetch v.lifecycle as lifecycle where ores.resId=:resId and ores.resName=:resName"), + @NamedQuery(name="getDisplayNameByResourceKey", query="select v.displayname from repositoryentry v where v.olatResource.key=:resKey"), @NamedQuery(name="getDisplayNameByOlatResourceRedId", query="select v.displayname from repositoryentry v inner join v.olatResource as ores where ores.resId=:resid"), @NamedQuery(name="getDisplayNameByRepositoryEntryKey", query="select v.displayname from repositoryentry v where v.key=:reKey") diff --git a/src/main/java/org/olat/repository/RepositoryEntryAuthorView.java b/src/main/java/org/olat/repository/RepositoryEntryAuthorView.java index dc6f98d9dbb8b922c4a0999fa45e5ef8c2eba898..3bb215877d45449fe5065e21c5589b4f59d1818b 100644 --- a/src/main/java/org/olat/repository/RepositoryEntryAuthorView.java +++ b/src/main/java/org/olat/repository/RepositoryEntryAuthorView.java @@ -53,6 +53,8 @@ public interface RepositoryEntryAuthorView extends OLATResourceable, RepositoryE public RepositoryEntryLifecycle getLifecycle(); + public int getNumOfReferences(); + public Date getDeletionDate(); public String getDeletedByFullName(); diff --git a/src/main/java/org/olat/repository/RepositoryMailing.java b/src/main/java/org/olat/repository/RepositoryMailing.java index 39f8ac3f222f21720fde343e6bc3a62e13b6e313..4301c5b5d531be36b86e302ba6fb197c53de06e7 100644 --- a/src/main/java/org/olat/repository/RepositoryMailing.java +++ b/src/main/java/org/olat/repository/RepositoryMailing.java @@ -25,6 +25,7 @@ import org.apache.velocity.VelocityContext; import org.olat.basesecurity.BaseSecurity; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.translator.Translator; +import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; import org.olat.core.id.Roles; import org.olat.core.id.User; @@ -166,7 +167,7 @@ public class RepositoryMailing { // build learning resources as list of url as string final String reName = re.getDisplayname(); final String redescription = (StringHelper.containsNonWhitespace(re.getDescription()) ? FilterFactory.getHtmlTagAndDescapingFilter().filter(re.getDescription()) : ""); - + final String reUrl = Settings.getServerContextPathURI() + "/url/RepositoryEntry/" + re.getKey(); // get some data about the actor and fetch the translated subject / body via i18n module String[] bodyArgs = new String[] { actor.getUser().getProperty(UserConstants.FIRSTNAME, null), @@ -180,6 +181,8 @@ public class RepositoryMailing { String subject = trans.translate(subjectKey); String body = trans.translate(bodyKey, bodyArgs); + + // create a mail template which all these data MailTemplate mailTempl = new MailTemplate(subject, body, null) { @Override @@ -192,6 +195,7 @@ public class RepositoryMailing { // Put variables from greater context context.put("coursename", reName); context.put("coursedescription", redescription); + context.put("courseurl", reUrl); } }; return mailTempl; diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java index 9173a930807d419db87a66b5dca197398c162342..74ad472d1b8d0acbe2bacef65e0c7591d770bfd8 100644 --- a/src/main/java/org/olat/repository/RepositoryManager.java +++ b/src/main/java/org/olat/repository/RepositoryManager.java @@ -88,6 +88,7 @@ import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.olat.resource.accesscontrol.ResourceReservation; import org.olat.resource.accesscontrol.manager.ACReservationDAO; +import org.olat.resource.accesscontrol.provider.auto.AutoAccessManager; import org.olat.search.service.document.RepositoryEntryDocument; import org.olat.search.service.indexer.LifeFullIndexer; import org.olat.user.UserImpl; @@ -99,15 +100,15 @@ import org.springframework.stereotype.Service; * Initial Date: Mar 31, 2004 * * @author Mike Stock - * - * Comment: - * + * + * Comment: + * */ @Service("repositoryManager") public class RepositoryManager { - + private static final OLog log = Tracing.createLoggerFor(RepositoryManager.class); - + public static final int PICTURE_WIDTH = 570; public static final int PICTURE_HEIGHT = (PICTURE_WIDTH / 3) * 2; @@ -125,25 +126,27 @@ public class RepositoryManager { private ACReservationDAO reservationDao; @Autowired private LifeFullIndexer lifeIndexer; + @Autowired + private AutoAccessManager autoAccessManager; /** * @return Singleton. */ - public static RepositoryManager getInstance() { + public static RepositoryManager getInstance() { return CoreSpringFactory.getImpl(RepositoryManager.class); } - + /** * @param repositoryEntryStatusCode */ public RepositoryEntryStatus createRepositoryEntryStatus(int repositoryEntryStatusCode) { return new RepositoryEntryStatus(repositoryEntryStatusCode); } - + /** * Copy the repo entry image from the source to the target repository entry. * If the source repo entry does not exists, nothing will happen - * + * * @param src * @param target * @return @@ -158,16 +161,16 @@ public class RepositoryManager { if(targetFile != null) { targetFile.delete(); } - + String sourceImageSuffix = FileUtils.getFileSuffix(srcFile.getName()); VFSContainer repositoryHome = new LocalFolderImpl(new File(FolderConfig.getCanonicalRepositoryHome())); - VFSLeaf newImage = repositoryHome.createChildLeaf(target.getResourceableId() + "." + sourceImageSuffix); + VFSLeaf newImage = repositoryHome.createChildLeaf(target.getResourceableId() + "." + sourceImageSuffix); if (newImage != null) { return VFSManager.copyContent(srcFile, newImage); } return false; } - + public void deleteImage(RepositoryEntry re) { VFSLeaf imgFile = getImage(re); if (imgFile != null) { @@ -180,7 +183,7 @@ public class RepositoryManager { imgFile.delete(); } } - + public VFSLeaf getImage(OLATResourceable re) { VFSContainer repositoryHome = new LocalFolderImpl(new File(FolderConfig.getCanonicalRepositoryHome())); String imageName = re.getResourceableId() + ".jpg"; @@ -195,7 +198,7 @@ public class RepositoryManager { } return null; } - + public boolean setImage(VFSLeaf newImageFile, RepositoryEntry re) { VFSLeaf currentImage = getImage(re); if(currentImage != null) { @@ -207,20 +210,20 @@ public class RepositoryManager { } currentImage.delete(); } - + if(newImageFile == null || !newImageFile.exists() || newImageFile.getSize() <= 0) { return false; } - + String targetExtension = ".png"; String extension = FileUtils.getFileSuffix(newImageFile.getName()); if("jpg".equalsIgnoreCase(extension) || "jpeg".equalsIgnoreCase(extension)) { targetExtension = ".jpg"; } - + VFSContainer repositoryHome = new LocalFolderImpl(new File(FolderConfig.getCanonicalRepositoryHome())); VFSLeaf repoImage = repositoryHome.createChildLeaf(re.getResourceableId() + targetExtension); - + if(targetExtension.equals(".png") || targetExtension.equals(".jpg")) { Size newImageSize = imageHelper.getSize(newImageFile, extension); if(newImageSize != null && newImageSize.getWidth() <= PICTURE_WIDTH && newImageSize.getHeight() <= PICTURE_HEIGHT) { @@ -233,7 +236,7 @@ public class RepositoryManager { return size != null; } - + /** * Lookup repo entry by key. * @param the repository entry key (not the olatresourceable key) @@ -243,7 +246,7 @@ public class RepositoryManager { if (key == null) return null; return lookupRepositoryEntry(key, false) ; } - + /** * Lookup repo entry by key. * @param the repository entry key (not the olatresourceable key) @@ -264,13 +267,13 @@ public class RepositoryManager { } return entries.get(0); } - + public OLATResource lookupRepositoryEntryResource(Long key) { if (key == null) return null; StringBuilder query = new StringBuilder(); query.append("select v.olatResource from ").append(RepositoryEntry.class.getName()).append(" as v ") .append(" where v.key = :repoKey"); - + List<OLATResource> entries = dbInstance.getCurrentEntityManager() .createQuery(query.toString(), OLATResource.class) .setParameter("repoKey", key) @@ -340,7 +343,7 @@ public class RepositoryManager { } return result.get(0); } - + public Long lookupRepositoryEntryKey(OLATResourceable resourceable, boolean strict) { OLATResource ores = (resourceable instanceof OLATResource) ? (OLATResource)resourceable : OLATResourceManager.getInstance().findResourceable(resourceable); @@ -390,12 +393,12 @@ public class RepositoryManager { .append(" inner join fetch v.statistics as statistics") .append(" left join fetch v.lifecycle as lifecycle") .append(" where v.softkey=:softkey"); - + List<RepositoryEntry> result = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("softkey", softkey) .getResultList(); - + int size = result.size(); if (strict) { if (size != 1) @@ -410,7 +413,7 @@ public class RepositoryManager { } return result.get(0); } - + /** * Convenience method to access the repositoryEntry displayname by the referenced OLATResourceable id. * This only works if a repository entry has an referenced olat resourceable like a course or an content package repo entry @@ -429,6 +432,18 @@ public class RepositoryManager { return displaynames.get(0); } + public String lookupDisplayNameByResourceKey(Long resourceKey) { + List<String> displaynames = dbInstance.getCurrentEntityManager() + .createNamedQuery("getDisplayNameByResourceKey", String.class) + .setParameter("resKey", resourceKey) + .setHint("org.hibernate.cacheable", Boolean.TRUE) + .getResultList(); + + if (displaynames.size() > 1) throw new AssertException("Repository lookup returned zero or more than one result: " + displaynames.size()); + else if (displaynames.isEmpty()) return null; + return displaynames.get(0); + } + /** * Convenience method to access the repositoryEntry displayname by the referenced OLATResourceable id. * This only works if a repository entry has an referenced olat resourceable like a course or an content package repo entry @@ -446,7 +461,7 @@ public class RepositoryManager { else if (displaynames.isEmpty()) return null; return displaynames.get(0); } - + /** * Check if (and which) external IDs already exist. * @param a collection of external IDs to check if already existing @@ -479,7 +494,7 @@ public class RepositoryManager { sb.append("select v from ").append(RepositoryEntryShortImpl.class.getName()).append(" v ") .append(" inner join fetch v.olatResource as ores") .append(" where ores.key in (:resKeys)"); - + List<Long> resourceKeys = PersistenceHelper.toKeys(resources); List<RepositoryEntryShort> shorties = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntryShort.class) @@ -487,7 +502,7 @@ public class RepositoryManager { .getResultList(); return shorties; } - + /** * Load a list of repository entry without all the security groups ... * @param resources @@ -501,7 +516,7 @@ public class RepositoryManager { .getResultList(); return shorties; } - + /** * Test a repo entry if identity is allowed to launch. * @param ureq @@ -511,7 +526,7 @@ public class RepositoryManager { public boolean isAllowedToLaunch(UserRequest ureq, RepositoryEntry re) { return isAllowedToLaunch(ureq.getIdentity(), ureq.getUserSession().getRoles(), re); } - + public RepositoryEntrySecurity isAllowed(UserRequest ureq, RepositoryEntry re) { return isAllowed(ureq.getIdentity(), ureq.getUserSession().getRoles(), re); } @@ -546,10 +561,10 @@ public class RepositoryManager { } else if (re.getAccess() == RepositoryEntry.ACC_OWNERS && re.isMembersOnly()) { return repositoryEntryRelationDao.isMember(identity, re); } - + return false; } - + public RepositoryEntrySecurity isAllowed(Identity identity, Roles roles, RepositoryEntry re) { boolean isOwner = false; boolean isCourseCoach = false; @@ -557,10 +572,10 @@ public class RepositoryManager { boolean isCourseParticipant = false; boolean isGroupParticipant = false; boolean isGroupWaiting = false; - + boolean isEntryAdmin = false; boolean canLaunch = false; - + if (roles.isGuestOnly()) { if (re.getAccess() >= RepositoryEntry.ACC_USERS_GUESTS) { // allow for guests if access granted for guests @@ -600,10 +615,10 @@ public class RepositoryManager { break; } case invitee: break; - + } } - + if(isOwner) { canLaunch = true; isEntryAdmin = true; @@ -635,9 +650,9 @@ public class RepositoryManager { } } } - + boolean readOnly = new RepositoryEntryStatus(re.getStatusCode()).isClosed(); - + return new RepositoryEntrySecurity(isEntryAdmin, isOwner, isCourseParticipant, isCourseCoach, isGroupParticipant, isGroupCoach, @@ -657,7 +672,7 @@ public class RepositoryManager { lifeIndexer.indexDocument(RepositoryEntryDocument.TYPE, updatedRe.getKey()); return updatedRe; } - + public RepositoryEntry setAccessAndProperties(final RepositoryEntry re, int access, boolean membersOnly, boolean canCopy, boolean canReference, boolean canDownload) { @@ -674,17 +689,17 @@ public class RepositoryManager { reloadedRe.setCanReference(canReference); reloadedRe.setCanDownload(canDownload); RepositoryEntry updatedRe = dbInstance.getCurrentEntityManager().merge(reloadedRe); - + //fetch the values updatedRe.getStatistics().getLaunchCounter(); if(updatedRe.getLifecycle() != null) { updatedRe.getLifecycle().getKey(); } - + dbInstance.commit(); return updatedRe; } - + public RepositoryEntry setLeaveSetting(final RepositoryEntry re, RepositoryEntryAllowToLeaveOptions setting) { RepositoryEntry reloadedRe = repositoryEntryDao.loadForUpdate(re); @@ -699,8 +714,8 @@ public class RepositoryManager { } dbInstance.commit(); return updatedRe; - } - + } + /** * This method doesn't update empty and null values! ( Reserved to unit tests * and REST API) @@ -720,7 +735,7 @@ public class RepositoryManager { if(reloadedRe == null) { return null; } - + if(StringHelper.containsNonWhitespace(displayName)) { reloadedRe.setDisplayname(displayName); } @@ -745,11 +760,11 @@ public class RepositoryManager { reloadedRe.setAllowToLeaveOption(RepositoryEntryAllowToLeaveOptions.never); } } - + RepositoryEntryLifecycle cycleToDelete = null; RepositoryEntryLifecycle currentCycle = reloadedRe.getLifecycle(); if(currentCycle != null) { - // currently, it's a private cycle + // currently, it's a private cycle if(currentCycle.isPrivateCycle()) { //the new one is none or public, remove the private cycle if(cycle == null || !cycle.isPrivateCycle()) { @@ -763,12 +778,13 @@ public class RepositoryManager { if(cycleToDelete != null) { dbInstance.getCurrentEntityManager().remove(cycleToDelete); } - + dbInstance.commit(); lifeIndexer.indexDocument(RepositoryEntryDocument.TYPE, updatedRe.getKey()); + autoAccessManager.grantAccess(updatedRe); return updatedRe; } - + /** * The method updates empty and null values! * @param re @@ -806,7 +822,7 @@ public class RepositoryManager { RepositoryEntryLifecycle cycleToDelete = null; RepositoryEntryLifecycle currentCycle = reloadedRe.getLifecycle(); if(currentCycle != null) { - // currently, it's a private cycle + // currently, it's a private cycle if(currentCycle.isPrivateCycle()) { //the new one is none or public, remove the private cycle if(cycle == null || !cycle.isPrivateCycle()) { @@ -820,22 +836,23 @@ public class RepositoryManager { if(cycleToDelete != null) { dbInstance.getCurrentEntityManager().remove(cycleToDelete); } - + //fetch the values updatedRe.getStatistics().getLaunchCounter(); if(updatedRe.getLifecycle() != null) { updatedRe.getLifecycle().getKey(); } - + dbInstance.commit(); lifeIndexer.indexDocument(RepositoryEntryDocument.TYPE, updatedRe.getKey()); + autoAccessManager.grantAccess(updatedRe); return updatedRe; } - + public void triggerIndexer(RepositoryEntryRef re) { lifeIndexer.indexDocument(RepositoryEntryDocument.TYPE, re.getKey()); } - + /** * Count by type, limit by role accessability. * @param restrictedType @@ -854,14 +871,14 @@ public class RepositoryManager { dbquery.setCacheable(true); return ((Long)dbquery.list().get(0)).intValue(); } - + public long countPublished(String restrictedType) { StringBuilder query = new StringBuilder(400); query.append("select count(*) from org.olat.repository.RepositoryEntry v") .append(" inner join v.olatResource res") .append(" where res.resName=:restrictedType ") .append(" and ((v.access=").append(RepositoryEntry.ACC_OWNERS).append(" and v.membersOnly=true) or v.access>=").append(RepositoryEntry.ACC_USERS).append(")"); - + List<Number> count = dbInstance.getCurrentEntityManager() .createQuery(query.toString(), Number.class) .setParameter("restrictedType", restrictedType) @@ -881,14 +898,14 @@ public class RepositoryManager { if(roles.isOLATAdmin()) { identity = null;//not need for the query as administrator } - + StringBuilder sb = new StringBuilder(400); sb.append("select distinct v from ").append(RepositoryEntry.class.getName()).append(" v ") .append(" inner join fetch v.olatResource as res") .append(" inner join fetch v.statistics as statistics") .append(" left join fetch v.lifecycle as lifecycle") .append(" where res.resName in (:restrictedType) and "); - + boolean setIdentity = false; if (roles.isOLATAdmin()) { sb.append("v.access>=").append(RepositoryEntry.ACC_OWNERS); // treat admin special b/c admin is author as well @@ -914,7 +931,7 @@ public class RepositoryManager { */ public List<RepositoryEntry> queryByTypeLimitAccess(Identity identity, Roles roles, List<String> restrictedType) { if(restrictedType == null | restrictedType.isEmpty()) return Collections.emptyList(); - + String institution = identity.getUser().getProperty(UserConstants.INSTITUTIONALNAME, null); List<RepositoryEntry> results = new ArrayList<RepositoryEntry>(); if(!roles.isOLATAdmin() && institution != null && institution.length() > 0 && roles.isInstitutionalResourceManager()) { @@ -930,7 +947,7 @@ public class RepositoryManager { .append(" inner join identity.user as user") .append(" where user.institutionalName=:institutionCourseManager") .append(" and res.resName in (:restrictedType) and v.access = 1"); - + List<RepositoryEntry> institutionalResults = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("restrictedType", restrictedType) @@ -938,12 +955,12 @@ public class RepositoryManager { .getResultList(); results.addAll(institutionalResults); } - + long start = System.currentTimeMillis(); List<RepositoryEntry> genericResults = queryByTypeLimitAccess(identity, restrictedType, roles); long timeQuery3 = System.currentTimeMillis() - start; log.info("Repo-Perf: queryByTypeLimitAccess#3 takes " + timeQuery3); - + if(results.isEmpty()) { results.addAll(genericResults); } else { @@ -958,7 +975,7 @@ public class RepositoryManager { /** * Query by ownership, optionally limit by type. - * + * * @param identity * @param limitType * @return Results @@ -977,7 +994,7 @@ public class RepositoryManager { if (limitTypes != null && limitTypes.length > 0) { sb.append(" and res.resName in (:types)"); } - + TypedQuery<RepositoryEntry> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("identityKey", identity.getKey()); @@ -990,11 +1007,11 @@ public class RepositoryManager { } return query.getResultList(); } - + /** * Return the entries visible by the specified roles as member. The query * take the business groups in account. - * + * * @param identity * @param owner * @param coach @@ -1005,7 +1022,7 @@ public class RepositoryManager { public List<RepositoryEntry> queryByMembership(IdentityRef identity, boolean owner, boolean coach, boolean participant, String... limitTypes) { if (identity == null) throw new AssertException("identity can not be null!"); if (!owner && !coach && !participant) return Collections.emptyList(); - + StringBuilder sb = new StringBuilder(512); sb.append("select v from repositoryentry v ") .append(" inner join fetch v.olatResource as res ") @@ -1033,11 +1050,11 @@ public class RepositoryManager { sb.append(")"); } sb.append(")"); - + if (limitTypes != null && limitTypes.length > 0) { sb.append(" and res.resName in (:types)"); } - + TypedQuery<RepositoryEntry> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("identityKey", identity.getKey()); @@ -1068,7 +1085,7 @@ public class RepositoryManager { /** * Search for resources that can be referenced by an author. This is the case: * 1) the user is the owner of the resource - * 2) the user is author and the resource is at least visible to authors (BA) + * 2) the user is author and the resource is at least visible to authors (BA) * and the resource is set to canReference * @param identity The user initiating the query * @param roles The current users role set @@ -1077,7 +1094,7 @@ public class RepositoryManager { * @param author Limit search to this user (Name, firstname, loginname). Can be NULL * @param desc Limit search to description. Can be NULL * @return List of repository entries - */ + */ public List<RepositoryEntry> queryReferencableResourcesLimitType(Identity identity, Roles roles, List<String> resourceTypes, String displayName, String author, String desc) { if (identity == null) { @@ -1089,11 +1106,11 @@ public class RepositoryManager { } return queryResourcesLimitType(identity, resourceTypes, displayName, author, desc, true, false); } - + /** * Search for resources that can be copied by an author. This is the case: * 1) the user is the owner of the resource - * 2) the user is author and the resource is at least visible to authors (BA) + * 2) the user is author and the resource is at least visible to authors (BA) * and the resource is set to canCopy * @param identity The user initiating the query * @param roles The current users role set @@ -1102,7 +1119,7 @@ public class RepositoryManager { * @param author Limit search to this user (Name, firstname, loginname). Can be NULL * @param desc Limit search to description. Can be NULL * @return List of repository entries - */ + */ public List<RepositoryEntry> queryCopyableResourcesLimitType(Identity identity, Roles roles, List<String> resourceTypes, String displayName, String author, String desc) { if (identity == null) { @@ -1114,25 +1131,25 @@ public class RepositoryManager { } return queryResourcesLimitType(identity, resourceTypes, displayName, author, desc, false, true); } - + public List<RepositoryEntry> queryResourcesLimitType(Identity identity, List<String> resourceTypes, String displayName, String author, String desc, boolean checkCanReference, boolean checkCanCopy) { - + // cleanup some data: use null values if emtpy if (resourceTypes != null && resourceTypes.size() == 0) resourceTypes = null; if ( ! StringHelper.containsNonWhitespace(displayName)) displayName = null; if ( ! StringHelper.containsNonWhitespace(author)) author = null; if ( ! StringHelper.containsNonWhitespace(desc)) desc = null; - + // Build the query - // 1) Joining tables + // 1) Joining tables StringBuilder query = new StringBuilder(400); query.append("select distinct v from ").append(RepositoryEntry.class.getName()).append(" v ") .append(" inner join fetch v.olatResource as res" ) .append(" inner join fetch v.statistics as statistics") .append(" left join fetch v.lifecycle as lifecycle"); // 2) where clause - query.append(" where "); + query.append(" where "); // restrict on ownership or referencability flag int access; @@ -1154,7 +1171,7 @@ public class RepositoryManager { access = RepositoryEntry.ACC_OWNERS; query.append(" v.access>=:access "); } - + // restrict on type if (resourceTypes != null) { query.append(" and res.resName in (:resourcetypes)"); @@ -1182,7 +1199,7 @@ public class RepositoryManager { desc = '%' + desc + '%'; query.append(" and v.description like :desc"); } - + // create query an set query data TypedQuery<RepositoryEntry> dbquery = dbInstance.getCurrentEntityManager() .createQuery(query.toString(), RepositoryEntry.class); @@ -1202,13 +1219,13 @@ public class RepositoryManager { if (resourceTypes != null) { dbquery.setParameter("resourcetypes", resourceTypes); } - return dbquery.getResultList(); + return dbquery.getResultList(); } - + /** * Query by ownership, limit by access. - * + * * @param identity * @param limitAccess * @return Results @@ -1227,15 +1244,15 @@ public class RepositoryManager { sb.append(" or (v.access=1 and v.membersOnly=true)"); } sb.append(")"); - + List<RepositoryEntry> entries = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("identityKey", identity.getKey()) .setParameter("limitAccess", limitAccess) .getResultList(); - return entries; + return entries; } - + /** * check ownership of identity for a resource * @return true if the identity is member of the security group of the repository entry @@ -1246,7 +1263,7 @@ public class RepositoryManager { } return repositoryEntryRelationDao.hasRole(identity, entry, GroupRoles.owner.name()); } - + /** * This query need the repository entry as v, v.olatResource as res * and v.baseGroup as baseGroup @@ -1264,7 +1281,7 @@ public class RepositoryManager { } else { sb.append(RepositoryEntry.ACC_USERS); } - + //+ membership boolean setIdentity = false; if(!roles.isGuestOnly() && identity != null) { @@ -1281,15 +1298,15 @@ public class RepositoryManager { sb.append(")"); return setIdentity; } - + public int countGenericANDQueryWithRolesRestriction(SearchRepositoryEntryParameters params) { TypedQuery<Number> dbQuery = createGenericANDQueryWithRolesRestriction(params, false, Number.class); Number count = dbQuery.getSingleResult(); return count.intValue(); } - + public List<RepositoryEntry> genericANDQueryWithRolesRestriction(SearchRepositoryEntryParameters params, int firstResult, int maxResults, boolean orderBy) { - + TypedQuery<RepositoryEntry> dbQuery = createGenericANDQueryWithRolesRestriction(params, orderBy, RepositoryEntry.class); dbQuery.setFirstResult(firstResult); if(maxResults > 0) { @@ -1298,7 +1315,7 @@ public class RepositoryManager { List<RepositoryEntry> res = dbQuery.getResultList(); return res; } - + private <T> TypedQuery<T> createGenericANDQueryWithRolesRestriction(SearchRepositoryEntryParameters params, boolean orderBy, Class<T> type) { String displayName = params.getDisplayName(); String author = params.getAuthor(); @@ -1307,14 +1324,14 @@ public class RepositoryManager { final Identity identity = params.getIdentity(); final Roles roles = params.getRoles(); final String institution = params.getInstitution(); - + boolean institut = (!roles.isOLATAdmin() && institution != null && institution.length() > 0 && roles.isInstitutionalResourceManager()); boolean var_author = StringHelper.containsNonWhitespace(author); boolean var_displayname = StringHelper.containsNonWhitespace(displayName); boolean var_desc = StringHelper.containsNonWhitespace(desc); boolean var_resourcetypes = (resourceTypes != null && resourceTypes.size() > 0); boolean count = Number.class.equals(type); - + StringBuilder query = new StringBuilder(); if(count) { query.append("select count(v.key) from ").append(RepositoryEntry.class.getName()).append(" v "); @@ -1355,7 +1372,7 @@ public class RepositoryManager { .append(" where rel.entry=v and rel.group=baseGroup and membership.group=baseGroup and membership.identity=identity and user.identity.key=identity.key") .append(" and user.institutionalName=:institution and membership.role='").append(GroupRoles.owner.name()).append("'") .append(")))"); - + } else if (params.isOnlyOwnedResources()) { query.append(" where (v.access>0 and exists (select rel from repoentrytogroup as rel, bgroup as baseGroup, bgroupmember as membership ") .append(" where rel.entry=v and rel.group=baseGroup and membership.group=baseGroup") @@ -1371,17 +1388,17 @@ public class RepositoryManager { .append(" and membership.role in ('").append(GroupRoles.owner.name()).append("','").append(GroupRoles.coach.name()).append("','").append(GroupRoles.participant.name()).append("')") .append(" )") .append(" ))"); - + setIdentity = true; } else { query.append(" where "); setIdentity = appendAccessSubSelects(query, identity, roles); } - + if(params.getParentEntry() != null) { query.append(" and parentCei.key=:parentCeiKey"); } - + if (var_author) { // fuzzy author search author = PersistenceHelper.makeFuzzyQueryString(author); @@ -1397,7 +1414,7 @@ public class RepositoryManager { PersistenceHelper.appendFuzzyLike(query, "identity.name", "author", dbInstance.getDbVendor()); query.append(" ))"); } - + if (var_displayname) { //displayName = '%' + displayName.replace('*', '%') + '%'; //query.append(" and v.displayname like :displayname"); @@ -1405,7 +1422,7 @@ public class RepositoryManager { query.append(" and "); PersistenceHelper.appendFuzzyLike(query, "v.displayname", "displayname", dbInstance.getDbVendor()); } - + if (var_desc) { //desc = '%' + desc.replace('*', '%') + '%'; //query.append(" and v.description like :desc"); @@ -1413,15 +1430,15 @@ public class RepositoryManager { query.append(" and "); PersistenceHelper.appendFuzzyLike(query, "v.description", "desc", dbInstance.getDbVendor()); } - + if (var_resourcetypes) { query.append(" and res.resName in (:resourcetypes)"); } - + if(params.getRepositoryEntryKeys() != null && !params.getRepositoryEntryKeys().isEmpty()) { query.append(" and v.key in (:entryKeys)"); } - + if(params.getManaged() != null) { if(params.getManaged().booleanValue()) { query.append(" and v.managedFlagsString is not null"); @@ -1429,15 +1446,15 @@ public class RepositoryManager { query.append(" and v.managedFlagsString is null"); } } - + if(StringHelper.containsNonWhitespace(params.getExternalId())) { query.append(" and v.externalId=:externalId"); } - + if(StringHelper.containsNonWhitespace(params.getExternalRef())) { query.append(" and v.externalRef=:externalRef"); } - + if(params.getMarked() != null) { setIdentity = true; query.append(" and v.key ").append(params.getMarked().booleanValue() ? "" : "not").append(" in (") @@ -1449,7 +1466,7 @@ public class RepositoryManager { if(!count && orderBy) { query.append(" order by v.displayname, v.key ASC"); } - + TypedQuery<T> dbQuery = dbInstance.getCurrentEntityManager().createQuery(query.toString(), type); if(institut) { dbQuery.setParameter("institution", institution); @@ -1484,10 +1501,10 @@ public class RepositoryManager { } return dbQuery; } - + /** * Leave the course, commit to the database and send events - * + * * @param identity * @param re * @param status @@ -1504,7 +1521,7 @@ public class RepositoryManager { sendDeferredEvents(deferredEvents, re); } } - + /** * add provided list of identities as owners to the repo entry. silently ignore * if some identities were already owners before. @@ -1534,7 +1551,7 @@ public class RepositoryManager { } iae.setIdentitiesAddedEvent(reallyAddedId); } - + /** * remove list of identities as owners of given repository entry. * @param ureqIdentity @@ -1544,16 +1561,16 @@ public class RepositoryManager { */ public void removeOwners(Identity ureqIdentity, List<Identity> removeIdentities, RepositoryEntry re){ List<RepositoryEntryMembershipModifiedEvent> deferredEvents = new ArrayList<>(); - + for (Identity identity : removeIdentities) { removeOwner(ureqIdentity, identity, re); deferredEvents.add(RepositoryEntryMembershipModifiedEvent.removed(identity, re)); } - + dbInstance.commit(); sendDeferredEvents(deferredEvents, re); } - + private void sendDeferredEvents(List<? extends MultiUserEvent> events, OLATResourceable ores) { EventBus eventBus = CoordinatorManager.getInstance().getCoordinator().getEventBus(); for(MultiUserEvent event:events) { @@ -1561,7 +1578,7 @@ public class RepositoryManager { eventBus.fireEventToListenersOf(event, OresHelper.lookupType(RepositoryEntry.class)); } } - + private void removeOwner(Identity ureqIdentity, Identity identity, RepositoryEntry re) { repositoryEntryRelationDao.removeRole(identity, re, GroupRoles.owner.name()); @@ -1577,7 +1594,7 @@ public class RepositoryManager { log.audit("Identity(.key):" + ureqIdentity.getKey() + " removed identity '" + identity.getName() + "' from repositoryentry with key " + re.getKey()); } - + public void acceptPendingParticipation(Identity ureqIdentity, Identity identityToAdd, OLATResource resource, ResourceReservation reservation) { RepositoryEntry re = lookupRepositoryEntry(resource, false); if(re != null) { @@ -1593,7 +1610,7 @@ public class RepositoryManager { reservationDao.deleteReservation(reservation); } } - + /** * add provided list of identities as tutor to the repo entry. silently ignore * if some identities were already tutor before. @@ -1607,7 +1624,7 @@ public class RepositoryManager { List<Identity> reallyAddedId = new ArrayList<Identity>(); for (Identity identityToAdd : addIdentities) { if (!repositoryEntryRelationDao.hasRole(identityToAdd, re, GroupRoles.coach.name())) { - + boolean mustAccept = true; if(ureqIdentity != null && ureqIdentity.equals(identityToAdd)) { mustAccept = false;//adding itself, we hope that he knows what he makes @@ -1616,7 +1633,7 @@ public class RepositoryManager { } else { mustAccept = repositoryModule.isAcceptMembership(ureqRoles); } - + if(mustAccept) { ResourceReservation olderReservation = reservationDao.loadReservation(identityToAdd, re.getOlatResource()); if(olderReservation == null) { @@ -1638,7 +1655,7 @@ public class RepositoryManager { } iae.setIdentitiesAddedEvent(reallyAddedId); } - + /** * Internal method to add tutors, it makes no check. * @param ureqIdentity @@ -1660,7 +1677,7 @@ public class RepositoryManager { log.audit("Identity(.key):" + ureqIdentity.getKey() + " added identity '" + identity.getName() + "' to repositoryentry with key " + re.getKey()); } - + /** * remove list of identities as tutor of given repository entry. * @param ureqIdentity @@ -1677,10 +1694,10 @@ public class RepositoryManager { dbInstance.commit(); sendDeferredEvents(deferredEvents, re); } - + private void removeTutor(Identity ureqIdentity, Identity identity, RepositoryEntry re) { repositoryEntryRelationDao.removeRole(identity, re, GroupRoles.coach.name()); - + ActionType actionType = ThreadLocalUserActivityLogger.getStickyActionType(); ThreadLocalUserActivityLogger.setStickyActionType(ActionType.admin); try{ @@ -1692,7 +1709,7 @@ public class RepositoryManager { log.audit("Identity(.key):" + ureqIdentity.getKey() + " removed identity '" + identity.getName() + "' from repositoryentry with key " + re.getKey()); } - + /** * add provided list of identities as participant to the repo entry. silently ignore * if some identities were already participant before. @@ -1706,7 +1723,7 @@ public class RepositoryManager { List<Identity> reallyAddedId = new ArrayList<Identity>(); for (Identity identityToAdd : addIdentities) { if (!repositoryEntryRelationDao.hasRole(identityToAdd, re, GroupRoles.participant.name())) { - + boolean mustAccept = true; if(ureqIdentity != null && ureqIdentity.equals(identityToAdd)) { mustAccept = false;//adding itself, we hope that he knows what he makes @@ -1715,7 +1732,7 @@ public class RepositoryManager { } else { mustAccept = repositoryModule.isAcceptMembership(ureqRoles); } - + if(mustAccept) { ResourceReservation olderReservation = reservationDao.loadReservation(identityToAdd, re.getOlatResource()); if(olderReservation == null) { @@ -1737,7 +1754,7 @@ public class RepositoryManager { } iae.setIdentitiesAddedEvent(reallyAddedId); } - + /** * This is for internal usage only. The method dosn't make any check. * @param ureqIdentity @@ -1746,7 +1763,7 @@ public class RepositoryManager { */ private void addInternalParticipant(Identity ureqIdentity, Identity identity, RepositoryEntry re) { repositoryEntryRelationDao.addRole(identity, re, GroupRoles.participant.name()); - + ActionType actionType = ThreadLocalUserActivityLogger.getStickyActionType(); ThreadLocalUserActivityLogger.setStickyActionType(ActionType.admin); try{ @@ -1758,7 +1775,7 @@ public class RepositoryManager { log.audit("Identity(.key):" + ureqIdentity.getKey() + " added identity '" + identity.getName() + "' to repositoryentry with key " + re.getKey()); } - + /** * remove list of identities as participant of given repository entry. * @param ureqIdentity @@ -1775,10 +1792,10 @@ public class RepositoryManager { dbInstance.commit(); sendDeferredEvents(deferredEvents, re); } - + private void removeParticipant(Identity ureqIdentity, Identity identity, RepositoryEntry re, MailPackage mailing, boolean sendMail) { repositoryEntryRelationDao.removeRole(identity, re, GroupRoles.participant.name()); - + if(sendMail) { RepositoryMailing.sendEmail(ureqIdentity, identity, re, RepositoryMailing.Type.removeParticipant, mailing); } @@ -1794,11 +1811,11 @@ public class RepositoryManager { log.audit("Identity(.key):" + ureqIdentity.getKey() + " removed identity '" + identity.getName() + "' from repositoryentry with key " + re.getKey()); } - + /** * Remove the identities as members of the repository and from * all connected business groups. - * + * * @param members * @param re */ @@ -1814,7 +1831,7 @@ public class RepositoryManager { ThreadLocalUserActivityLogger.setStickyActionType(actionType); } } - + List<ResourceReservation> reservations = reservationDao.loadReservations(Collections.singletonList(re.getOlatResource())); for(ResourceReservation reservation:reservations) { if(members.contains(reservation.getIdentity())) { @@ -1836,15 +1853,15 @@ public class RepositoryManager { sendDeferredEvents(deferredEvents, re); } if (allOk) { - // do logging - not optimal but + // do logging - not optimal but StringBuilder sb = new StringBuilder(); sb.append("Identity(.key):").append(ureqIdentity.getKey()).append("removed multiple identities from security groups. Identities:: " ); for (Identity member : members) { sb.append(member.getName()).append(", "); } - log.audit(sb.toString()); + log.audit(sb.toString()); } - + for(Identity identity:members) { RepositoryMailing.sendEmail(ureqIdentity, identity, re, RepositoryMailing.Type.removeParticipant, mailing); } @@ -1865,11 +1882,11 @@ public class RepositoryManager { if(!StringHelper.containsNonWhitespace(currentUserInstitutionalName)) { return false; } - + if(!roles.isInstitutionalResourceManager()) { return false; } - + StringBuilder sb = new StringBuilder(); sb.append("select count(v) from ").append(RepositoryEntry.class.getName()).append(" v") .append(" inner join v.groups as relGroup") @@ -1878,7 +1895,7 @@ public class RepositoryManager { .append(" inner join membership.identity as identity") .append(" inner join identity.user as user") .append(" where v.key=:repoKey and user.institutionalName=:institutionCourseManager"); - + Number count = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Number.class) .setParameter("repoKey", repositoryEntry.getKey()) @@ -1886,7 +1903,7 @@ public class RepositoryManager { .getSingleResult(); return count == null ? false : count.intValue() > 0; } - + public int countLearningResourcesAsStudent(IdentityRef identity) { StringBuilder sb = new StringBuilder(1200); sb.append("select count(v) from ").append(RepositoryEntry.class.getName()).append(" as v ") @@ -1900,7 +1917,7 @@ public class RepositoryManager { .setParameter("identityKey", identity.getKey()) .getSingleResult().intValue(); } - + /** * Gets all learning resources where the user is in a learning group as participant. * @param identity @@ -1920,7 +1937,7 @@ public class RepositoryManager { if(StringHelper.containsNonWhitespace(type)) { sb.append(" and res.resName=:resourceType"); } - + appendOrderBy(sb, "v", orderby); TypedQuery<RepositoryEntry> query = dbInstance.getCurrentEntityManager() @@ -1936,7 +1953,7 @@ public class RepositoryManager { List<RepositoryEntry> repoEntries = query.getResultList(); return repoEntries; } - + /** * Gets all learning resources where the user is in a learning group as participant. * @param identity @@ -1966,7 +1983,7 @@ public class RepositoryManager { } return query.getResultList(); } - + public List<RepositoryEntry> getLearningResourcesAsBookmark(Identity identity, Roles roles, String type, int firstResult, int maxResults, RepositoryEntryOrder... orderby) { if(roles.isGuestOnly()) { return Collections.emptyList(); @@ -2013,7 +2030,7 @@ public class RepositoryManager { List<RepositoryEntry> repoEntries = query.getResultList(); return repoEntries; } - + public List<RepositoryEntryLight> getParticipantRepositoryEntry(IdentityRef identity, int maxResults, RepositoryEntryOrder... orderby) { StringBuilder sb = new StringBuilder(200); sb.append("select v from repoentrylight as v ") @@ -2025,7 +2042,7 @@ public class RepositoryManager { .append(" )") .append(" and (v.access>=3 or (v.access=").append(RepositoryEntry.ACC_OWNERS).append(" and v.membersOnly=true))"); appendOrderBy(sb, "v", orderby); - + TypedQuery<RepositoryEntryLight> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntryLight.class) .setParameter("identityKey", identity.getKey()); @@ -2034,7 +2051,7 @@ public class RepositoryManager { } return query.getResultList(); } - + public List<RepositoryEntryLight> getTutorRepositoryEntry(IdentityRef identity, int maxResults, RepositoryEntryOrder... orderby) { StringBuilder sb = new StringBuilder(200); sb.append("select v from repoentrylight as v ") @@ -2046,7 +2063,7 @@ public class RepositoryManager { .append(" )") .append(" and (v.access>=3 or (v.access=").append(RepositoryEntry.ACC_OWNERS).append(" and v.membersOnly=true))"); appendOrderBy(sb, "v", orderby); - + TypedQuery<RepositoryEntryLight> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntryLight.class) .setParameter("identityKey", identity.getKey()); @@ -2056,7 +2073,7 @@ public class RepositoryManager { return query.getResultList(); } - + public int countLearningResourcesAsOwner(IdentityRef identity) { StringBuilder sb = new StringBuilder(200); sb.append("select count(v) from ").append(RepositoryEntry.class.getName()).append(" v ") @@ -2070,31 +2087,31 @@ public class RepositoryManager { .setParameter("identityKey", identity.getKey()) .getSingleResult().intValue(); } - + /** * Gets all learning resources where the user is coach of a learning group or - * where he is in a rights group or where he is in the repository entry owner + * where he is in a rights group or where he is in the repository entry owner * group (course administrator) - * + * * @param identity * @return list of RepositoryEntries */ public boolean hasLearningResourcesAsTeacher(IdentityRef identity) { return countLearningResourcesAsTeacher(identity) > 0; } - + public int countLearningResourcesAsTeacher(IdentityRef identity) { StringBuilder sb = new StringBuilder(1200); sb.append("select count(v) from ").append(RepositoryEntry.class.getName()).append(" v ") .append(" inner join v.olatResource as res "); whereClauseLearningResourcesAsTeacher(sb); - + return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Number.class) .setParameter("identityKey", identity.getKey()) .getSingleResult().intValue(); } - + public List<RepositoryEntry> getLearningResourcesAsTeacher(Identity identity, int firstResult, int maxResults, RepositoryEntryOrder... orderby) { StringBuilder sb = new StringBuilder(1200); sb.append("select distinct v from ").append(RepositoryEntry.class.getName()).append(" v ") @@ -2103,7 +2120,7 @@ public class RepositoryManager { .append(" left join fetch v.lifecycle as lifecycle"); whereClauseLearningResourcesAsTeacher(sb); appendOrderBy(sb, "v", orderby); - + TypedQuery<RepositoryEntry> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("identityKey", identity.getKey()) @@ -2114,7 +2131,7 @@ public class RepositoryManager { List<RepositoryEntry> entries = query.getResultList(); return entries; } - + /** * Write the where clause for countLearningResourcesAsTeacher and getLearningResourcesAsTeacher * @param sb @@ -2126,7 +2143,7 @@ public class RepositoryManager { .append(" where (v.access>=3 or (v.access=").append(RepositoryEntry.ACC_OWNERS).append(" and v.membersOnly=true))") .append(" and membership.identity.key=:identityKey"); } - + public int countFavoritLearningResourcesAsTeacher(Identity identity, List<String> types) { StringBuilder sb = new StringBuilder(); sb.append("select count(v) from ").append(RepositoryEntry.class.getName()).append(" v ") @@ -2149,7 +2166,7 @@ public class RepositoryManager { } return query.getSingleResult().intValue(); } - + public List<RepositoryEntry> getFavoritLearningResourcesAsTeacher(IdentityRef identity, List<String> types, int firstResult, int maxResults, RepositoryEntryOrder... orderby) { StringBuilder sb = new StringBuilder(); @@ -2182,7 +2199,7 @@ public class RepositoryManager { } return query.getResultList(); } - + /** * Need a repository entry or identites to return a list. * @param re @@ -2191,7 +2208,7 @@ public class RepositoryManager { */ public List<RepositoryEntryMembership> getRepositoryEntryMembership(RepositoryEntryRef re, Identity... identity) { if(re == null && (identity == null || identity.length == 0)) return Collections.emptyList(); - + StringBuilder sb = new StringBuilder(400); sb.append("select distinct membership from repoentrymembership as membership "); boolean and = false; @@ -2220,30 +2237,30 @@ public class RepositoryManager { List<RepositoryEntryMembership> entries = query.getResultList(); return entries; } - + public List<RepositoryEntryMembership> getRepositoryEntryMembership(RepositoryEntryRef re) { if(re == null) return Collections.emptyList(); - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); sb.append("select membership.identity.key, membership.creationDate, membership.lastModified, membership.role ") .append(" from ").append(RepositoryEntry.class.getName()).append(" as v ") .append(" inner join v.groups as relGroup on relGroup.defaultGroup=true") .append(" inner join relGroup.group as baseGroup") .append(" inner join baseGroup.members as membership") .append(" where v.key=:repoKey"); - + List<Object[]> members = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Object[].class) .setParameter("repoKey", re.getKey()) .getResultList(); - + Map<Long, RepositoryEntryMembership> memberships = new HashMap<Long, RepositoryEntryMembership>(); for(Object[] membership:members) { Long identityKey = (Long)membership[0]; Date lastModified = (Date)membership[1]; Date creationDate = (Date)membership[2]; Object role = membership[3]; - + RepositoryEntryMembership mb = memberships.get(identityKey); if(mb == null) { mb = new RepositoryEntryMembership(); @@ -2253,7 +2270,7 @@ public class RepositoryManager { } mb.setCreationDate(creationDate); mb.setLastModified(lastModified); - + if(GroupRoles.participant.name().equals(role)) { mb.setParticipant(true); } else if(GroupRoles.coach.name().equals(role)) { @@ -2262,13 +2279,13 @@ public class RepositoryManager { mb.setOwner(true); } } - + return new ArrayList<RepositoryEntryMembership>(memberships.values()); } - + public List<RepositoryEntryMembership> getOwnersMembership(List<RepositoryEntry> res) { if(res== null || res.isEmpty()) return Collections.emptyList(); - + StringBuilder sb = new StringBuilder(400); sb.append("select distinct membership from ").append(RepositoryEntryMembership.class.getName()).append(" membership ") .append(" where membership.repoKey in (:repoKey)"); @@ -2281,7 +2298,7 @@ public class RepositoryManager { List<RepositoryEntryMembership> entries = query.getResultList(); return entries; } - + public void updateRepositoryEntryMemberships(Identity ureqIdentity, Roles ureqRoles, RepositoryEntry re, List<RepositoryEntryPermissionChangeEvent> changes, MailPackage mailing) { @@ -2297,11 +2314,11 @@ public class RepositoryManager { dbInstance.commitAndCloseSession(); sendDeferredEvents(deferredEvents, re); } - + private void updateRepositoryEntryMembership(Identity ureqIdentity, Roles ureqRoles, RepositoryEntry re, RepositoryEntryPermissionChangeEvent changes, MailPackage mailing, List<RepositoryEntryMembershipModifiedEvent> deferredEvents) { - + if(changes.getRepoOwner() != null) { if(changes.getRepoOwner().booleanValue()) { addOwners(ureqIdentity, new IdentitiesAddEvent(changes.getMember()), re); @@ -2310,7 +2327,7 @@ public class RepositoryManager { deferredEvents.add(RepositoryEntryMembershipModifiedEvent.removed(changes.getMember(), re)); } } - + if(changes.getRepoTutor() != null) { if(changes.getRepoTutor().booleanValue()) { addTutors(ureqIdentity, ureqRoles, new IdentitiesAddEvent(changes.getMember()), re, mailing); @@ -2319,7 +2336,7 @@ public class RepositoryManager { deferredEvents.add(RepositoryEntryMembershipModifiedEvent.removed(changes.getMember(), re)); } } - + if(changes.getRepoParticipant() != null) { if(changes.getRepoParticipant().booleanValue()) { addParticipants(ureqIdentity, ureqRoles, new IdentitiesAddEvent(changes.getMember()), re, mailing); @@ -2329,13 +2346,13 @@ public class RepositoryManager { } } } - + private final boolean and(StringBuilder sb, boolean and) { if(and) sb.append(" and "); else sb.append(" where "); return true; } - + private void appendOrderBy(StringBuilder sb, String var, RepositoryEntryOrder... orderby) { if(orderby != null && orderby.length > 0) { sb.append(" order by "); @@ -2348,7 +2365,7 @@ public class RepositoryManager { sb.append(var).append(".key asc"); } } - + public boolean isIdentityInTutorSecurityGroup(Identity identity, RepositoryEntryRef resource) { return repositoryEntryRelationDao.hasRole(identity, resource, GroupRoles.coach.name()); } diff --git a/src/main/java/org/olat/repository/RepositoryService.java b/src/main/java/org/olat/repository/RepositoryService.java index 13aa47c236a6f3d1087874a5091edb4a27da0aa5..71075201bb9e27a791849db6ea03d34b3478805e 100644 --- a/src/main/java/org/olat/repository/RepositoryService.java +++ b/src/main/java/org/olat/repository/RepositoryService.java @@ -40,68 +40,72 @@ import org.olat.resource.OLATResource; /** * To replace the repository manager - * - * + * + * * Initial date: 20.02.2014<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public interface RepositoryService { - + public static final OLATResourceable REPOSITORY_EVENT_ORES = OresHelper.createOLATResourceableInstance("REPO-CHANGE", 1l); - - + + public RepositoryEntry create(Identity initialAuthor, String initialAuthorAlt, String resourceName, String displayname, String description, OLATResource resource, int access); - + public RepositoryEntry create(String initialAuthor, String resourceName, String displayname, String description, OLATResource resource); - + public RepositoryEntry copy(RepositoryEntry sourceEntry, Identity author, String displayname); - + public RepositoryEntry loadByKey(Long key); - + public RepositoryEntry loadByResourceKey(Long key); - + + public List<RepositoryEntry> loadRepositoryEntriesByExternalId(String externalId); + + public List<RepositoryEntry> loadRepositoryEntriesByExternalRef(String externalRef); + public List<RepositoryEntry> loadByResourceKeys(Collection<Long> keys); - + /** * @param repositoryEntryKey The key of the repository entry * @return The olat resource of the repository entry */ public OLATResource loadRepositoryEntryResource(Long repositoryEntryKey); - + /** * @param softkey The soft key of the repository entry * @return The olat resource of the repository entry */ public OLATResource loadRepositoryEntryResourceBySoftKey(String softkey); - + public VFSLeaf getIntroductionImage(RepositoryEntry re); public VFSLeaf getIntroductionMovie(RepositoryEntry re); - - + + public RepositoryEntry update(RepositoryEntry re); - + /** * Set the access to 0. The resource is not deleted on the database * but the resource is removed from the catalog. - * - * + * + * * @param entry * @param owners If the owners need to be removed */ public RepositoryEntry deleteSoftly(RepositoryEntry entry, Identity deletedBy, boolean owners); - + /** * The access is set to B. * @param entry * @return */ public RepositoryEntry restoreRepositoryEntry(RepositoryEntry entry); - - + + /** * Delete the learning resource with all its attached resources. * @param entry @@ -111,16 +115,16 @@ public interface RepositoryService { * @return */ public ErrorList deletePermanently(RepositoryEntry entry, Identity identity, Roles roles, Locale locale); - + /** * Delete only the database object * @param entry */ public void deleteRepositoryEntryAndBaseGroups(RepositoryEntry entry); - + /** * This will change the status of the repository entry to "closed" (statusCode=2). - * + * * @param entry * @param identity * @param roles @@ -128,56 +132,56 @@ public interface RepositoryService { * @return The closed repository entry */ public RepositoryEntry closeRepositoryEntry(RepositoryEntry entry); - + public RepositoryEntry uncloseRepositoryEntry(RepositoryEntry entry); - + /** * The unpublish will remove the users (coaches and participants) but will let * the owners. Catalog entries will be removed and the relations to the business groups * will be deleted. - * + * * @param entry * @return */ public RepositoryEntry unpublishRepositoryEntry(RepositoryEntry entry); - + /** * Increment the launch counter and the last usage date. - * + * * @param re The repository entry */ public void incrementLaunchCounter(RepositoryEntry re); - + /** * Increment the download counter and the last usage date. - * + * * @param re The repository entry */ public void incrementDownloadCounter(RepositoryEntry re); - + /** * Update the last usage of the specified repository entry * with a granularity of 1 minute. - * + * * @param re The repository entry */ public void setLastUsageNowFor(RepositoryEntry re); public Group getDefaultGroup(RepositoryEntryRef ref); - + /** - * + * * @param identity * @param entry * @return True if the identity is member of the repository entry and its attached business groups */ public boolean isMember(IdentityRef identity, RepositoryEntryRef entry); - + public void filterMembership(IdentityRef identity, List<Long> entries); - + public int countMembers(RepositoryEntryRef re, String... roles); - + /** * Count all members (following up to business groups wainting list) * @param res @@ -185,98 +189,98 @@ public interface RepositoryService { * @return */ public int countMembers(List<? extends RepositoryEntryRef> res, Identity excludeMe); - + /** * Return the smallest enrollment date. - * + * * @param re * @param identity * @return */ public Date getEnrollmentDate(RepositoryEntryRef re, IdentityRef identity, String... roles); - + /** * Return the smallest enrollment date. - * + * * @param re * @param identity * @return */ public Map<Long,Date> getEnrollmentDates(RepositoryEntryRef re, String... roles); - + /** * @param re The repository entry * @return True if the configuration allowed user to leave the entry right now */ public boolean isParticipantAllowedToLeave(RepositoryEntry re); - + /** * Return the primary keys of the authors */ public List<Long> getAuthors(RepositoryEntryRef re); - + /** * Get the members of the repository entry (the method doesn't * follow the business groups). - * + * * @param re * @param roles * @return */ public List<Identity> getMembers(RepositoryEntryRef re, String... roles); - + /** - * Get the + * Get the * @param re * @param followBusinessGroups * @param roles * @return */ public List<Identity> getMembers(List<? extends RepositoryEntryRef> re, RepositoryEntryRelationType relationType, String... roles); - + /** * Return all the identities the specified role linked to a repository * entry. - * - * + * + * * @param rolle * @return */ public List<Identity> getIdentitiesWithRole(String role); - + /** * Get the role in the specified resource, business group are included in * the query. - * + * * @return The list of roles */ public List<String> getRoles(Identity identity, RepositoryEntryRef re); - + /** * Has specific role in the specified resource (doesn't follow the business groups). - * + * * @return True if the specified role(s) was found. */ public boolean hasRole(Identity identity, RepositoryEntryRef re, String... roles); - + /** * Has specific role in any resource (follow or not the business groups). - * + * * @return True if the specified role(s) was found. */ public boolean hasRole(Identity identity, boolean followBusinessGroups, String... roles); - - + + public void addRole(Identity identity, RepositoryEntry re, String role); - + public void removeRole(Identity identity, RepositoryEntry re, String role); - + public void removeMembers(RepositoryEntry re, String... roles); - + public List<RepositoryEntry> searchByIdAndRefs(String id); - + public int countMyView(SearchMyRepositoryEntryViewParams params); - + /** * The identity is mandatory for the search. * @param params @@ -285,8 +289,8 @@ public interface RepositoryService { * @return */ public List<RepositoryEntryMyView> searchMyView(SearchMyRepositoryEntryViewParams params, int firstResult, int maxResults); - + public int countAuthorView(SearchAuthorRepositoryEntryViewParams params); - + public List<RepositoryEntryAuthorView> searchAuthorView(SearchAuthorRepositoryEntryViewParams params, int firstResult, int maxResults); } diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties index 6b98813ae1005e84cf532ff04ca7458ddea62921..2059de1b21bfcd517aa6e4dc8d0af63829dcadea 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties @@ -135,6 +135,10 @@ cif.membership.mandatory=Meine Kurse cif.objectives=Lernziele cif.ores_id=OpenOLAT-Ressourcen-ID cif.owned.resources.only=Meine Ressourcen +cif.owned.resources.usage=Referenzierte Ressourcen +cif.owned.resources.usage.all=Alle +cif.owned.resources.usage.used=Referenziert +cif.owned.resources.usage.notUsed=Nicht referenziert cif.owners=Autoren cif.private.dates=Datum cif.public.dates=Semester @@ -215,6 +219,7 @@ details.delete.acknowledge=Best\u00E4tigung details.delete.acknowledge.error=Bitte best\u00E4tigen. details.delete.acknowledge.msg=Alle Dateien werden definitiv gel\u00F6scht und k\u00F6nnen nicht mehr wiederhergestellt werden. details.delete.alt={0} l\u00F6schen +details.delete.soft.acknowledge.msg=Die Lernressource wird als gel\u00F6scht markiert. details.delete.soft.desc=Mit dieser Funktion wird die Lernressource als gel\u00F6scht markiert. details.delete.soft.desc.1=Die Benutzerdaten werden aus dem Kurs entfernt. details.delete.soft.desc.2=Nur noch der Kursbesitzer hat Zugriff auf den Kurs. @@ -375,7 +380,7 @@ no.lifecycle=Keine Einschr\u00E4nkung no.catalog.entries=Diese Resource wurde noch nicht im Katalog registriert. \r\n\r\n Verwenden Sie den "In Katalog einf\u00FCgen" Button in der Toolbar, um die Resource auf einer bestimmten Katalog-Ebenen hinzuzuf\u00FCgen. Der Katalog erlaubt es dem Benutzer je nach Zugriffskonfiguration nach bestimmten Eintr\u00E4gen zu suchen. Sie k\u00F6nnen die Resource auf mehreren Katalog-Ebenen hinzuf\u00FCgen. info.catalog.entries=Verwenden Sie den "In Katalog einf\u00FCgen" Button in der Toolbar, um die Resource auf einer bestimmten Katalog-Ebenen hinzuzuf\u00FCgen. Der Katalog erlaubt es dem Benutzer je nach Zugriffskonfiguration nach bestimmten Eintr\u00E4gen zu suchen. Sie k\u00F6nnen die Resource auf mehreren Katalog-Ebenen hinzuf\u00FCgen. nomembers=XXX No members -notification.mail.added.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\nSie wurden von {0} {1} ({2}) in einen Kurs eingeladen\: \n\nKursname\: $coursename\nBeschreibung\: $coursedescription\n\nBei Fragen kontaktieren Sie bitte {0} {1} ({2}). +notification.mail.added.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\nSie wurden von {0} {1} ({2}) in einen Kurs eingeladen\: \n\nKursname\: $coursename\nBeschreibung\: $coursedescription\nZugang\: $courseurl\n\nBei Fragen kontaktieren Sie bitte {0} {1} ({2}). notification.mail.added.subject=Kurs $coursename notification.mail.removed.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\nSie wurden von {0} {1} ({2}) aus dem Kurs ausgetragen\: \n\nKursname\: $coursename\nBeschreibung\: $coursedescription\n\nBei Fragen kontaktieren Sie bitte {0} {1} ({2}). notification.mail.removed.subject=Kurs $coursename\: Sie wurden ausgetragen. @@ -524,7 +529,7 @@ table.header.details=<i class\='o_icon o_icon_details o_icon-lg'> </i> table.header.displayname=Titel der Lernressource table.header.edit=<i class\='o_icon o_icon_edit o_icon-lg'> </i> table.header.externalid=Ext. ID -table.header.externalref=Ext. Ref. +table.header.externalref=Kennzeichen table.header.firstName=$org.olat.group.ui.main\:table.header.firstName table.header.firstTime=$org.olat.group.ui.main\:table.header.firstTime table.header.freePlace=$org.olat.group.ui.main\:table.header.freePlace @@ -545,6 +550,7 @@ table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Fa table.header.online=$org.olat.group.ui.main\:table.header.online table.header.participants=$org.olat.group.ui.main\:table.header.participants table.header.participantsCount=$org.olat.group.ui.main\:table.header.participantsCount +table.header.references=Ref. table.header.remove=$org.olat.group.ui.main\:table.header.remove table.header.role=$org.olat.group.ui.main\:table.header.role table.header.start=Starten diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties index a35e1a54d8748bfca30d2ae74aa489c39be7c38c..0bb90ebf9244706b2426c292fadda81a929edad0 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties @@ -130,7 +130,11 @@ cif.managedflags=Externally managed modules cif.membership.mandatory=My courses only cif.objectives=Objectives cif.ores_id=OpenOLAT resource ID -cif.owned.resources.only=My ressources +cif.owned.resources.only=My resources +cif.owned.resources.usage=Referenced resources +cif.owned.resources.usage.all=All +cif.owned.resources.usage.used=Referenced +cif.owned.resources.usage.notUsed=Not referenced cif.owners=Authoring rights cif.private.dates=Dates cif.public.dates=Semester @@ -219,6 +223,7 @@ details.delete.managed=managed details.delete.notOrphan=still referenced details.delete.notOwner=not owner details.delete.references=Do you wish to delete the referenced learning resources too? +details.delete.soft.acknowledge.msg=The learning resource will be marked as deleted. details.delete.soft.auto.desc=<strong>The course will be automatically deleted at {0}.</strong> details.delete.soft.desc=Using this method the learning resource will be marked as deleted. details.delete.soft.desc.1=The user data will be removed from the course. @@ -372,7 +377,7 @@ no.lifecycle=No limitation no.catalog.entries=This resource has not been added to the catalog yet. \r\n\r\n Use the "Add to catalog" button in the toolbar above to add the resource to a specific level in the catalog. The catalog allows users to browse for available resources depending on th resource access configuration. You can add the resource to multiple catalog levels. info.catalog.entries=Use the "Add to catalog" button in the toolbar above to add the resource to a specific level in the catalog. The catalog allows users to browse for available resources depending on th resource access configuration. You can add the resource to multiple catalog levels. nomembers=XXX No members -notification.mail.added.body=*** This is an automatically generated message. Please do not answer to this message *** \r\n\r\nYou have been added by {0} {1} ({2}) to a course\:\r\n\r\nCourse name\: $coursename\r\nDescription\: $coursedescription\r\n\r\nIf you have questions regarding this action, please contact {0} {1} ({2}). +notification.mail.added.body=*** This is an automatically generated message. Please do not answer to this message *** \r\n\r\nYou have been added by {0} {1} ({2}) to a course\:\r\n\r\nCourse name\: $coursename\r\nDescription\: $coursedescription\nLink\: $courseurl\n\nIf you have questions regarding this action, please contact {0} {1} ({2}). notification.mail.added.subject=Course $coursename notification.mail.removed.body=*** This is an automatically generated message. Please do not answer to this message *** \r\n\r\nYou have been removed by {0} {1} ({2}) from a course\:\r\n\r\nCourse name\: $coursename\r\nDescription\: $coursedescription\r\n\r\nIf you have questions regarding this action, please contact {0} {1} ({2}). notification.mail.removed.subject=Course $coursename\: you have been removed. @@ -542,6 +547,7 @@ table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Bo table.header.online=$org.olat.group.ui.main\:table.header.online table.header.participants=$org.olat.group.ui.main\:table.header.participants table.header.participantsCount=$org.olat.group.ui.main\:table.header.participantsCount +table.header.references=Ref. table.header.remove=$org.olat.group.ui.main\:table.header.remove table.header.role=$org.olat.group.ui.main\:table.header.role table.header.start=Launch diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties index 61ccf1edf081b57c8e199762b661c1eb5edf6f6d..ce3b4f04270771a9df972334b20e3663e9efada6 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Thu Jun 08 21:34:52 CEST 2017 +#Tue Aug 15 17:30:54 CEST 2017 BinderTemplate=Mod\u00E8le de portfolio 2.0 CourseModule=Cours EPStructuredMapTemplate=Mod\u00E8le de portfolio @@ -131,6 +131,10 @@ cif.membership.mandatory=Mes cours cif.objectives=Objectifs cif.ores_id=OpenOLAT Resource Id cif.owned.resources.only=Mes ressources +cif.owned.resources.usage=Ressources r\u00E9f\u00E9renc\u00E9es +cif.owned.resources.usage.all=Toutes +cif.owned.resources.usage.notUsed=Pas r\u00E9f\u00E9renc\u00E9es +cif.owned.resources.usage.used=R\u00E9f\u00E9renc\u00E9es cif.owners=Auteurs cif.private.dates=Date cif.public.dates=Semestre @@ -219,6 +223,7 @@ details.delete.managed=managed details.delete.notOrphan=encore r\u00E9f\u00E9renc\u00E9 details.delete.notOwner=pas propri\u00E9taire details.delete.references=Voulez-vous effacer les objects didactiques r\u00E9f\u00E9renc\u00E9s par cette resource? +details.delete.soft.acknowledge.msg=La ressource didactique sera marqu\u00E9e comme effac\u00E9e. details.delete.soft.auto.desc=<strong>Le cours sera automatiquement effac\u00E9 le {0}.</strong> details.delete.soft.desc=Avec cette fonction, la ressource didactique sera marqu\u00E9e comme effac\u00E9e. details.delete.soft.desc.1=Les donn\u00E9es utilisateurs du cours seront effac\u00E9es. @@ -323,6 +328,7 @@ import.file=Fichier import.member=$org.olat.group.ui.main\:import.member index.header=Ressources didactiques index.header.alt=Recherchez des ressources didactiques +info.catalog.entries=Utilisez le bouton "Ajouter au catalogue" dans la barre d'outils pour ajouter l'objet didactique au catalogue. Le catalogue permet \u00E0 l'utilisateur de trouver des objets didactiques en fonction de la configuration d'acc\u00E8s des entr\u00E9es. Vous pouvez ajouter les ressources \u00E0 diff\u00E9rents niveaux du catalogue. info.could.not.delete.entry=L'entr\u00E9e n'a pas \u00E9t\u00E9 \u00E9limin\u00E9e. info.entry.deleted=L'entr\u00E9e a \u00E9t\u00E9 supprim\u00E9e info.entry.read.only=L'objet didactique a \u00E9t\u00E9 termin\u00E9. @@ -368,9 +374,10 @@ new.test=Cr\u00E9er test new.test.intro=Cr\u00E9er un nouveau test. new.wiki=Cr\u00E9er Wiki new.wiki.intro=Cr\u00E9er un nouvel Wiki +no.catalog.entries=Cet object didactique n'est pas encore dans le catalogue. Utilisez le bouton "Ajouter au catalogue" dans la barre d'outils pour ins\u00E9rer l'objet didactique au catalogue. Le catalogue permet \u00E0 l'utilisateur de trouver des objets didactiques en fonction de la configuration d'acc\u00E8s des entr\u00E9es. Vous pouvez ajouter les ressources \u00E0 diff\u00E9rents niveaux du catalogue. no.lifecycle=Pas de limitation nomembers=Pas de membres -notification.mail.added.body=*** Ceci est un message g\u00E9n\u00E9r\u00E9 automatiquement. S'il vous pla\u00EEt, ne r\u00E9pondez pas \u00E0 ce message ***\r\n\r\nVous avez \u00E9t\u00E9 invit\u00E9 par {0} {1} ({2}) \u00E0 prendre part \u00E0 un cours\:\r\n\r\nNom du cours\: $coursename\r\nDescription\: $coursedescription\r\n\r\nSi vous avez des questions, veuillez contacter {0} {1} ({2}). +notification.mail.added.body=*** Ceci est un message g\u00E9n\u00E9r\u00E9 automatiquement. S'il vous pla\u00EEt, ne r\u00E9pondez pas \u00E0 ce message ***\r\n\r\nVous avez \u00E9t\u00E9 invit\u00E9 par {0} {1} ({2}) \u00E0 prendre part \u00E0 un cours\:\r\n\r\nNom du cours\: $coursename\r\nDescription\: $coursedescription\r\nLien\: $courseurl\r\n\r\nSi vous avez des questions, veuillez contacter {0} {1} ({2}). notification.mail.added.subject=Cours $coursename notification.mail.removed.body=*** Ceci est un message g\u00E9n\u00E9r\u00E9 automatiquement. S'il vous pla\u00EEt, ne r\u00E9pondez pas \u00E0 ce message ***\r\n\r\nVous avez \u00E9t\u00E9 retir\u00E9 par {0} {1} ({2}) d'un cours\:\r\n\r\nNom du cours\: $coursename\r\nDescription\: $coursedescription\r\n\r\nSi vous avez des questions, veuillez contacter {0} {1} ({2}). notification.mail.removed.subject=Cours $coursename\: vous avez \u00E9t\u00E9 d\u00E9sinscrit. @@ -540,6 +547,7 @@ table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Fa table.header.online=$org.olat.group.ui.main\:table.header.online table.header.participants=$org.olat.group.ui.main\:table.header.participants table.header.participantsCount=$org.olat.group.ui.main\:table.header.participantsCount +table.header.references=R\u00E9f. table.header.remove=$org.olat.group.ui.main\:table.header.remove table.header.role=$org.olat.group.ui.main\:table.header.role table.header.start=D\u00E9marrer diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_it.properties index 9f67b506826fa49a28d96fca6f22329296d48256..10838139aaaadc640987abec973090b54395d13a 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_it.properties @@ -358,7 +358,7 @@ new.wiki=Creare Wiki new.wiki.intro=Creare un nuovo Wiki no.lifecycle=Senza limitazioni nomembers=Nessun membro -notification.mail.added.body=*** Questo \u00E8 un messaggio generato automaticamente. Non rispondere a questo messaggio *** \r\n\r\nSei stato aggiunto da {0} {1} ({2}) in un corso\:\r\n\r\nNome del corso\: $coursename\r\nDescrizione\: $coursedescription\r\n\r\nSe hai domande riguardanti questa azione, contatta {0} {1} ({2}). +notification.mail.added.body=*** Questo \u00E8 un messaggio generato automaticamente. Non rispondere a questo messaggio *** \r\n\r\nSei stato aggiunto da {0} {1} ({2}) in un corso\:\r\n\r\nNome del corso\: $coursename\r\nDescrizione\: $coursedescription\r\nURL\:$courseurl\r\n\r\nSe hai domande riguardanti questa azione, contatta {0} {1} ({2}). notification.mail.added.subject=Corso $coursename notification.mail.removed.body=*** Questo \u00E8 un messaggio generato automaticamente. Non rispondere a questo messaggio *** \r\n\r\nSei stato rimosso da {0} {1} ({2}) da un corso\:\r\n\r\nNome del corso\: $coursename\r\nDescrizione\: $coursedescription\r\n\r\nSe hai domande riguardanti questa azione, contatta {0} {1} ({2}). notification.mail.removed.subject=Corso $coursename\: sei stato rimosso. diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_pl.properties index 358d8c3d2956ec99c27905c683811570641dca6f..118847c3bc1bf2d5aa0747c32602c3d4805529ab 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_pl.properties @@ -1,4 +1,4 @@ -#Thu Sep 03 11:24:43 CEST 2015 +#Mon Aug 21 14:37:31 CEST 2017 CourseModule=Kurs Failed=Przesy\u0142anie tego pliku nie powiod\u0142o si\u0119. FileResource.ANIM=Animacja @@ -52,100 +52,6 @@ add.wrongtype=Format tego zasobu edukacyjnego nie odpowiada wybranemu formatowi. addinfo.owner=Dodatkowe informacje assessment=$org.olat.group.ui.main\:assessment cap.launch=\u0141adowanie zasobu edukacyjnego. Prosz\u0119 czeka\u0107... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - chkbx.calendar.onoff=Kalendarz chkbx.chat.onoff=Aktywuj czata kursu chkbx.efficency.onoff=Wykaz osi\u0105gni\u0119\u0107 @@ -276,9 +182,6 @@ glossary.no.glossary=Nie wybrano s\u0142ownika groups.header=Przypisz w\u0142a\u015Bcicieli zasobu edukacyjnego groups.intro=Przypisz u\u017Cytkownik\u00F3w OpenOLAT do w\u0142a\u015Bcicieli wybranego zasobu edukacyjnego.<br />W\u0142a\u015Bciciele mog\u0105 czyta\u0107, modyfikowa\u0107 i usuwa\u0107 zas\u00F3b edukacyjny. heading.disabled=Funkcja niedost\u0119pna - - - home=$org.olat.group.ui.main\:home import.member=$org.olat.group.ui.main\:import.member index.header=Zasoby edukacyjne @@ -308,7 +211,7 @@ new.wiki=Utw\u00F3rz Wiki new.wiki.intro=Utw\u00F3rz now\u0105 Wiki no.lifecycle=Bez ogranicze\u0144 nomembers=XXX No members -notification.mail.added.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \r\n\r\nZosta\u0142e\u015B dodany przez {0} {1} ({2}) do kursu\:\r\n\r\nNazwa kursu\: $coursename\r\nOpis\: $coursedescription\r\n\r\nW razie pyta\u0144 skontaktuj si\u0119 z {0} {1} ({2}). +notification.mail.added.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \r\n\r\nZosta\u0142e\u015B dodany przez {0} {1} ({2}) do kursu\:\r\n\r\nNazwa kursu\: $coursename\r\nOpis\: $coursedescription\r\nURL\: $courseurl\r\n\r\nW razie pyta\u0144 skontaktuj si\u0119 z {0} {1} ({2}). notification.mail.added.subject=Kurs $coursename notification.mail.removed.body=*** Wiadomo\u015B\u0107 generowana automatycznie, nie odpowiadaj na ni\u0105 *** \r\n\r\nZosta\u0142e\u015B usuni\u0119ty przez {0} {1} ({2}) z kursu\:\r\n\r\nNazwa kursu\: $coursename\r\nOpis\: $coursedescription\r\n\r\nW razie pyta\u0144 skontaktuj si\u0119 z {0} {1} ({2}). notification.mail.removed.subject=Kurs $coursename\: zosta\u0142e\u015B usuni\u0119ty. @@ -343,8 +246,11 @@ scorm.no.scorm.namespace=Materia\u0142 SCORM nie zosta\u0142 dodany. Tw\u00F3j p search.blog=Blogi search.catalog=Katalog search.course=Kursy +search.courses.closed=Zako\u0144czone search.courses.student=Szukaj search.cp=Pakiety CP +search.deleted=Usuni\u0119te +search.filter.showAll=Wszystkie search.generic=Wyszukiwarka search.glossary=S\u0142owniki search.home=Zasoby edukacyjne @@ -362,8 +268,10 @@ search.sharedfolder=Folder zasob\u00F3w search.survey=Ankiety search.test=Testy search.wiki=Wiki +security.disabled.info=Zas\u00F3b niedost\u0119pny ze wzgl\u0119d\u00F3w bezpiecze\u0144stwa. Skontaktuj si\u0119 z administratorem. sf.notconfigured=Nie wybrano folderu zasob\u00F3w sf.resourcetitle=Folder zasob\u00F3w +sign.out=Zrezygnuj z kursu tab.calendar=Kalendarz tab.chat=Czat kursu tab.efficencystatement=Wykaz osi\u0105gni\u0119\u0107 diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_BR.properties index 74aa3cfad43cf3b74bc55c76a1d251ab1440b9a5..edfe5202fa40d9c8d9a5ee36825e97d0a425250f 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Fri Jun 23 15:07:23 CEST 2017 +#Tue Sep 19 20:29:38 CEST 2017 BinderTemplate=Modelo Portfolio 2.0 CourseModule=Curso EPStructuredMapTemplate=Template/modelo de Portfolio @@ -131,6 +131,10 @@ cif.membership.mandatory=Meus cursos apenas cif.objectives=Objetivos cif.ores_id=OpenOLAT-ID do recurso cif.owned.resources.only=Meus recursos +cif.owned.resources.usage=Recursos referenciados +cif.owned.resources.usage.all=Todos +cif.owned.resources.usage.notUsed=N\u00E3o referenciado +cif.owned.resources.usage.used=Referenciado cif.owners=Autores cif.private.dates=Datas cif.public.dates=Semestre @@ -219,6 +223,7 @@ details.delete.managed=Gerenciado details.delete.notOrphan=Ainda referenciado details.delete.notOwner=N\u00E3o propriet\u00E1rio details.delete.references=Voc\u00EA quer apagar as refer\u00EAncias tamb\u00E9m? +details.delete.soft.acknowledge.msg=O recurso did\u00E1tico ser\u00E1 marcado como exclu\u00EDdo. details.delete.soft.auto.desc=<strong>O curso ser\u00E1 automaticamente exclu\u00EDdo em {0}.</strong> details.delete.soft.desc=Usando este m\u00E9todo, o recurso did\u00E1tico ser\u00E1 marcado como exclu\u00EDdo. details.delete.soft.desc.1=Os dados de usu\u00E1rios ser\u00E3o removidos do curso. @@ -372,7 +377,7 @@ new.wiki.intro=Criar novo wiki no.catalog.entries=Este recurso ainda n\u00E3o foi adicionado ao cat\u00E1logo. Use o bot\u00E3o "Adicionar ao cat\u00E1logo" na barra de ferramentas acima para adicionar o recurso a um n\u00EDvel espec\u00EDfico no cat\u00E1logo. O cat\u00E1logo permite aos usu\u00E1rios procurar recursos dispon\u00EDveis dependendo da configura\u00E7\u00E3o de acesso a recursos. Voc\u00EA pode adicionar o recurso a v\u00E1rios n\u00EDveis do cat\u00E1logo. no.lifecycle=Nenhuma limita\u00E7\u00E3o nomembers=XXX No members -notification.mail.added.body=*** Esta \u00E9 uma mensagem gerada automaticamente. Por favor, n\u00E3o responda a esta mensagem ***\r\n\r\nVoc\u00EA foi adicionado por {0} {1} ({2}) para um curso\:\r\n\r\nNome do curso\: $coursename\r\nDescri\u00E7\u00E3o\: $coursedescription\r\n\r\nSe voc\u00EA tem alguma d\u00FAvida sobre esta a\u00E7\u00E3o, entre em contato {0} {1} ({2}). +notification.mail.added.body=*** Esta \u00E9 uma mensagem gerada automaticamente. Por favor, n\u00E3o responda a esta mensagem ***\r\n\r\nVoc\u00EA foi adicionado por {0} {1} ({2}) para um curso\:\r\n\r\nNome do curso\: $coursename\r\nDescri\u00E7\u00E3o\: $coursedescription\r\nURL\: $courseurl\r\n\r\nSe voc\u00EA tem alguma d\u00FAvida sobre esta a\u00E7\u00E3o, entre em contato {0} {1} ({2}). notification.mail.added.subject=Curso $coursename notification.mail.removed.body=*** Esta \u00E9 uma mensagem gerada automaticamente. Por favor, n\u00E3o responda a esta mensagem ***\r\n\r\nVoc\u00EA foi removido por {0} {1} ({2}) de um curso\:\r\n\r\nNome do curso\: $coursename\r\nDescri\u00E7\u00E3o\: $coursedescription\r\n\r\nSe voc\u00EA tem d\u00FAvidas sobre esta a\u00E7\u00E3o, entre em contato {0} {1} ({2}). notification.mail.removed.subject=Curso $coursename\: voc\u00EA foi removido. @@ -542,6 +547,7 @@ table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Fa table.header.online=$org.olat.group.ui.main\:table.header.online table.header.participants=$org.olat.group.ui.main\:table.header.participants table.header.participantsCount=$org.olat.group.ui.main\:table.header.participantsCount +table.header.references=Ref. table.header.remove=$org.olat.group.ui.main\:table.header.remove table.header.role=$org.olat.group.ui.main\:table.header.role table.header.start=In\u00EDcio diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_CN.properties index 96ae112ae6a34f229f266d17344ecbefde46fed0..6dbda79b0cbd2e9904d20cd22b5559f220e7a059 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_CN.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_zh_CN.properties @@ -203,7 +203,7 @@ new.wiki=\u521B\u5EFA\u7EF4\u57FA new.wiki.intro=\u521B\u5EFA\u65B0\u7EF4\u57FA no.lifecycle=\u65E0\u9650\u5236 nomembers=XXX\u53F7\u6210\u5458 -notification.mail.added.body=***\u8FD9\u662F\u81EA\u52A8\u4EA7\u751F\u7684\u4FE1\u606F\u3002\u8BF7\u60A8\u4E0D\u8981\u56DE\u590D***\r\n\r\n\u60A8\u88AB{0}{1}{2}\u9080\u8BF7\u53C2\u52A0\u8BFE\u7A0B\uFF1A\r\n\r\n\u8BFE\u7A0B\u540D\u79F0\uFF1A$coursename\r\n\u8BFE\u7A0B\u63CF\u8FF0\uFF1A$coursedescription\r\n\r\n\u5982\u679C\u6709\u95EE\u9898\u8BF7\u60A8\u8054\u7CFB{0}{1}{2}\u3002 +notification.mail.added.body=***\u8FD9\u662F\u81EA\u52A8\u4EA7\u751F\u7684\u4FE1\u606F\u3002\u8BF7\u60A8\u4E0D\u8981\u56DE\u590D***\r\n\r\n\u60A8\u88AB{0}{1}{2}\u9080\u8BF7\u53C2\u52A0\u8BFE\u7A0B\uFF1A\r\n\r\n\u8BFE\u7A0B\u540D\u79F0\uFF1A$coursename\r\n\u8BFE\u7A0B\u63CF\u8FF0\uFF1A$coursedescription\r\nURL\: $courseurl\r\n\r\n\u5982\u679C\u6709\u95EE\u9898\u8BF7\u60A8\u8054\u7CFB{0}{1}{2}\u3002 notification.mail.added.subject=\u8BFE\u7A0B $coursename notification.mail.removed.body=***\u8FD9\u662F\u81EA\u52A8\u4EA7\u751F\u7684\u4FE1\u606F\u3002\u8BF7\u60A8\u4E0D\u8981\u56DE\u590D***\r\n\r\n\u60A8\u88AB{0}{1}{2}\u767B\u51FA\u4EE5\u4E0B\u8BFE\u7A0B\uFF1A\r\n\r\n\u8BFE\u7A0B\u540D\u79F0\uFF1A$coursename\r\n\u8BFE\u7A0B\u63CF\u8FF0\uFF1A$coursedescription\r\n\r\n\u5982\u679C\u6709\u95EE\u9898\u8BF7\u60A8\u8054\u7CFB{0}{1}{2}\u3002 notification.mail.removed.subject=\u8BFE\u7A0B $coursename\uFF1A\u60A8\u88AB\u767B\u51FA\u3002 diff --git a/src/main/java/org/olat/repository/_spring/repositoryContext.xml b/src/main/java/org/olat/repository/_spring/repositoryContext.xml index 42418ac70ceaccbf098de19278af84a3b048cb2c..9c0dc8925cf895d0f414a4e338c013eaba2ec802 100644 --- a/src/main/java/org/olat/repository/_spring/repositoryContext.xml +++ b/src/main/java/org/olat/repository/_spring/repositoryContext.xml @@ -10,13 +10,13 @@ <context:component-scan base-package="org.olat.repository" /> - <bean id="automaticLifecycleTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="automaticLifecycleTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="automaticLifecycleJob" /> <property name="cronExpression" value="0 45 5 * * ?" /> <property name="startDelay" value="55000" /> </bean> - <bean id="automaticLifecycleJob" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="automaticLifecycleJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.repository.manager.AutomaticLifecycleJob" /> </bean> diff --git a/src/main/java/org/olat/repository/handlers/BlogHandler.java b/src/main/java/org/olat/repository/handlers/BlogHandler.java index c231436f175ebd64ed895af1194ee3642dd32d44..da468173d2eb041d1120bfcf36c86c68266e76d1 100644 --- a/src/main/java/org/olat/repository/handlers/BlogHandler.java +++ b/src/main/java/org/olat/repository/handlers/BlogHandler.java @@ -48,6 +48,8 @@ import org.olat.fileresource.FileResourceManager; import org.olat.fileresource.types.BlogFileResource; import org.olat.fileresource.types.FileResource; import org.olat.fileresource.types.ResourceEvaluation; +import org.olat.modules.webFeed.Feed; +import org.olat.modules.webFeed.FeedChangedEvent; import org.olat.modules.webFeed.FeedResourceSecurityCallback; import org.olat.modules.webFeed.FeedSecurityCallback; import org.olat.modules.webFeed.manager.FeedManager; @@ -72,7 +74,6 @@ import org.olat.resource.references.ReferenceManager; * * @author Gregor Wassmann */ -// Loads of parameters are unused public class BlogHandler implements RepositoryHandler { @Override @@ -238,4 +239,14 @@ public class BlogHandler implements RepositoryHandler { public boolean isLocked(OLATResourceable ores) { return FeedManager.getInstance().isLocked(ores); } + + @Override + public void onDescriptionChanged(RepositoryEntry entry) { + Feed feed = FeedManager.getInstance().updateFeedWithRepositoryEntry(entry); + DBFactory.getInstance().commitAndCloseSession(); + + CoordinatorManager.getInstance().getCoordinator().getEventBus() + .fireEventToListenersOf(new FeedChangedEvent(feed.getKey()), feed); + } + } \ No newline at end of file diff --git a/src/main/java/org/olat/repository/handlers/CourseHandler.java b/src/main/java/org/olat/repository/handlers/CourseHandler.java index 3661f0ecc39caa4f61581ab6f75270151dde0be0..c2cfbf276217e4b6666b9c62c0f5088efe448ace 100644 --- a/src/main/java/org/olat/repository/handlers/CourseHandler.java +++ b/src/main/java/org/olat/repository/handlers/CourseHandler.java @@ -26,6 +26,8 @@ package org.olat.repository.handlers; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.FileVisitResult; @@ -254,9 +256,29 @@ public class CourseHandler implements RepositoryHandler { course = CourseFactory.loadCourse(cgm.getCourseResource()); course.postImport(fImportBaseDirectory, envMapper); - //rename root nodes - course.getRunStructure().getRootNode().setShortTitle(Formatter.truncateOnly(displayname, 25)); //do not use truncate! - course.getRunStructure().getRootNode().setLongTitle(displayname); + //rename root nodes, but only when user modified the course title + boolean doUpdateTitle = true; + File repoConfigXml = new File(fImportBaseDirectory, "repo.xml"); + if (repoConfigXml.exists()) { + RepositoryEntryImport importConfig; + try { + importConfig = RepositoryEntryImportExport.getConfiguration(new FileInputStream(repoConfigXml)); + if(importConfig != null) { + if (displayname.equals(importConfig.getDisplayname())) { + // do not update if title was not modified during import + // user does not expect to have an updated title and there is a chance + // the root node title is not the same as the course title + doUpdateTitle = false; + } + } + } catch (FileNotFoundException e) { + // ignore + } + } + if (doUpdateTitle) { + course.getRunStructure().getRootNode().setShortTitle(Formatter.truncateOnly(displayname, 25)); //do not use truncate! + course.getRunStructure().getRootNode().setLongTitle(displayname); + } //course.saveRunStructure(); CourseEditorTreeNode editorRootNode = ((CourseEditorTreeNode)course.getEditorTreeModel().getRootNode()); editorRootNode.getCourseNode().setShortTitle(Formatter.truncateOnly(displayname, 25)); //do not use truncate! @@ -458,6 +480,7 @@ public class CourseHandler implements RepositoryHandler { Reminder clonedReminder = reminderService.createReminder(target, author); clonedReminder.setDescription(reminder.getDescription()); + clonedReminder.setEmailSubject(reminder.getEmailSubject()); clonedReminder.setEmailBody(reminder.getEmailBody()); clonedReminder.setConfiguration(reminderService.toXML(clonedRules)); reminderService.save(clonedReminder); diff --git a/src/main/java/org/olat/repository/handlers/PodcastHandler.java b/src/main/java/org/olat/repository/handlers/PodcastHandler.java index 2f08f48615557d1a2586109c43e492a408def20b..682d0f7e9171eb8383e82ec9506cfb0a82f90763 100644 --- a/src/main/java/org/olat/repository/handlers/PodcastHandler.java +++ b/src/main/java/org/olat/repository/handlers/PodcastHandler.java @@ -48,6 +48,8 @@ import org.olat.fileresource.FileResourceManager; import org.olat.fileresource.types.FileResource; import org.olat.fileresource.types.PodcastFileResource; import org.olat.fileresource.types.ResourceEvaluation; +import org.olat.modules.webFeed.Feed; +import org.olat.modules.webFeed.FeedChangedEvent; import org.olat.modules.webFeed.FeedResourceSecurityCallback; import org.olat.modules.webFeed.FeedSecurityCallback; import org.olat.modules.webFeed.manager.FeedManager; @@ -72,7 +74,6 @@ import org.olat.resource.references.ReferenceManager; * * @author Gregor Wassmann */ -// Loads of parameters are unused public class PodcastHandler implements RepositoryHandler { @Override @@ -232,4 +233,14 @@ public class PodcastHandler implements RepositoryHandler { public boolean isLocked(OLATResourceable ores) { return FeedManager.getInstance().isLocked(ores); } + + @Override + public void onDescriptionChanged(RepositoryEntry entry) { + Feed feed = FeedManager.getInstance().updateFeedWithRepositoryEntry(entry); + DBFactory.getInstance().commitAndCloseSession(); + + CoordinatorManager.getInstance().getCoordinator().getEventBus() + .fireEventToListenersOf(new FeedChangedEvent(feed.getKey()), feed); + } + } \ No newline at end of file diff --git a/src/main/java/org/olat/repository/handlers/RepositoryHandler.java b/src/main/java/org/olat/repository/handlers/RepositoryHandler.java index e4c1779091c200468fa4edf70f7927f7cd6560ca..d4a52561448afd16ac358f845d7db1fc659e4493 100644 --- a/src/main/java/org/olat/repository/handlers/RepositoryHandler.java +++ b/src/main/java/org/olat/repository/handlers/RepositoryHandler.java @@ -199,7 +199,7 @@ public interface RepositoryHandler { /** * Called if the repository entry referencing the given Resourceable will be deleted * from the repository. Do any necessary cleanup work specific to this handler's type. - * The handler is responsible for deleting the resourceable aswell. + * The handler is responsible for deleting the resourceable as well. * @param res * @param ureq * @param wControl @@ -209,7 +209,7 @@ public interface RepositoryHandler { /** * Called if the repository entry referencing the given Resourceable will be deleted - * from the repository. Return status wether to proceed with the delete action. If + * from the repository. Return status whether to proceed with the delete action. If * this method returns false, the entry will not be deleted. * @param res * @param identity @@ -242,4 +242,12 @@ public interface RepositoryHandler { */ public boolean isLocked(OLATResourceable ores); + /** + * Called when the repository entry of that Resourceable changed. + * @param entry + */ + default public void onDescriptionChanged(RepositoryEntry entry) { + // nothing to do + } + } diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryAuthorQueries.java b/src/main/java/org/olat/repository/manager/RepositoryEntryAuthorQueries.java index 4e5acd1b6f4ef3a24a4a81b19abb0cff86e1657e..2edefad11175b7c9dbef9f6a984c1f369a9a984c 100644 --- a/src/main/java/org/olat/repository/manager/RepositoryEntryAuthorQueries.java +++ b/src/main/java/org/olat/repository/manager/RepositoryEntryAuthorQueries.java @@ -41,6 +41,7 @@ import org.olat.repository.RepositoryEntryAuthorView; import org.olat.repository.model.RepositoryEntryAuthorImpl; import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams; import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams.OrderBy; +import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams.ResourceUsage; import org.olat.user.UserImpl; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; @@ -97,6 +98,9 @@ public class RepositoryEntryAuthorQueries { Number numOffers = (Number)object[2]; long offers = numOffers == null ? 0l : numOffers.longValue(); + Number numOfReferences = (Number)object[3]; + int references = numOfReferences == null ? 0 : numOfReferences.intValue(); + String deletedByName = null; if(params.isDeleted()) { Identity deletedBy = re.getDeletedBy(); @@ -105,7 +109,7 @@ public class RepositoryEntryAuthorQueries { } } - views.add(new RepositoryEntryAuthorImpl(re, hasMarks, offers, deletedByName)); + views.add(new RepositoryEntryAuthorImpl(re, hasMarks, offers, references, deletedByName)); } return views; } @@ -138,8 +142,11 @@ public class RepositoryEntryAuthorQueries { needIdentity = true; } sb.append(" (select count(offer.key) from acoffer as offer ") - .append(" where offer.resource=res and offer.valid=true") - .append(" ) as offers") + .append(" where offer.resource.key=res.key and offer.valid=true") + .append(" ) as offers,") + .append(" (select count(ref.key) from references as ref ") + .append(" where ref.target.key=res.key") + .append(" ) as references") .append(" from repositoryentry as v") .append(" inner join ").append(oracle ? "" : "fetch").append(" v.olatResource as res") .append(" inner join fetch v.statistics as stats") @@ -179,6 +186,14 @@ public class RepositoryEntryAuthorQueries { .append(" ))"); } + if(params.getResourceUsage() != null && params.getResourceUsage() != ResourceUsage.all) { + sb.append(" and res.resName!='CourseModule' and"); + if(params.getResourceUsage() == ResourceUsage.notUsed) { + sb.append(" not"); + } + sb.append(" exists (select ref.key from references as ref where ref.target.key=res.key)"); + } + if(params.getRepoEntryKeys() != null && params.getRepoEntryKeys().size() > 0) { sb.append(" and v.key in (:repoEntryKeys)"); } @@ -369,6 +384,14 @@ public class RepositoryEntryAuthorQueries { sb.append(" order by offers desc, lower(v.displayname) desc"); } break; + case references: { + if(asc) { + sb.append(" order by references asc, lower(v.displayname) asc"); + } else { + sb.append(" order by references desc, lower(v.displayname) desc"); + } + break; + } case creationDate: sb.append(" order by v.creationDate "); appendAsc(sb, asc).append(", lower(v.displayname) asc"); diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryDAO.java b/src/main/java/org/olat/repository/manager/RepositoryEntryDAO.java index cac0c3838c000aa90a12f3709db0c5eac81a7228..bc6eae1dd5486cecd3e1d3b05c8818f690531980 100644 --- a/src/main/java/org/olat/repository/manager/RepositoryEntryDAO.java +++ b/src/main/java/org/olat/repository/manager/RepositoryEntryDAO.java @@ -37,17 +37,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** - * + * * Initial date: 26.02.2014<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ @Service public class RepositoryEntryDAO { - + @Autowired private DB dbInstance; - + public RepositoryEntry loadByKey(Long key) { List<RepositoryEntry> entries = dbInstance.getCurrentEntityManager() .createNamedQuery("loadRepositoryEntryByKey", RepositoryEntry.class) @@ -57,9 +57,9 @@ public class RepositoryEntryDAO { return null; } return entries.get(0); - + } - + public RepositoryEntry loadForUpdate(RepositoryEntry re) { //first remove it from caches dbInstance.getCurrentEntityManager().detach(re); @@ -74,7 +74,7 @@ public class RepositoryEntryDAO { .getResultList(); return entries == null || entries.isEmpty() ? null : entries.get(0); } - + public RepositoryEntry loadByResourceKey(Long resourceKey) { List<RepositoryEntry> entries = dbInstance.getCurrentEntityManager() .createNamedQuery("loadRepositoryEntryByResourceKey", RepositoryEntry.class) @@ -85,7 +85,7 @@ public class RepositoryEntryDAO { } return entries.get(0); } - + public List<RepositoryEntry> loadByResourceKeys(Collection<Long> resourceKeys) { if(resourceKeys == null || resourceKeys.isEmpty()) return Collections.emptyList(); @@ -95,12 +95,48 @@ public class RepositoryEntryDAO { .append(" inner join fetch v.statistics as statistics") .append(" left join fetch v.lifecycle as lifecycle") .append(" where ores.key in (:resourceKeys)"); - + return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("resourceKeys", resourceKeys) .getResultList(); } + + public List<RepositoryEntry> loadRepositoryEntriesByExternalId(String externalId) { + if (externalId == null) return Collections.emptyList(); + String query = "select v from repositoryentry as v where v.externalId=:externalId"; + + List<RepositoryEntry> entries = dbInstance.getCurrentEntityManager() + .createQuery(query, RepositoryEntry.class) + .setParameter("externalId", externalId) + .setHint("org.hibernate.cacheable", Boolean.TRUE) + .getResultList(); + return entries; + } + + public List<RepositoryEntry> loadRepositoryEntriesByExternalRef(String externalRef) { + if (externalRef == null) return Collections.emptyList(); + String query = "select v from repositoryentry as v where v.externalRef=:externalRef"; + + List<RepositoryEntry> entries = dbInstance.getCurrentEntityManager() + .createQuery(query, RepositoryEntry.class) + .setParameter("externalRef", externalRef) + .setHint("org.hibernate.cacheable", Boolean.TRUE) + .getResultList(); + return entries; + } + + public RepositoryEntry loadByResourceId(String resourceName, Long resourceId) { + List<RepositoryEntry> entries = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadRepositoryEntryByResourceId", RepositoryEntry.class) + .setParameter("resId", resourceId) + .setParameter("resName", resourceName) + .getResultList(); + if(entries.isEmpty()) { + return null; + } + return entries.get(0); + } public List<RepositoryEntry> searchByIdAndRefs(String idAndRefs) { StringBuilder sb = new StringBuilder(); @@ -108,7 +144,7 @@ public class RepositoryEntryDAO { .append(" inner join fetch v.olatResource as res") .append(" inner join fetch v.statistics as statistics") .append(" left join fetch v.lifecycle as lifecycle"); - + Long id = null; if(StringHelper.isLong(idAndRefs)) { try { @@ -120,7 +156,7 @@ public class RepositoryEntryDAO { sb.append(" where v.externalId=:ref or v.externalRef=:ref or v.softkey=:ref"); if(id != null) { sb.append(" or v.key=:vKey or res.resId=:vKey"); - } + } TypedQuery<RepositoryEntry> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("ref", idAndRefs); @@ -129,25 +165,25 @@ public class RepositoryEntryDAO { } return query.getResultList(); } - + public List<RepositoryEntry> getAllRepositoryEntries(int firstResult, int maxResults) { StringBuilder sb = new StringBuilder(); sb.append("select v from ").append(RepositoryEntry.class.getName()).append(" as v ") .append(" inner join fetch v.olatResource as ores") .append(" inner join fetch v.statistics as statistics") .append(" left join fetch v.lifecycle as lifecycle"); - + return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setFirstResult(firstResult) .setMaxResults(maxResults) .getResultList(); } - + public OLATResource loadRepositoryEntryResource(Long key) { if (key == null) return null; String query = "select v.olatResource from repositoryentry as v where v.key=:repoKey"; - + List<OLATResource> entries = dbInstance.getCurrentEntityManager() .createQuery(query, OLATResource.class) .setParameter("repoKey", key) @@ -158,7 +194,7 @@ public class RepositoryEntryDAO { } return entries.get(0); } - + public OLATResource loadRepositoryEntryResourceBySoftKey(String softkey) { if(softkey == null || "sf.notconfigured".equals(softkey)) { return null; @@ -174,7 +210,7 @@ public class RepositoryEntryDAO { } return entries.get(0); } - + public List<RepositoryEntry> getLastUsedRepositoryEntries(String resourceTypeName, int firstResult, int maxResults) { StringBuilder sb = new StringBuilder(); sb.append("select v from ").append(RepositoryEntry.class.getName()).append(" as v ") @@ -183,7 +219,7 @@ public class RepositoryEntryDAO { .append(" left join fetch v.lifecycle as lifecycle") .append(" where ores.resName=:resourceTypeName") .append(" order by statistics.lastUsage desc"); - + return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setFirstResult(firstResult) @@ -191,7 +227,7 @@ public class RepositoryEntryDAO { .setParameter("resourceTypeName", resourceTypeName) .getResultList(); } - + public List<RepositoryEntry> getRepositoryEntriesAfterTheEnd(Date date) { StringBuilder sb = new StringBuilder(); sb.append("select v from ").append(RepositoryEntry.class.getName()).append(" as v ") @@ -199,12 +235,12 @@ public class RepositoryEntryDAO { .append(" inner join fetch v.statistics as statistics") .append(" inner join fetch v.lifecycle as lifecycle") .append(" where lifecycle.validTo<:now"); - + Calendar cal = Calendar.getInstance(); cal.setTime(date); CalendarUtils.getEndOfDay(cal); Date endOfDay = cal.getTime(); - + return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("now", endOfDay) diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryMyCourseQueries.java b/src/main/java/org/olat/repository/manager/RepositoryEntryMyCourseQueries.java index a564e60b6c02340e8d3e84b8ffe89d7942ce1966..aed4c2154710057af1a4cbcfc25abefddcfed6c5 100644 --- a/src/main/java/org/olat/repository/manager/RepositoryEntryMyCourseQueries.java +++ b/src/main/java/org/olat/repository/manager/RepositoryEntryMyCourseQueries.java @@ -200,6 +200,11 @@ public class RepositoryEntryMyCourseQueries { } //user course informations //efficiency statements + + // join seems to be quicker + if(params.getMarked() != null && params.getMarked().booleanValue()) { + sb.append(" inner join ").append(MarkImpl.class.getName()).append(" as mark2 on (mark2.creator.key=:identityKey and mark2.resId=v.key and mark2.resName='RepositoryEntry')"); + } sb.append(" where "); needIdentityKey |= appendMyViewAccessSubSelect(sb, roles, params.getFilters(), params.isMembershipMandatory()); @@ -229,11 +234,6 @@ public class RepositoryEntryMyCourseQueries { if (params.isResourceTypesDefined()) { sb.append(" and res.resName in (:resourcetypes)"); } - if(params.getMarked() != null && params.getMarked().booleanValue()) { - sb.append(" and exists (select mark2.key from ").append(MarkImpl.class.getName()).append(" as mark2 ") - .append(" where mark2.creator.key=:identityKey and mark2.resId=v.key and mark2.resName='RepositoryEntry'") - .append(" )"); - } String author = params.getAuthor(); if (StringHelper.containsNonWhitespace(author)) { // fuzzy author search @@ -291,8 +291,9 @@ public class RepositoryEntryMyCourseQueries { if(StringHelper.containsNonWhitespace(params.getIdRefsAndTitle())) { quickRefs = params.getIdRefsAndTitle(); quickText = PersistenceHelper.makeFuzzyQueryString(quickRefs); - - sb.append(" and (v.externalId=:quickRef or v.externalRef=:quickRef or v.softkey=:quickRef or "); + sb.append(" and (v.externalId=:quickRef or "); + PersistenceHelper.appendFuzzyLike(sb, "v.externalRef", "quickText", dbInstance.getDbVendor()); + sb.append(" or v.softkey=:quickRef or "); PersistenceHelper.appendFuzzyLike(sb, "v.displayname", "quickText", dbInstance.getDbVendor()); if(StringHelper.isLong(quickRefs)) { try { diff --git a/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java b/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java index c5a3f7cb568c110ee0288fee1579d18441286f48..ba957b60fcec5814a3b699d6e76f30a1c0587298 100644 --- a/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java +++ b/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java @@ -85,6 +85,7 @@ import org.olat.repository.model.SearchMyRepositoryEntryViewParams; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.olat.resource.accesscontrol.manager.ACReservationDAO; +import org.olat.resource.accesscontrol.provider.auto.AutoAccessManager; import org.olat.resource.references.ReferenceManager; import org.olat.search.service.document.RepositoryEntryDocument; import org.olat.search.service.indexer.LifeFullIndexer; @@ -93,14 +94,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** - * + * * Initial date: 20.02.2014<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ @Service("repositoryService") public class RepositoryServiceImpl implements RepositoryService { - + private static final OLog log = Tracing.createLoggerFor(RepositoryServiceImpl.class); @Autowired @@ -114,6 +115,8 @@ public class RepositoryServiceImpl implements RepositoryService { @Autowired private ACReservationDAO reservationDao; @Autowired + private AutoAccessManager autoAccessManager; + @Autowired private ReferenceManager referenceManager; @Autowired private RepositoryEntryDAO repositoryEntryDAO; @@ -148,7 +151,7 @@ public class RepositoryServiceImpl implements RepositoryService { @Autowired private LifeFullIndexer lifeIndexer; - + @Override public RepositoryEntry create(String initialAuthor, String resourceName, String displayname, String description, OLATResource resource) { @@ -160,11 +163,11 @@ public class RepositoryServiceImpl implements RepositoryService { String resourceName, String displayname, String description, OLATResource resource, int access) { return create(initialAuthorAlt, initialAuthor, resourceName, displayname, description, resource, access); } - + private RepositoryEntry create(String initialAuthorName, Identity initialAuthor, String resourceName, - String displayname, String description, OLATResource resource, int access) { + String displayname, String description, OLATResource resource, int access) { Date now = new Date(); - + RepositoryEntry re = new RepositoryEntry(); if(StringHelper.containsNonWhitespace(initialAuthorName)) { re.setInitialAuthor(initialAuthorName); @@ -191,7 +194,7 @@ public class RepositoryServiceImpl implements RepositoryService { dbInstance.getCurrentEntityManager().persist(resource); } re.setOlatResource(resource); - + RepositoryEntryStatistics statistics = new RepositoryEntryStatistics(); statistics.setLastUsage(now); statistics.setCreationDate(now); @@ -201,9 +204,9 @@ public class RepositoryServiceImpl implements RepositoryService { statistics.setNumOfRatings(0l); statistics.setNumOfComments(0l); dbInstance.getCurrentEntityManager().persist(statistics); - + re.setStatistics(statistics); - + Group group = groupDao.createGroup(); RepositoryEntryToGroupRelation rel = new RepositoryEntryToGroupRelation(); rel.setCreationDate(new Date()); @@ -214,13 +217,15 @@ public class RepositoryServiceImpl implements RepositoryService { Set<RepositoryEntryToGroupRelation> rels = new HashSet<>(2); rels.add(rel); re.setGroups(rels); - + if(initialAuthor != null) { groupDao.addMembershipTwoWay(group, initialAuthor, GroupRoles.owner.name()); } - + dbInstance.getCurrentEntityManager().persist(re); - return re; + + autoAccessManager.grantAccess(re); + return re; } @Override @@ -229,7 +234,7 @@ public class RepositoryServiceImpl implements RepositoryService { OLATResource copyResource = resourceManager.createOLATResourceInstance(sourceResource.getResourceableTypeName()); RepositoryEntry copyEntry = create(author, null, sourceEntry.getResourcename(), displayname, sourceEntry.getDescription(), copyResource, RepositoryEntry.ACC_OWNERS); - + //copy all fields copyEntry.setAuthors(sourceEntry.getAuthors()); copyEntry.setCredits(sourceEntry.getCredits()); @@ -238,13 +243,13 @@ public class RepositoryServiceImpl implements RepositoryService { copyEntry.setObjectives(sourceEntry.getObjectives()); copyEntry.setRequirements(sourceEntry.getRequirements()); copyEntry = dbInstance.getCurrentEntityManager().merge(copyEntry); - + RepositoryHandler handler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(sourceEntry); copyEntry = handler.copy(author, sourceEntry, copyEntry); //copy the image RepositoryManager.getInstance().copyImage(sourceEntry, copyEntry); - + //copy media container VFSContainer sourceMediaContainer = handler.getMediaContainer(sourceEntry); if(sourceMediaContainer != null) { @@ -254,8 +259,8 @@ public class RepositoryServiceImpl implements RepositoryService { ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_CREATE, getClass(), LoggingResourceable.wrap(copyEntry, OlatResourceableType.genRepoEntry)); - - + + lifeIndexer.indexDocument(RepositoryEntryDocument.TYPE, copyEntry.getKey()); return copyEntry; } @@ -266,9 +271,10 @@ public class RepositoryServiceImpl implements RepositoryService { RepositoryEntry mergedRe = dbInstance.getCurrentEntityManager().merge(re); dbInstance.commit(); lifeIndexer.indexDocument(RepositoryEntryDocument.TYPE, mergedRe.getKey()); + autoAccessManager.grantAccess(re); return mergedRe; } - + @Override public RepositoryEntry loadByKey(Long key) { return repositoryEntryDAO.loadByKey(key); @@ -278,7 +284,7 @@ public class RepositoryServiceImpl implements RepositoryService { public RepositoryEntry loadByResourceKey(Long resourceKey) { return repositoryEntryDAO.loadByResourceKey(resourceKey); } - + @Override public List<RepositoryEntry> loadByResourceKeys(Collection<Long> resourceKeys) { return repositoryEntryDAO.loadByResourceKeys(resourceKeys); @@ -294,6 +300,16 @@ public class RepositoryServiceImpl implements RepositoryService { return repositoryEntryDAO.loadRepositoryEntryResourceBySoftKey(softkey); } + @Override + public List<RepositoryEntry> loadRepositoryEntriesByExternalId(String externalId) { + return repositoryEntryDAO.loadRepositoryEntriesByExternalId(externalId); + } + + @Override + public List<RepositoryEntry> loadRepositoryEntriesByExternalRef(String externalRef) { + return repositoryEntryDAO.loadRepositoryEntriesByExternalRef(externalRef); + } + @Override public VFSLeaf getIntroductionImage(RepositoryEntry re) { VFSContainer repositoryHome = new LocalFolderImpl(new File(FolderConfig.getCanonicalRepositoryHome())); @@ -320,13 +336,13 @@ public class RepositoryServiceImpl implements RepositoryService { if(item instanceof VFSLeaf && item.getName().startsWith(re.getKey().toString()) && (item.getName().endsWith(".mp4") || item.getName().endsWith(".m4v") || item.getName().endsWith(".flv")) ) { - return (VFSLeaf)item; - } + return (VFSLeaf)item; + } } } return null; } - + @Override public RepositoryEntry deleteSoftly(RepositoryEntry re, Identity deletedBy, boolean owners) { RepositoryEntry reloadedRe = repositoryEntryDAO.loadForUpdate(re); @@ -370,7 +386,7 @@ public class RepositoryServiceImpl implements RepositoryService { @Override public ErrorList deletePermanently(RepositoryEntry entry, Identity identity, Roles roles, Locale locale) { ErrorList errors = new ErrorList(); - + boolean debug = log.isDebug(); // invoke handler delete callback @@ -386,7 +402,7 @@ public class RepositoryServiceImpl implements RepositoryService { userCourseInformationsManager.deleteUserCourseInformations(entry); certificatesManager.deleteRepositoryEntry(entry); - + // delete all bookmarks referencing deleted entry CoreSpringFactory.getImpl(MarkManager.class).deleteMarks(entry); // delete all catalog entries referencing deleted entry @@ -407,7 +423,7 @@ public class RepositoryServiceImpl implements RepositoryService { //delete lectures CoreSpringFactory.getImpl(LectureService.class).delete(entry); dbInstance.commit(); - + // inform handler to do any cleanup work... handler must delete the // referenced resourceable a swell. handler.cleanupOnDelete(entry, resource); @@ -426,9 +442,9 @@ public class RepositoryServiceImpl implements RepositoryService { if(debug) log.debug("deleteRepositoryEntry Done"); return errors; } - + /** - * + * * @param entry */ @Override @@ -451,12 +467,12 @@ public class RepositoryServiceImpl implements RepositoryService { groupDao.removeGroup(defaultGroup); } dbInstance.commit(); - + OLATResource reloadedResource = resourceManager.findResourceById(resourceKey); if(reloadedResource != null) { dbInstance.getCurrentEntityManager().remove(reloadedResource); } - + dbInstance.commit(); } @@ -522,7 +538,7 @@ public class RepositoryServiceImpl implements RepositoryService { /** * Get the role in the specified resource, business group are included in * the query. - * + * */ @Override public List<String> getRoles(Identity identity, RepositoryEntryRef re) { @@ -587,12 +603,12 @@ public class RepositoryServiceImpl implements RepositoryService { return reToGroupDao.countMembers(re, roles); } - + @Override public int countMembers(List<? extends RepositoryEntryRef> res, Identity excludeMe) { return reToGroupDao.countMembers(res, excludeMe); } - + @Override public Date getEnrollmentDate(RepositoryEntryRef re, IdentityRef identity, String... roles) { return reToGroupDao.getEnrollmentDate(re, identity, roles); diff --git a/src/main/java/org/olat/repository/model/RepositoryEntryAuthorImpl.java b/src/main/java/org/olat/repository/model/RepositoryEntryAuthorImpl.java index 221d37cbc027a9f07287aa097782f6d212a1cad7..147dbcf98814d3dbedbe93ffaa4c03e580faa94f 100644 --- a/src/main/java/org/olat/repository/model/RepositoryEntryAuthorImpl.java +++ b/src/main/java/org/olat/repository/model/RepositoryEntryAuthorImpl.java @@ -56,6 +56,8 @@ public class RepositoryEntryAuthorImpl implements RepositoryEntryAuthorView { private final Date lastUsage; + public int numOfReferences; + private final Date deletionDate; private final String deletedByFullName; @@ -66,7 +68,7 @@ public class RepositoryEntryAuthorImpl implements RepositoryEntryAuthorView { private final long offers; - public RepositoryEntryAuthorImpl(RepositoryEntry re, boolean marked, long offers, String deletedByFullName) { + public RepositoryEntryAuthorImpl(RepositoryEntry re, boolean marked, long offers, int numOfReferences, String deletedByFullName) { key = re.getKey(); creationDate = re.getCreationDate(); @@ -87,6 +89,8 @@ public class RepositoryEntryAuthorImpl implements RepositoryEntryAuthorView { lastUsage = re.getStatistics().getLastUsage(); + this.numOfReferences = numOfReferences; + deletionDate = re.getDeletionDate(); this.deletedByFullName = deletedByFullName; @@ -190,6 +194,11 @@ public class RepositoryEntryAuthorImpl implements RepositoryEntryAuthorView { return lifecycle; } + @Override + public int getNumOfReferences() { + return numOfReferences; + } + @Override public boolean isMarked() { return marked; diff --git a/src/main/java/org/olat/repository/model/SearchAuthorRepositoryEntryViewParams.java b/src/main/java/org/olat/repository/model/SearchAuthorRepositoryEntryViewParams.java index 75688f7470cf7a2d84a140a14276a0349ad28180..3549ae151b64a7aff3cc0b56217cd47e9c1ea394 100644 --- a/src/main/java/org/olat/repository/model/SearchAuthorRepositoryEntryViewParams.java +++ b/src/main/java/org/olat/repository/model/SearchAuthorRepositoryEntryViewParams.java @@ -38,6 +38,7 @@ public class SearchAuthorRepositoryEntryViewParams { private Boolean marked; private boolean deleted = false; private boolean ownedResourcesOnly; + private ResourceUsage resourceUsage = ResourceUsage.all; private String idAndRefs; private String idRefsAndTitle; @@ -174,6 +175,14 @@ public class SearchAuthorRepositoryEntryViewParams { this.marked = marked; } + public ResourceUsage getResourceUsage() { + return resourceUsage; + } + + public void setResourceUsage(ResourceUsage resourceUsage) { + this.resourceUsage = resourceUsage; + } + public enum OrderBy { key, favorit, @@ -192,7 +201,14 @@ public class SearchAuthorRepositoryEntryViewParams { lifecycleSoftkey, lifecycleStart, lifecycleEnd, + references, deletionDate, deletedBy } + + public enum ResourceUsage { + all, + used, + notUsed + } } diff --git a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java index 446c40520f04b28118b6ed33b8b2a26ec198f8d9..6f0095e68a4c4d5876b55f681eefd55abc59842c 100644 --- a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java +++ b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java @@ -500,10 +500,12 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController protected void processEntryChangedEvent(EntryChangedEvent repoEvent) { if(repoEvent.isMe(getIdentity()) && (repoEvent.getChange() == Change.addBookmark || repoEvent.getChange() == Change.removeBookmark)) { - boolean marked = markManager.isMarked(OresHelper.clone(re), getIdentity(), null); - String css = "o_icon " + (marked ? Mark.MARK_CSS_ICON : Mark.MARK_ADD_CSS_ICON); - bookmarkLink.setIconLeftCSS(css); - bookmarkLink.setTitle( translate(marked ? "details.bookmark.remove" : "details.bookmark")); + if(bookmarkLink != null) { + boolean marked = markManager.isMarked(OresHelper.clone(re), getIdentity(), null); + String css = "o_icon " + (marked ? Mark.MARK_CSS_ICON : Mark.MARK_ADD_CSS_ICON); + bookmarkLink.setIconLeftCSS(css); + bookmarkLink.setTitle( translate(marked ? "details.bookmark.remove" : "details.bookmark")); + } } } @@ -572,7 +574,21 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController } } else if(descriptionCtrl == source) { if(event == Event.CHANGED_EVENT) { - refreshRepositoryEntry(descriptionCtrl.getEntry()); + RepositoryEntry entry = descriptionCtrl.getEntry(); + refreshRepositoryEntry(entry); + handler.onDescriptionChanged(entry); + // update name of root bread crumb and opened tabs in top nav in case the title has been modified + if (toolbarPanel.getBreadCrumbs().size() > 0) { + String newTitle = entry.getDisplayname(); + String oldTitle = toolbarPanel.getBreadCrumbs().get(0).getCustomDisplayText(); + if (!newTitle.equals(oldTitle)) { + // 1: update breadcrumb in toolbar + toolbarPanel.getBreadCrumbs().get(0).setCustomDisplayText(newTitle); + // 2: update dynamic tab in topnav + OLATResourceable reOres = OresHelper.clone(entry); + getWindowControl().getWindowBackOffice().getWindow().getDTabs().updateDTabTitle(reOres, newTitle); + } + } } else if(event == Event.CLOSE_EVENT) { doClose(ureq); } diff --git a/src/main/java/org/olat/repository/ui/author/AuthorListController.java b/src/main/java/org/olat/repository/ui/author/AuthorListController.java index 7103a5b0c9ec0d80f088a964314be73899bea9e1..433f3792aa7577d93d766e4ec92f3f109b84dc9c 100644 --- a/src/main/java/org/olat/repository/ui/author/AuthorListController.java +++ b/src/main/java/org/olat/repository/ui/author/AuthorListController.java @@ -101,8 +101,10 @@ import org.olat.repository.handlers.RepositoryHandlerFactory; import org.olat.repository.handlers.RepositoryHandlerFactory.OrderedRepositoryHandler; import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams; import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams.OrderBy; +import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams.ResourceUsage; import org.olat.repository.ui.RepositoyUIFactory; import org.olat.repository.ui.author.AuthoringEntryDataModel.Cols; +import org.olat.resource.references.ReferenceManager; import org.olat.user.UserManager; import org.olat.util.logging.activity.LoggingResourceable; import org.springframework.beans.factory.annotation.Autowired; @@ -132,6 +134,7 @@ public class AuthorListController extends FormBasicController implements Activat private AuthorSearchController searchCtrl; private UserSearchController userSearchCtr; private DialogBoxController copyDialogCtrl; + private ReferencesController referencesCtrl; private CopyRepositoryEntryController copyCtrl; private ConfirmCloseController closeCtrl; private ConfirmDeleteSoftlyController confirmDeleteCtrl; @@ -290,6 +293,9 @@ public class AuthorListController extends FormBasicController implements Activat true, OrderBy.creationDate.name())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.lastUsage.i18nKey(), Cols.lastUsage.ordinal(), true, OrderBy.lastUsage.name())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.references.i18nKey(), Cols.references.ordinal(), + true, OrderBy.references.name())); + initActionsColumns(columnsModel); model = new AuthoringEntryDataModel(dataSource, columnsModel); @@ -466,6 +472,7 @@ public class AuthorListController extends FormBasicController implements Activat searchParams.setDisplayname(null); searchParams.setDescription(null); searchParams.setOwnedResourcesOnly(false); + searchParams.setResourceUsage(ResourceUsage.all); } } else if(userSearchCtr == source) { @SuppressWarnings("unchecked") @@ -488,6 +495,11 @@ public class AuthorListController extends FormBasicController implements Activat toolsCalloutCtrl.deactivate(); cleanUp(); } + } else if(referencesCtrl == source) { + if(event == Event.DONE_EVENT) { + toolsCalloutCtrl.deactivate(); + cleanUp(); + } } else if(closeCtrl == source) { if(event == Event.CANCELLED_EVENT) { cmc.deactivate(); @@ -588,6 +600,9 @@ public class AuthorListController extends FormBasicController implements Activat } else if("tools".equals(cmd)) { AuthoringEntryRow row = (AuthoringEntryRow)link.getUserObject(); doOpenTools(ureq, row, link); + } else if("references".equals(cmd)) { + AuthoringEntryRow row = (AuthoringEntryRow)link.getUserObject(); + doOpenReferences(ureq, row, link); } } else if(source == tableEl) { if(event instanceof SelectionEvent) { @@ -649,6 +664,25 @@ public class AuthorListController extends FormBasicController implements Activat } } + private void doOpenReferences(UserRequest ureq, AuthoringEntryRow row, FormLink link) { + removeAsListenerAndDispose(toolsCtrl); + removeAsListenerAndDispose(toolsCalloutCtrl); + + RepositoryEntry entry = repositoryService.loadByKey(row.getKey()); + if(entry == null) { + tableEl.reloadData(); + showWarning("repositoryentry.not.existing"); + } else { + referencesCtrl = new ReferencesController(ureq, getWindowControl(), entry); + listenTo(referencesCtrl); + + toolsCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(), + referencesCtrl.getInitialComponent(), link.getFormDispatchId(), "", true, ""); + listenTo(toolsCalloutCtrl); + toolsCalloutCtrl.activate(); + } + } + private void doImport(UserRequest ureq) { if(importCtrl != null) return; @@ -720,6 +754,7 @@ public class AuthorListController extends FormBasicController implements Activat searchParams.setIdAndRefs(se.getId()); searchParams.setAuthor(se.getAuthor()); searchParams.setOwnedResourcesOnly(se.isOwnedResourcesOnly()); + searchParams.setResourceUsage(se.getResourceUsage()); searchParams.setDisplayname(se.getDisplayname()); searchParams.setDescription(se.getDescription()); tableEl.reset(true, true, true); @@ -989,6 +1024,13 @@ public class AuthorListController extends FormBasicController implements Activat } } + private void launch(UserRequest ureq, RepositoryEntryRef ref) { + String businessPath = "[RepositoryEntry:" + ref.getKey() + "]"; + if(!NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl())) { + tableEl.reloadData(); + } + } + private void launchCatalog(UserRequest ureq, RepositoryEntryRef ref) { String businessPath = "[RepositoryEntry:" + ref.getKey() + "][Catalog:0]"; NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); @@ -1055,6 +1097,57 @@ public class AuthorListController extends FormBasicController implements Activat toolsLink.setIconLeftCSS("o_icon o_icon_actions o_icon-lg"); toolsLink.setUserObject(row); row.setToolsLink(toolsLink); + //references + if(row.getNumOfReferences() > 0) { + String numOfReferences = Integer.toString(row.getNumOfReferences()); + FormLink referencesLink = uifactory.addFormLink("tools_" + counter.incrementAndGet(), "references", numOfReferences, null, null, Link.NONTRANSLATED); + referencesLink.setUserObject(row); + row.setReferencesLink(referencesLink); + } + } + + private class ReferencesController extends BasicController { + + @Autowired + private ReferenceManager referenceManager; + + public ReferencesController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) { + super(ureq, wControl); + setTranslator(AuthorListController.this.getTranslator()); + VelocityContainer mainVC = createVelocityContainer("references"); + + List<RepositoryEntry> refs = referenceManager.getRepositoryReferencesTo(entry.getOlatResource()); + + List<String> refLinks = new ArrayList<>(refs.size()); + for(RepositoryEntry ref:refs) { + String name = "ref-" + counter.incrementAndGet(); + Link refLink = LinkFactory.createLink(name, "reference", getTranslator(), mainVC, this, Link.NONTRANSLATED); + refLink.setCustomDisplayText(StringHelper.escapeHtml(ref.getDisplayname())); + refLink.setUserObject(ref); + refLink.setIconLeftCSS("o_icon o_icon-fw " + RepositoyUIFactory.getIconCssClass(ref)); + refLinks.add(name); + } + mainVC.contextPut("referenceLinks", refLinks); + + putInitialPanel(mainVC); + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if(source instanceof Link) { + fireEvent(ureq, Event.DONE_EVENT); + Link link = (Link)source; + if("reference".equals(link.getCommand())) { + RepositoryEntryRef uobject = (RepositoryEntryRef)link.getUserObject(); + launch(ureq, uobject); + } + } + } + + @Override + protected void doDispose() { + // + } } private class ToolsController extends BasicController { diff --git a/src/main/java/org/olat/repository/ui/author/AuthorSearchController.java b/src/main/java/org/olat/repository/ui/author/AuthorSearchController.java index 50cba0ca9236e865f26392d1fbe3f22a7c08c0ab..de67a19b2b71647ec916b42a4108d1149aa48872 100644 --- a/src/main/java/org/olat/repository/ui/author/AuthorSearchController.java +++ b/src/main/java/org/olat/repository/ui/author/AuthorSearchController.java @@ -44,6 +44,7 @@ import org.olat.core.util.Util; import org.olat.repository.RepositoryManager; import org.olat.repository.handlers.RepositoryHandlerFactory; import org.olat.repository.handlers.RepositoryHandlerFactory.OrderedRepositoryHandler; +import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams.ResourceUsage; import org.springframework.beans.factory.annotation.Autowired; /** @@ -55,12 +56,14 @@ import org.springframework.beans.factory.annotation.Autowired; public class AuthorSearchController extends FormBasicController implements ExtendedFlexiTableSearchController { private static final String[] keys = new String[]{ "my" }; + private static final String[] usageKeys = new String[]{ ResourceUsage.all.name(), ResourceUsage.used.name(), ResourceUsage.notUsed.name() }; private TextElement id; // only for admins private TextElement displayName; private TextElement author; private TextElement description; private SingleSelection types; + private SingleSelection resourceUsageEl; private MultipleSelectionElement ownedResourcesOnlyEl; private FormLink searchButton; @@ -117,6 +120,14 @@ public class AuthorSearchController extends FormBasicController implements Exten ownedResourcesOnlyEl = uifactory.addCheckboxesHorizontal("cif_my", "cif.owned.resources.only", rightContainer, keys, new String[]{ "" }); ownedResourcesOnlyEl.select(keys[0], true); + String[] usageValues = new String[] { + translate("cif.owned.resources.usage.all"), + translate("cif.owned.resources.usage.used"), + translate("cif.owned.resources.usage.notUsed") + }; + resourceUsageEl = uifactory.addRadiosHorizontal("cif_used", "cif.owned.resources.usage", rightContainer, usageKeys, usageValues); + resourceUsageEl.select(usageKeys[0], true); + FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator()); formLayout.add(buttonLayout); searchButton = uifactory.addFormLink("search", buttonLayout, Link.BUTTON); @@ -132,6 +143,9 @@ public class AuthorSearchController extends FormBasicController implements Exten author.setValue(se.getAuthor()); ownedResourcesOnlyEl.select(keys[0], se.isOwnedResourcesOnly()); description.setValue(se.getDescription()); + if(se.getResourceUsage() != null) { + resourceUsageEl.select(se.getResourceUsage().name(), true); + } String type = se.getType(); if(StringHelper.containsNonWhitespace(type)) { @@ -197,6 +211,13 @@ public class AuthorSearchController extends FormBasicController implements Exten return ownedResourcesOnlyEl.isAtLeastSelected(1); } + public ResourceUsage getResourceUsage() { + if(resourceUsageEl.isOneSelected()) { + return ResourceUsage.valueOf(resourceUsageEl.getSelectedKey()); + } + return ResourceUsage.all; + } + @Override public void setEnabled(boolean enable) { this.enabled = enable; @@ -242,6 +263,7 @@ public class AuthorSearchController extends FormBasicController implements Exten e.setDescription(getDescription()); e.setType(getRestrictedType()); e.setOwnedResourcesOnly(isOwnedResourcesOnly()); + e.setResourceUsage(getResourceUsage()); fireEvent(ureq, e); } diff --git a/src/main/java/org/olat/repository/ui/author/AuthoringEntryDataModel.java b/src/main/java/org/olat/repository/ui/author/AuthoringEntryDataModel.java index 8cb4517d62c9182853fa1c014ce5b92452cd9df0..45a4ef7abce4eac6a77ebe91be2b2cc80eac02df 100644 --- a/src/main/java/org/olat/repository/ui/author/AuthoringEntryDataModel.java +++ b/src/main/java/org/olat/repository/ui/author/AuthoringEntryDataModel.java @@ -85,6 +85,12 @@ class AuthoringEntryDataModel extends DefaultFlexiTableDataSourceModel<Authoring case deletedBy: return item.getDeletedByFullName(); case deletionDate: return item.getDeletionDate(); case mark: return item.getMarkLink(); + case references: { + if(item.getNumOfReferences() <= 0) { + return null; + } + return item.getReferencesLink(); + } case detailsSupported: { RepositoryHandler handler = handlerFactory.getRepositoryHandler(item.getResourceType()); return (handler != null) ? Boolean.TRUE : Boolean.FALSE; @@ -125,6 +131,7 @@ class AuthoringEntryDataModel extends DefaultFlexiTableDataSourceModel<Authoring access("table.header.access"), creationDate("table.header.date"), lastUsage("table.header.lastusage"), + references("table.header.references"), deletedBy("table.header.deletedby"), deletionDate("table.header.deletiondate"), mark("table.header.mark"), diff --git a/src/main/java/org/olat/repository/ui/author/AuthoringEntryRow.java b/src/main/java/org/olat/repository/ui/author/AuthoringEntryRow.java index 74ae6d439c72ad899c72ace67ea4daed19268767..1d3710f434242493e936bf9b7ba0d9b09a86d920 100644 --- a/src/main/java/org/olat/repository/ui/author/AuthoringEntryRow.java +++ b/src/main/java/org/olat/repository/ui/author/AuthoringEntryRow.java @@ -68,6 +68,8 @@ public class AuthoringEntryRow implements RepositoryEntryRef, RepositoryEntryLig private Date lifecycleStart; private Date lifecycleEnd; + private int numOfReferences; + private final String deletedByFullName; private final Date deletionDate; @@ -77,6 +79,7 @@ public class AuthoringEntryRow implements RepositoryEntryRef, RepositoryEntryLig private FormLink markLink; private FormLink toolsLink; + private FormLink referencesLink; public AuthoringEntryRow(RepositoryEntryAuthorView view, String fullnameAuthor) { key = view.getKey(); @@ -119,6 +122,8 @@ public class AuthoringEntryRow implements RepositoryEntryRef, RepositoryEntryLig } } + numOfReferences = view.getNumOfReferences(); + deletedByFullName = view.getDeletedByFullName(); deletionDate = view.getDeletionDate(); } @@ -204,6 +209,10 @@ public class AuthoringEntryRow implements RepositoryEntryRef, RepositoryEntryLig public Date getLifecycleEnd() { return lifecycleEnd; } + + public int getNumOfReferences() { + return numOfReferences; + } public String getDeletedByFullName() { return deletedByFullName; @@ -282,6 +291,14 @@ public class AuthoringEntryRow implements RepositoryEntryRef, RepositoryEntryLig this.toolsLink = toolsLink; } + public FormLink getReferencesLink() { + return referencesLink; + } + + public void setReferencesLink(FormLink referencesLink) { + this.referencesLink = referencesLink; + } + @Override public int hashCode() { return key == null ? -79224867 : key.hashCode(); diff --git a/src/main/java/org/olat/repository/ui/author/ConfirmDeleteSoftlyController.java b/src/main/java/org/olat/repository/ui/author/ConfirmDeleteSoftlyController.java index 8b685ada8189cc9091759c941470e0bc611120ef..5a521134753374c681f3f062075fbf04100cadd2 100644 --- a/src/main/java/org/olat/repository/ui/author/ConfirmDeleteSoftlyController.java +++ b/src/main/java/org/olat/repository/ui/author/ConfirmDeleteSoftlyController.java @@ -104,7 +104,7 @@ public class ConfirmDeleteSoftlyController extends FormBasicController { } uifactory.addStaticTextElement("rows", "details.delete.entries", message.toString(), layoutCont); - String[] acknowledge = new String[] { translate("details.delete.acknowledge.msg") }; + String[] acknowledge = new String[] { translate("details.delete.soft.acknowledge.msg") }; acknowledgeEl = uifactory.addCheckboxesHorizontal("confirm", "details.delete.acknowledge", layoutCont, new String[]{ "" }, acknowledge); FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); diff --git a/src/main/java/org/olat/repository/ui/author/SearchEvent.java b/src/main/java/org/olat/repository/ui/author/SearchEvent.java index 9c025694c74aaf5ed620c189f5a9d0617c60d086..2a280d9dee150b037596e4c414b0c42bc0903199 100644 --- a/src/main/java/org/olat/repository/ui/author/SearchEvent.java +++ b/src/main/java/org/olat/repository/ui/author/SearchEvent.java @@ -21,6 +21,7 @@ package org.olat.repository.ui.author; import org.olat.core.gui.control.Event; import org.olat.core.id.context.StateEntry; +import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams.ResourceUsage; /** * @@ -38,6 +39,7 @@ public class SearchEvent extends Event implements StateEntry { private String description; private String type; private boolean ownedResourcesOnly; + private ResourceUsage resourceUsage; public SearchEvent() { super("re-search"); @@ -92,6 +94,14 @@ public class SearchEvent extends Event implements StateEntry { this.ownedResourcesOnly = ownedResourcesOnly; } + public ResourceUsage getResourceUsage() { + return resourceUsage; + } + + public void setResourceUsage(ResourceUsage resourceUsage) { + this.resourceUsage = resourceUsage; + } + @Override public SearchEvent clone() { SearchEvent clone = new SearchEvent(); @@ -101,6 +111,7 @@ public class SearchEvent extends Event implements StateEntry { clone.description = description; clone.type = type; clone.ownedResourcesOnly = ownedResourcesOnly; + clone.resourceUsage = resourceUsage; return clone; } } diff --git a/src/main/java/org/olat/repository/ui/author/_content/references.html b/src/main/java/org/olat/repository/ui/author/_content/references.html new file mode 100644 index 0000000000000000000000000000000000000000..f0015f49fe164962aee30168422639b85642164f --- /dev/null +++ b/src/main/java/org/olat/repository/ui/author/_content/references.html @@ -0,0 +1,6 @@ +$r.translate("details.referenceinfo.txt") +<ul class="o_dropdown list-unstyled"> +#foreach($referenceLink in $referenceLinks) + <li>$r.render($referenceLink)</li> +#end +</ul> \ No newline at end of file diff --git a/src/main/java/org/olat/repository/ui/catalog/CatalogEntryEditController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryEditController.java index fb766096e21fa9aa64db3fe6314faf656c481ab4..6736835495f611341d4d4c14a9a20dd0a1e55ec8 100644 --- a/src/main/java/org/olat/repository/ui/catalog/CatalogEntryEditController.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryEditController.java @@ -45,6 +45,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.FileElementEvent 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.core.util.WebappHelper; import org.olat.core.util.vfs.LocalFileImpl; @@ -164,8 +165,30 @@ public class CatalogEntryEditController extends FormBasicController { public void setElementCssClass(String cssClass) { flc.setElementCssClass(cssClass); } - - + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + nameEl.clearError(); + if(StringHelper.containsNonWhitespace(nameEl.getValue())) { + if(nameEl.getValue().length() > 99) { + nameEl.setErrorKey("input.toolong", new String[]{ "100" }); + allOk &= false; + } + } else { + nameEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + styleEl.clearError(); + if(!styleEl.isOneSelected()) { + styleEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + return allOk & super.validateFormLogic(ureq); + } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { diff --git a/src/main/java/org/olat/repository/ui/catalog/CatalogManagerController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogManagerController.java index e870a22832ad406570753a1318b284be2296f914..5b5a7865508a9f487dec661f2d14e2cebfefc1d7 100644 --- a/src/main/java/org/olat/repository/ui/catalog/CatalogManagerController.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogManagerController.java @@ -85,7 +85,7 @@ public class CatalogManagerController extends BasicController implements Activat Long entryKey = entry.getOLATResourceable().getResourceableId(); if(entryKey != null && entryKey.longValue() > 0) { List<ContextEntry> parentLine = new ArrayList<>(); - for(CatalogEntry node = catalogManager.getCatalogEntryByKey(entryKey); node.getParent() != null; node=node.getParent()) { + for(CatalogEntry node = catalogManager.getCatalogEntryByKey(entryKey); node != null && node.getParent() != null; node=node.getParent()) { OLATResourceable nodeRes = OresHelper.createOLATResourceableInstance("Node", node.getKey()); ContextEntry ctxEntry = BusinessControlFactory.getInstance().createContextEntry(nodeRes); ctxEntry.setTransientState(new CatalogStateEntry(node)); diff --git a/src/main/java/org/olat/repository/ui/catalog/_content/node.html b/src/main/java/org/olat/repository/ui/catalog/_content/node.html index ec678a6f86545e5014e68b7fb1fc6ef2a2c09279..15eedc15d0bb55108582b19216ae62497907c93e 100644 --- a/src/main/java/org/olat/repository/ui/catalog/_content/node.html +++ b/src/main/java/org/olat/repository/ui/catalog/_content/node.html @@ -86,8 +86,8 @@ <h4>$r.translate("cat.externalLink")</h4> #if($extLink) <div class="o_copy_code o_nowrap"> - <a href="javascript:;" id="o_extlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"></i></a> - $extLink + <a href="javascript:;" id="o_extlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"> </i></a> + <input type="text" value="$extLink" onclick="this.select()"/> <script type="text/javascript"> /* <![CDATA[ */ jQuery(function() { @@ -99,8 +99,8 @@ #end #if($guestExtLink) <div class="o_copy_code o_nowrap"> - <a href="javascript:;" id="o_guestextlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"></i></a> - ${guestExtLink} + <a href="javascript:;" id="o_guestextlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"> </i></a> + <input type="text" value="$guestExtLink" onclick="this.select()"/> <script type="text/javascript"> /* <![CDATA[ */ jQuery(function() { diff --git a/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pl.properties index 99f015a3d05fad1d51523877aa9662a850066315..88e657b8193cb719d3124fea4010903268d1a8b6 100644 --- a/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pl.properties @@ -1,9 +1,12 @@ -#Fri Jan 11 13:42:50 CET 2013 +#Mon Aug 21 14:41:04 CEST 2017 +admin.catalog.settings=Ustawienia katalogu +admin.menu.title=Katalog cat.externalLink=Zewn\u0119trzny link do kategorii cat.login=Zaloguj si\u0119 cat.move.submit=Przesu\u0144 element cat.move.title=Dodaj pozycj\u0119 do kategorii -catalog.locked.by=Zadanie nie mo\u017Ce zosta\u0107 wykonane w tej chwili, poniewa\u017C katalog jest obecnie edytowany przez u\u017Cytkownika {0} +catalog.courses=Moje kursy +catalog.locked.by=Zadanie nie mo\u017Ce zosta\u0107 wykonane w tej chwili, poniewa\u017C katalog jest obecnie edytowany przez u\u017Cytkownika {0} catalog.tree.add.already.exists=Zas\u00F3b edukacyjny {0} jest ju\u017C przypisany do tej kategorii w katalogu catalog.tree.add.intro=Wybierz miejsce w katalogu, w kt\u00F3rym chcesz umie\u015Bci\u0107 zas\u00F3b\: {0} catalog.tree.add.title=Dodaj zas\u00F3b edukacyjny "{0}" do katalogu @@ -34,10 +37,10 @@ tools.add.catalog.link=Zasoby edukacyjne tools.add.header=Dodaj tools.delete.catalog.entry=Usu\u0144 tools.edit.catalog.category=Zmie\u0144 nazw\u0119 lub opis -tools.edit.catalog.category.ownergroup=Mianuj admina +tools.edit.catalog.category.ownergroup=Mianuj administratora tools.edit.header=Kategoria tools.move.catalog.entry=Przesu\u0144 tools.move.catalog.entry.failed=Wyst\u0105pi\u0142 b\u0142\u0105d, element nie m\u00F3g\u0142 zosta\u0107 przesuni\u0119ty tools.move.catalog.entry.success=Pozycja "{0}" zosta\u0142a przesuni\u0119ta pomy\u015Blnie -tools.new.catalog.categoryrequest=Kontakt z adminem +tools.new.catalog.categoryrequest=Kontakt z administratorem tools.pastestructure=Wstaw element struktury diff --git a/src/main/java/org/olat/repository/ui/list/_content/details.html b/src/main/java/org/olat/repository/ui/list/_content/details.html index 3ab004132c63d1d9dfeb80fd67a1171800d0d4ad..d410068d4de03a0645cf699dc35c13e357fdb979 100644 --- a/src/main/java/org/olat/repository/ui/list/_content/details.html +++ b/src/main/java/org/olat/repository/ui/list/_content/details.html @@ -197,8 +197,8 @@ <div class="o_extlink clearfix o_block_large_bottom"> <h4>$r.translate("details.extlinkheader")</h4> <div class="o_copy_code o_nowrap"> - <a href="javascript:;" id="o_extlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"></i></a> - $extlink + <a href="javascript:;" id="o_extlink"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"> </i></a> + <input type="text" value="$extlink" onclick="this.select()"/> <script type="text/javascript"> /* <![CDATA[ */ jQuery(function() { @@ -209,8 +209,8 @@ </div> #if ($isGuestAllowed) <div class="o_copy_code o_nowrap"> - <a href="javascript:;" id="o_extlink2"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"></i></a> - ${extlink}?guest=true&lang=$r.getLanguageCode() + <a href="javascript:;" id="o_extlink2"><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"> </i></a> + <input type="text" value="${extlink}?guest=true&lang=$r.getLanguageCode()" onclick="this.select()"/> <script type="text/javascript"> /* <![CDATA[ */ jQuery(function() { diff --git a/src/main/java/org/olat/resource/accesscontrol/ACService.java b/src/main/java/org/olat/resource/accesscontrol/ACService.java index 919f464cd2ae0ce1c08b28e938b33f575e0269d2..c5aecfe996835c429d100463b6243440307f1994 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ACService.java +++ b/src/main/java/org/olat/resource/accesscontrol/ACService.java @@ -38,19 +38,19 @@ import org.olat.resource.accesscontrol.ui.OrderTableItem; import org.olat.user.propertyhandlers.UserPropertyHandler; /** - * + * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public interface ACService { - + /** - * + * * @param resource - * @param atDate + * @param atDate * @return */ public boolean isResourceAccessControled(OLATResource resource, Date atDate); - + /** * The rule to access a business group:<br/> * -No offer, access is free<br/> @@ -62,11 +62,11 @@ public interface ACService { * @return */ public AccessResult isAccessible(BusinessGroup group, Identity forId, boolean allowNonInteractiveAccess); - + public AccessResult isAccessible(RepositoryEntry entry, Identity forId, boolean allowNonInteractiveAccess); - + /** - * + * * @param entry * @param forId * @param knowMember If you know that the forId is a member @@ -75,24 +75,24 @@ public interface ACService { */ public AccessResult isAccessible(RepositoryEntry entry, Identity forId, Boolean knowMember, boolean allowNonInteractiveAccess); - + public Offer createOffer(OLATResource resource, String resourceName); - + public Offer save(Offer offer); - + public void deleteOffer(Offer offer); - - + + public List<OLATResourceAccess> filterRepositoryEntriesWithAC(List<RepositoryEntry> repoEntries); - + public List<OLATResourceAccess> filterResourceWithAC(List<OLATResource> resources); - + public Set<Long> filterResourcesWithAC(Collection<Long> resourceKeys); - + public List<Offer> findOfferByResource(OLATResource resource, boolean valid, Date atDate); - + /** - * + * * @param resourceKeys This parameter is mandatory and must not be empty * @param resourceType * @param valid @@ -103,22 +103,26 @@ public interface ACService { /** * Get the list of access methods for a business group that are currently available - * @param group - * @param valid + * @param group + * @param valid * @param atDate * @return The list of OfferAccess objects that represent available access methods */ public List<OfferAccess> getAccessMethodForBusinessGroup(BusinessGroup group, boolean valid, Date atDate); - + + public List<OfferAccess> getValidOfferAccess(OLATResource resource, AccessMethod method); + + public List<AccessMethod> getAvailableMethodsByType(Class<? extends AccessMethod> type); + public OfferAccess saveOfferAccess(OfferAccess link); - + public AccessResult accessResource(Identity identity, OfferAccess link, Object argument); public boolean allowAccesToResource(Identity identity, Offer offer); - + public boolean denyAccesToResource(Identity identity, Offer offer); - - + + /** * Get the reservation form an identity on a resource * @param identity @@ -126,21 +130,21 @@ public interface ACService { * @return */ public ResourceReservation getReservation(Identity identity, OLATResource resource); - + /** * Get the reservations pending a list of resources. * @param resources * @return */ public List<ResourceReservation> getReservations(List<OLATResource> resources); - + /** * The list of pending reservations * @param identity * @return */ public List<ResourceReservation> getReservations(Identity identity); - + /** * Reserve a resource * @param identity @@ -148,57 +152,59 @@ public interface ACService { * @return */ public boolean reserveAccessToResource(Identity identity, OfferAccess offer); - + /** * A user must sometimes explicitly accept a reservation. * @param identity * @param reservation */ public void acceptReservationToResource(Identity identity, ResourceReservation reservation); - + /** * Cancel a reservation * @param identity * @param reservation */ public void removeReservation(Identity ureqIdentity, Identity identity, ResourceReservation reservation); - + public int countReservations(OLATResource resource); - + public void cleanupReservations(); - + /** - * + * * @param resources * @return */ public List<ACResourceInfo> getResourceInfos(List<OLATResource> resources); public String resolveDisplayName(OLATResource resource); - + public void enableMethod(Class<? extends AccessMethod> type, boolean enable); - + public List<AccessMethod> getAvailableMethods(Identity identity, Roles roles); - + public OfferAccess createOfferAccess(Offer offer, AccessMethod method); - + public void deletedLinkToMethod(OfferAccess link); - + public List<OfferAccess> getOfferAccess(Offer offer, boolean valid); - + public Order loadOrderByKey(Long key); - + public List<Order> findOrders(Identity delivery, OrderStatus... status); - + public List<AccessTransaction> findAccessTransactions(Order order); - + public List<Order> findOrders(OLATResource resource, OrderStatus... status); - + + public List<Order> findOrder(OLATResource resource, Identity identity, AccessMethod method); + public int countOrderItems(OLATResource resource, IdentityRef delivery, Long orderNr, Date from, Date to, OrderStatus[] statuss); - + public List<OrderTableItem> findOrderItems(OLATResource resource, IdentityRef delivery, Long orderNr, Date from, Date to, OrderStatus[] status, int firstResult, int maxResults, List<UserPropertyHandler> userPropertyHandlers, SortKey... orderBy); - + } diff --git a/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java b/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java index b528177653f4bb2965040ab21c849715ba86d9fc..8dfb009d4797ca8cd63bda42353ab46ad153cc62 100644 --- a/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java +++ b/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java @@ -40,28 +40,29 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; /** - * + * * Description:<br> * Module for access control of OLAT Resource - * + * * <P> * Initial Date: 14 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Service("acModule") public class AccessControlModule extends AbstractSpringModule implements ConfigOnOff { - + private static final OLog log = Tracing.createLoggerFor(AccessControlModule.class); - + public static final String AC_ENABLED = "resource.accesscontrol.enabled"; public static final String AC_HOME_ENABLED = "resource.accesscontrol.home.overview"; private static final String VAT_ENABLED = "vat.enabled"; private static final String VAT_RATE = "vat.rate"; private static final String VAT_NR = "vat.number"; - + private static final String TOKEN_ENABLED = "method.token.enabled"; private static final String FREE_ENABLED = "method.free.enabled"; private static final String PAYPAL_ENABLED = "method.paypal.enabled"; + private static final String AUTO_ENABLED = "method.auto.enabled"; @Value("${resource.accesscontrol.enabled:true}") private boolean enabled; @@ -69,6 +70,8 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO private boolean homeOverviewEnabled; @Value("${method.free.enabled:true}") private boolean freeEnabled; + @Value("${method.auto.enabled:false}") + private boolean autoEnabled; @Value("${method.token.enabled:true}") private boolean tokenEnabled; @Value("${method.paypal.enabled:false}") @@ -97,7 +100,7 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO if(StringHelper.containsNonWhitespace(enabledObj)) { enabled = "true".equals(enabledObj); } - + String tokenEnabledObj = getStringPropertyValue(TOKEN_ENABLED, true); if(StringHelper.containsNonWhitespace(tokenEnabledObj)) { tokenEnabled = "true".equals(tokenEnabledObj); @@ -107,22 +110,27 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO if(StringHelper.containsNonWhitespace(paypalEnabledObj)) { paypalEnabled = "true".equals(paypalEnabledObj); } - + String freeEnabledObj = getStringPropertyValue(FREE_ENABLED, true); if(StringHelper.containsNonWhitespace(freeEnabledObj)) { freeEnabled = "true".equals(freeEnabledObj); } - + + String autoEnabledObj = getStringPropertyValue(AUTO_ENABLED, true); + if(StringHelper.containsNonWhitespace(autoEnabledObj)) { + autoEnabled = "true".equals(autoEnabledObj); + } + String homeEnabledObj = getStringPropertyValue(AC_HOME_ENABLED, true); if(StringHelper.containsNonWhitespace(homeEnabledObj)) { homeOverviewEnabled = "true".equals(homeEnabledObj); } - + String vatEnabledObj = getStringPropertyValue(VAT_ENABLED, true); if(StringHelper.containsNonWhitespace(vatEnabledObj)) { vatEnabled = "true".equals(vatEnabledObj); } - + String vatRateObj = getStringPropertyValue(VAT_RATE, true); if(StringHelper.containsNonWhitespace(vatRateObj)) { try { @@ -131,7 +139,7 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO log.error("Error parsing the VAT: " + vatRateObj, e); } } - + String vatNrObj = getStringPropertyValue(VAT_NR, true); if(StringHelper.containsNonWhitespace(vatNrObj)) { vatNumber = vatNrObj; @@ -143,12 +151,12 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO protected void initFromChangedProperties() { init(); } - + @Override public boolean isEnabled() { return enabled; } - + public void setEnabled(boolean enabled) { if(this.enabled != enabled) { setStringProperty(AC_ENABLED, Boolean.toString(enabled), true); @@ -180,7 +188,20 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO acMethodManager.enableMethod(FreeAccessMethod.class, freeEnabled); } } - + + public boolean isAutoEnabled() { + return autoEnabled; + } + + public void setAutoEnabled(boolean autoEnabled) { + if(this.autoEnabled != autoEnabled) { + setStringProperty(AUTO_ENABLED, Boolean.toString(autoEnabled), true); + } + if(acMethodManager != null) { + acMethodManager.enableAutoMethods(autoEnabled); + } + } + public boolean isPaypalEnabled() { return paypalEnabled; } @@ -203,7 +224,7 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO setStringProperty(AC_HOME_ENABLED, Boolean.toString(homeOverviewEnabled), true); } } - + public boolean isVatEnabled() { return vatEnabled; } @@ -231,21 +252,21 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO } public List<AccessMethodHandler> getMethodHandlers() { - return new ArrayList<AccessMethodHandler>(methodHandlers); + return new ArrayList<>(methodHandlers); } - + public void setMethodHandlers(List<AccessMethodHandler> handlers) { if(handlers != null) { methodHandlers.addAll(handlers); } } - + public void addMethodHandler(AccessMethodHandler handler) { if(handler != null) { methodHandlers.add(handler); } } - + public void removeMethodHandler(AccessMethodHandler handler) { if(handler != null) { methodHandlers.remove(handler); diff --git a/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml b/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml index ce642acdf8bc722c62a2d3a6eb14f6b3bbe07c9e..fa673d4cfcf31588b0e9f056399f042a9fb1bee7 100644 --- a/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml +++ b/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml @@ -2,9 +2,9 @@ <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation="http://www.springframework.org/schema/beans + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/context + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.olat.resource.accesscontrol" /> @@ -12,42 +12,29 @@ <!-- Extension for archiver --> <bean class="org.olat.resource.accesscontrol.ui.OrdersActionExtension" init-method="initExtensionPoints"> <constructor-arg index="0" ref="acModule" /> - <property name="actionController"> + <property name="actionController"> <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> <property name="className" value="org.olat.resource.accesscontrol.ui.OrdersAdminController"/> </bean> </property> - + <property name="i18nActionKey" value="order.menu.title.alt"/> <property name="i18nDescriptionKey" value="order.menu.title.alt"/> <property name="translationPackage" value="org.olat.resource.accesscontrol.ui"/> <property name="extensionPoints"> - <list> - <value>org.olat.course.archiver.ArchiverMainController</value> + <list> + <value>org.olat.course.archiver.ArchiverMainController</value> </list> </property> <property name="order" value="267" /> </bean> - + <!-- The "orders" (Buchungen) in Home --> - <bean class="org.olat.instantMessaging.InstantMessagingUserToolExtension" init-method="initExtensionPoints"> - <property name="order" value="118" /> - <property name="navigationKey" value="imclient" /> - <property name="translationPackage" value="org.olat.instantMessaging.ui" /> - <property name="i18nActionKey" value="im.chat"/> - <property name="i18nDescriptionKey" value="im.chat"/> - <property name="extensionPoints"> - <list> - <value>org.olat.home.HomeMainController</value> - </list> - </property> - </bean> - <bean class="org.olat.resource.accesscontrol.ui.HomeOrdersActionExtension" name="accesscontrol.actExt" init-method="initExtensionPoints"> <constructor-arg index="0" ref="acModule" /> <property name="order" value="109" /> <property name="enabled" value="${minimalhome.ext.bookings}"></property> - <property name="actionController"> + <property name="actionController"> <bean class=" org.olat.core.gui.control.creator.FactoryControllerCreator" scope="prototype"> <property name="factoryName" value="org.olat.resource.accesscontrol.ACUIFactory"/> <property name="factoryMethod" value="createOrdersController"/> @@ -60,61 +47,61 @@ <property name="i18nActionKey" value="menu.orders"/> <property name="i18nDescriptionKey" value="menu.orders.alt"/> <property name="extensionPoints"> - <list> + <list> <value>org.olat.home.HomeMainController</value> </list> </property> </bean> - + <!-- Access control administration --> <bean class="org.olat.core.extensions.action.GenericActionExtension" id="sysadmin.menupoint.access" init-method="initExtensionPoints"> - <property name="actionController"> + <property name="actionController"> <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> <property name="className" value="org.olat.resource.accesscontrol.ui.AccessControlAdminController"/> </bean> </property> <property name="navigationKey" value="accesscontrol" /> - <property name="parentTreeNodeIdentifier" value="sysconfigParent" /> + <property name="parentTreeNodeIdentifier" value="sysconfigParent" /> <property name="i18nActionKey" value="admin.menu.title"/> <property name="i18nDescriptionKey" value="admin.menu.title.alt"/> <property name="translationPackage" value="org.olat.resource.accesscontrol.ui"/> <property name="extensionPoints"> - <list> - <value>org.olat.admin.SystemAdminMainController</value> + <list> + <value>org.olat.admin.SystemAdminMainController</value> </list> </property> <property name="order" value="7220" /> </bean> - - <bean id="acReservationCleanupJob" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> + + <bean id="acReservationCleanupJob" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <property name="jobDetail" ref="acReservationCleanupJobDetail"/> <!-- 60 seconds --> <property name="repeatInterval" value="60000"/> <property name="startDelay" value="30000" /> </bean> - - <bean id="acReservationCleanupJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean"> + + <bean id="acReservationCleanupJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="org.olat.resource.accesscontrol.manager.ReservationsJob" /> </bean> - + <bean id="freeAccessHandler" class="org.olat.resource.accesscontrol.provider.free.FreeAccessHandler"/> <bean id="tokenAccessHandler" class="org.olat.resource.accesscontrol.provider.token.TokenAccessHandler"/> - + <!-- Orders admin panel --> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> - <property name="actionController"> + <property name="actionController"> <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> <property name="className" value="org.olat.resource.accesscontrol.ui.OrdersAdminController"/> </bean> </property> <property name="navigationKey" value="booking" /> - <property name="parentTreeNodeIdentifier" value="modulesParent" /> + <property name="parentTreeNodeIdentifier" value="modulesParent" /> <property name="i18nActionKey" value="order.menu.title"/> <property name="i18nDescriptionKey" value="order.menu.title.alt"/> <property name="translationPackage" value="org.olat.resource.accesscontrol.ui"/> <property name="extensionPoints"> - <list> - <value>org.olat.admin.SystemAdminMainController</value> + <list> + <value>org.olat.admin.SystemAdminMainController</value> </list> </property> <property name="order" value="7600" /> diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java index 3784ae097ff3924d68c962a8645c539fe4a32aa1..a517ed0173b7f314ef63370b40f63b68eefa950e 100644 --- a/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java +++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java @@ -33,6 +33,7 @@ import java.util.Set; import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityRef; +import org.olat.commons.calendar.CalendarUtils; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; @@ -78,19 +79,19 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** - * + * * Description:<br> * The access control is not intend for security check. - * + * * <P> * Initial Date: 14 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Service("acService") public class ACFrontendManager implements ACService { - + private static final OLog log = Tracing.createLoggerFor(ACFrontendManager.class); - + @Autowired private DB dbInstance; @Autowired @@ -134,7 +135,7 @@ public class ACFrontendManager implements ACService { if(!accessModule.isEnabled()) { return new AccessResult(true); } - + boolean member; if(knowMember == null) { member = repositoryService.isMember(forId, entry); @@ -144,40 +145,41 @@ public class ACFrontendManager implements ACService { if(member) { return new AccessResult(true); } - - List<Offer> offers = accessManager.findOfferByResource(entry.getOlatResource(), true, new Date()); + + Date now = dateNow(); + List<Offer> offers = accessManager.findOfferByResource(entry.getOlatResource(), true, now); if(offers.isEmpty()) { if(methodManager.isValidMethodAvailable(entry.getOlatResource(), null)) { //not open for the moment: no valid offer at this date but some methods are defined return new AccessResult(false); } else { return new AccessResult(true); - } + } } return isAccessible(forId, offers, allowNonInteractiveAccess); } - + @Override public AccessResult isAccessible(RepositoryEntry entry, Identity forId, boolean allowNonInteractiveAccess) { if(!accessModule.isEnabled()) { return new AccessResult(true); } - + boolean member = repositoryService.isMember(forId, entry); return isAccessible(entry, forId, new Boolean(member), allowNonInteractiveAccess); } - + /** - * + * * @param resource - * @param atDate + * @param atDate * @return */ @Override public boolean isResourceAccessControled(OLATResource resource, Date atDate) { return methodManager.isValidMethodAvailable(resource, atDate); } - + /** * The rule to access a business group:<br/> * -No offer, access is free<br/> @@ -201,21 +203,22 @@ public class ACFrontendManager implements ACService { if(roles.contains(GroupRoles.participant.name())) { return new AccessResult(true); } - + + Date now = dateNow(); OLATResource resource = OLATResourceManager.getInstance().findResourceable(group); - List<Offer> offers = accessManager.findOfferByResource(resource, true, new Date()); + List<Offer> offers = accessManager.findOfferByResource(resource, true, now); if(offers.isEmpty()) { if(methodManager.isValidMethodAvailable(resource, null)) { //not open for the moment: no valid offer at this date but some methods are defined return new AccessResult(false); } else { return new AccessResult(true); - } + } } - + return isAccessible(forId, offers, allowNonInteractiveAccess); } - + protected AccessResult isAccessible(Identity identity, List<Offer> offers, boolean allowNonInteractiveAccess) { List<OfferAccess> offerAccess = methodManager.getOfferAccess(offers, true); if(offerAccess.isEmpty()) { @@ -253,12 +256,13 @@ public class ACFrontendManager implements ACService { resourceKeys.add(ores.getKey()); resourceTypes.add(ores.getResourceableTypeName()); } - + String resourceType = null; if(resourceTypes.size() == 1) { resourceType = resourceTypes.iterator().next(); } - return methodManager.getAccessMethodForResources(resourceKeys, resourceType, "BusinessGroup", true, new Date()); + Date now = dateNow(); + return methodManager.getAccessMethodForResources(resourceKeys, resourceType, "BusinessGroup", true, now); } @Override @@ -272,12 +276,13 @@ public class ACFrontendManager implements ACService { resourceKeys.add(resource.getKey()); resourceTypes.add(resource.getResourceableTypeName()); } - + String resourceType = null; if(resourceTypes.size() == 1) { resourceType = resourceTypes.iterator().next(); } - return methodManager.getAccessMethodForResources(resourceKeys, resourceType, "BusinessGroup", true, new Date()); + Date now = dateNow(); + return methodManager.getAccessMethodForResources(resourceKeys, resourceType, "BusinessGroup", true, now); } @Override @@ -289,9 +294,9 @@ public class ACFrontendManager implements ACService { public List<Offer> findOfferByResource(OLATResource resource, boolean valid, Date atDate) { return accessManager.findOfferByResource(resource, valid, atDate); } - + /** - * + * * @param resourceKeys This parameter is mandatory and must not be empty! */ @Override @@ -304,8 +309,8 @@ public class ACFrontendManager implements ACService { /** * Get the list of access methods for a business group that are currently available - * @param group - * @param valid + * @param group + * @param valid * @param atDate * @return The list of OfferAccess objects that represent available access methods */ @@ -322,6 +327,16 @@ public class ACFrontendManager implements ACService { return offerAccess; } + @Override + public List<OfferAccess> getValidOfferAccess(OLATResource resource, AccessMethod method) { + return methodManager.getValidOfferAccess(resource, method); + } + + @Override + public List<AccessMethod> getAvailableMethodsByType(Class<? extends AccessMethod> type) { + return methodManager.getAvailableMethodsByType(type); + } + @Override public Offer save(Offer offer) { return accessManager.saveOffer(offer); @@ -335,20 +350,20 @@ public class ACFrontendManager implements ACService { } return methodManager.save(link); } - + @Override public AccessResult accessResource(Identity identity, OfferAccess link, Object argument) { if(link == null || link.getOffer() == null || link.getMethod() == null) { log.audit("Access refused (no offer) to: " + link + " for " + identity); return new AccessResult(false); } - + AccessMethodHandler handler = accessModule.getAccessMethodHandler(link.getMethod().getType()); if(handler == null) { log.audit("Access refused (no handler method) to: " + link + " for " + identity); return new AccessResult(false); } - + if(handler.checkArgument(link, argument)) { if(allowAccesToResource(identity, link.getOffer())) { Order order = orderManager.saveOneClick(identity, link); @@ -365,7 +380,7 @@ public class ACFrontendManager implements ACService { } return new AccessResult(false); } - + @Override public void acceptReservationToResource(Identity identity, ResourceReservation reservation) { OLATResource resource = reservation.getResource(); @@ -391,7 +406,7 @@ public class ACFrontendManager implements ACService { public ResourceReservation getReservation(Identity identity, OLATResource resource) { return reservationDao.loadReservation(identity, resource); } - + @Override public List<ResourceReservation> getReservations(List<OLATResource> resources) { return reservationDao.loadReservations(resources); @@ -422,7 +437,7 @@ public class ACFrontendManager implements ACService { if(reservation != null) { reserved = true; } - + int currentCount = businessGroupService.countMembers(reloadedGroup, GroupRoles.participant.name()); int reservations = reservationDao.countReservations(resource); if(currentCount + reservations < reloadedGroup.getMaxParticipants().intValue()) { @@ -453,13 +468,13 @@ public class ACFrontendManager implements ACService { if(offer.getKey() == null) { return false; } - + //check the resource OLATResource resource = offer.getResource(); if(resource == null || resource.getKey() == null || resource.getResourceableId() == null || resource.getResourceableTypeName() == null) { return false; } - + String resourceType = resource.getResourceableTypeName(); if("BusinessGroup".equals(resourceType)) { BusinessGroup group = businessGroupService.loadBusinessGroup(resource); @@ -485,13 +500,13 @@ public class ACFrontendManager implements ACService { if(offer.getKey() == null) { return false; } - + //check the resource OLATResource resource = offer.getResource(); if(resource == null || resource.getKey() == null || resource.getResourceableId() == null || resource.getResourceableTypeName() == null) { return false; } - + String resourceType = resource.getResourceableTypeName(); if("BusinessGroup".equals(resourceType)) { BusinessGroup group = businessGroupService.loadBusinessGroup(resource); @@ -529,13 +544,13 @@ public class ACFrontendManager implements ACService { } return null; } - + @Override public List<ACResourceInfo> getResourceInfos(List<OLATResource> resources) { if(resources == null || resources.isEmpty()) { return Collections.emptyList(); } - + List<OLATResource> groupResources = new ArrayList<OLATResource>(resources.size()); List<OLATResource> repositoryResources = new ArrayList<OLATResource>(resources.size()); for(OLATResource resource:resources) { @@ -606,7 +621,12 @@ public class ACFrontendManager implements ACService { public List<Order> findOrders(Identity delivery, OrderStatus... status) { return orderManager.findOrdersByDelivery(delivery, status); } - + + @Override + public List<Order> findOrder(OLATResource resource, Identity identity, AccessMethod method) { + return orderManager.findOrdersByResource(resource, identity, method); + } + @Override public List<AccessTransaction> findAccessTransactions(Order order) { return transactionManager.loadTransactionsForOrder(order); @@ -636,7 +656,7 @@ public class ACFrontendManager implements ACService { for(AccessMethod method:methods) { methodMap.put(method.getKey().toString(), method); } - + List<RawOrderItem> rawOrders = orderManager.findNativeOrderItems(resource, delivery, orderNr, from, to, status, firstResult, maxResults, userPropertyHandlers, orderBy); List<OrderTableItem> items = new ArrayList<>(rawOrders.size()); @@ -644,7 +664,7 @@ public class ACFrontendManager implements ACService { String orderStatusStr = rawOrder.getOrderStatus(); OrderStatus orderStatus = OrderStatus.valueOf(orderStatusStr); Status finalStatus = getStatus(orderStatusStr, rawOrder.getTrxStatus(), rawOrder.getPspTrxStatus()); - + String methodIds = rawOrder.getTrxMethodIds(); List<AccessMethod> orderMethods = new ArrayList<>(2); if(StringHelper.containsNonWhitespace(methodIds)) { @@ -655,23 +675,23 @@ public class ACFrontendManager implements ACService { } } } - + OrderTableItem item = new OrderTableItem(rawOrder.getOrderKey(), rawOrder.getOrderNr(), rawOrder.getTotal(), rawOrder.getCreationDate(), orderStatus, finalStatus, rawOrder.getDeliveryKey(), rawOrder.getUsername(), rawOrder.getUserProperties(), orderMethods); item.setResourceDisplayname(rawOrder.getResourceName()); - + items.add(item); } - + return items; } - + public Status getStatus(String orderStatus, String trxStatus, String pspTrxStatus) { boolean warning = false; boolean error = false; boolean canceled = false; - + if(OrderStatus.CANCELED.name().equals(orderStatus)) { canceled = true; } else if(OrderStatus.ERROR.name().equals(orderStatus)) { @@ -679,7 +699,7 @@ public class ACFrontendManager implements ACService { } else if(OrderStatus.PREPAYMENT.name().equals(orderStatus)) { warning = true; } - + if(StringHelper.containsNonWhitespace(trxStatus)) { if(trxStatus.contains(AccessTransactionStatus.CANCELED.name())) { canceled = true; @@ -687,7 +707,7 @@ public class ACFrontendManager implements ACService { error = true; } } - + if(StringHelper.containsNonWhitespace(pspTrxStatus)) { if(pspTrxStatus.contains(PSPTransactionStatus.ERROR.name())) { error = true; @@ -695,7 +715,7 @@ public class ACFrontendManager implements ACService { warning = true; } } - + if(error) { return Status.ERROR; } else if (warning) { @@ -704,8 +724,14 @@ public class ACFrontendManager implements ACService { return Status.CANCELED; } else { return Status.OK; - } + } } - - + + /** + * @return The current date without time + */ + private Date dateNow() { + return CalendarUtils.removeTime(new Date()); + } + } diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodDAO.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodDAO.java index 7c7d74ef4ea347a6d6fbd8ed833da82ac01b4295..65e609bf5e9242da0a34d1584a2d3c631c531a05 100644 --- a/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodDAO.java +++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodDAO.java @@ -35,16 +35,11 @@ import javax.persistence.TypedQuery; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.PersistenceHelper; -import org.olat.core.gui.control.Event; import org.olat.core.id.Identity; import org.olat.core.id.Roles; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; -import org.olat.core.util.coordinate.CoordinatorManager; -import org.olat.core.util.event.FrameworkStartedEvent; -import org.olat.core.util.event.FrameworkStartupEventChannel; -import org.olat.core.util.event.GenericEventListener; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceImpl; import org.olat.resource.accesscontrol.AccessControlModule; @@ -60,49 +55,50 @@ import org.olat.resource.accesscontrol.model.OLATResourceAccess; import org.olat.resource.accesscontrol.model.OfferAccessImpl; import org.olat.resource.accesscontrol.model.TokenAccessMethod; import org.olat.resource.accesscontrol.provider.paypal.model.PaypalAccessMethod; +import org.olat.shibboleth.manager.ShibbolethAutoAccessMethod; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** - * + * * Description:<br> * This class manages the methods available to access the resource. * As standard "static" (static as singleton), there is Token and Free * based access. - * + * * <P> * Initial Date: 18 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Service -public class ACMethodDAO implements GenericEventListener { - +public class ACMethodDAO implements InitializingBean { + private static final OLog log = Tracing.createLoggerFor(ACMethodDAO.class); @Autowired private DB dbInstance; @Autowired private AccessControlModule acModule; - - @Autowired - public ACMethodDAO(CoordinatorManager coordinatorManager) { - coordinatorManager.getCoordinator().getEventBus().registerFor(this, null, FrameworkStartupEventChannel.getStartupEventChannel()); - } @Override - public void event(Event event) { - if (event instanceof FrameworkStartedEvent && ((FrameworkStartedEvent) event).isEventOnThisNode()) { - enableMethod(TokenAccessMethod.class, acModule.isTokenEnabled()); - enableMethod(FreeAccessMethod.class, acModule.isFreeEnabled()); - enableMethod(PaypalAccessMethod.class, acModule.isPaypalEnabled()); - dbInstance.commitAndCloseSession(); - } + public void afterPropertiesSet() throws Exception { + enableMethod(TokenAccessMethod.class, acModule.isTokenEnabled()); + enableMethod(FreeAccessMethod.class, acModule.isFreeEnabled()); + enableMethod(PaypalAccessMethod.class, acModule.isPaypalEnabled()); + enableAutoMethods(acModule.isAutoEnabled()); + dbInstance.commitAndCloseSession(); + } + + + public void enableAutoMethods(boolean autoEnabled) { + enableMethod(ShibbolethAutoAccessMethod.class, autoEnabled); } public void enableMethod(Class<? extends AccessMethod> type, boolean enable) { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(type.getName()).append(" method"); - + List<AccessMethod> methods = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), AccessMethod.class) .getResultList(); @@ -131,7 +127,7 @@ public class ACMethodDAO implements GenericEventListener { public boolean isValidMethodAvailable(OLATResource resource, Date atDate) { StringBuilder sb = new StringBuilder(); - sb.append("select count(access.method) from acofferaccess access ") + sb.append("select access.method from acofferaccess access ") .append(" inner join access.offer offer") .append(" inner join offer.resource oResource") .append(" where access.valid=true") @@ -142,16 +138,22 @@ public class ACMethodDAO implements GenericEventListener { .append(" and (offer.validTo is null or offer.validTo>=:atDate)"); } - TypedQuery<Number> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class); + TypedQuery<AccessMethod> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), AccessMethod.class); query.setParameter("resourceKey", resource.getKey()); if(atDate != null) { query.setParameter("atDate", atDate, TemporalType.TIMESTAMP); } - Number methods = query.getSingleResult(); - return methods.intValue() > 0; + List<AccessMethod> methods = query.getResultList(); + List<AccessMethod> guiMethods = new ArrayList<>(); + for (AccessMethod method: methods) { + if (method.isVisibleInGui()) { + guiMethods.add(method); + } + } + return !guiMethods.isEmpty(); } - + public List<AccessMethod> getAllMethods() { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(AbstractAccessMethod.class.getName()).append(" method"); @@ -164,12 +166,12 @@ public class ACMethodDAO implements GenericEventListener { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(AbstractAccessMethod.class.getName()).append(" method") .append(" where method.valid=true and method.enabled=true"); - + TypedQuery<AccessMethod> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), AccessMethod.class); if(identity != null) { //query.setLong("identityKey", identity.getKey()); } - + List<AccessMethod> methods = query.getResultList(); List<AccessMethod> allowedMethods = new ArrayList<AccessMethod>(); for(AccessMethod method:methods) { @@ -187,7 +189,7 @@ public class ACMethodDAO implements GenericEventListener { sb.append("select method from ").append(AbstractAccessMethod.class.getName()).append(" method") .append(" where method.valid=true") .append(" and method.class=").append(type.getName()); - + TypedQuery<AccessMethod> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), AccessMethod.class); List<AccessMethod> methods = query.getResultList(); return methods; @@ -207,7 +209,28 @@ public class ACMethodDAO implements GenericEventListener { .setParameter("offerKey", offer.getKey()) .getResultList(); } - + + public List<OfferAccess> getValidOfferAccess(OLATResource resource, AccessMethod method) { + StringBuilder sb = new StringBuilder(); + sb.append("select access from acofferaccess access") + .append(" inner join fetch access.offer offer") + .append(" inner join fetch access.method method") + .append(" inner join fetch offer.resource resource") + .append(" where resource.key=:resourceKey") + .append(" and access.valid=true"); + if(method != null) { + sb.append(" and access.method=:method"); + } + + TypedQuery<OfferAccess> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), OfferAccess.class); + query.setParameter("resourceKey", resource.getKey()); + if(method != null) { + query.setParameter("method", method); + } + return query.getResultList(); + } + public List<OfferAccess> getOfferAccess(Collection<Offer> offers, boolean valid) { if(offers == null || offers.isEmpty()) return Collections.emptyList(); @@ -218,7 +241,7 @@ public class ACMethodDAO implements GenericEventListener { .append(" inner join fetch offer.resource resource") .append(" where offer.key in (:offersKey)") .append(" and access.valid=:valid"); - + List<Long> offersKey = PersistenceHelper.toKeys(offers); return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), OfferAccess.class) @@ -226,12 +249,12 @@ public class ACMethodDAO implements GenericEventListener { .setParameter("valid", valid) .getResultList(); } - + public List<OLATResourceAccess> getAccessMethodForResources(Collection<Long> resourceKeys, String resourceType, String excludedResourceType, boolean valid, Date atDate) { final int maxResourcesEntries = 250;//quicker to filter in java, numerous keys in "in" are slow - + StringBuilder sb = new StringBuilder(); sb.append("select access.method, resource, offer.price from acofferaccess access, ") .append(OLATResourceImpl.class.getName()).append(" resource") @@ -251,7 +274,7 @@ public class ACMethodDAO implements GenericEventListener { if(StringHelper.containsNonWhitespace(excludedResourceType)) { sb.append(" and not(oResource.resName=:excludedResourceType)"); } - + if(atDate != null) { sb.append(" and (offer.validFrom is null or offer.validFrom<=:atDate)") .append(" and (offer.validTo is null or offer.validTo>=:atDate)"); @@ -276,7 +299,7 @@ public class ACMethodDAO implements GenericEventListener { if(StringHelper.containsNonWhitespace(excludedResourceType)) { query.setParameter("excludedResourceType", excludedResourceType); } - + List<Object[]> rawResults = query.getResultList(); Map<Long,OLATResourceAccess> rawResultsMap = new HashMap<Long,OLATResourceAccess>(); for(Object[] rawResult:rawResults) { @@ -285,7 +308,10 @@ public class ACMethodDAO implements GenericEventListener { if(resourceKeysSet != null && !resourceKeysSet.contains(resource.getKey())) { continue; } - + if(!method.isVisibleInGui()) { + continue; + } + Price price = (Price)rawResult[2]; if(rawResultsMap.containsKey(resource.getKey())) { rawResultsMap.get(resource.getKey()).addBundle(price, method); @@ -293,7 +319,7 @@ public class ACMethodDAO implements GenericEventListener { rawResultsMap.put(resource.getKey(), new OLATResourceAccess(resource, price, method)); } } - + return new ArrayList<OLATResourceAccess>(rawResultsMap.values()); } @@ -305,7 +331,7 @@ public class ACMethodDAO implements GenericEventListener { access.setValid(true); return access; } - + public OfferAccess save(OfferAccess link) { if(link.getKey() == null) { dbInstance.getCurrentEntityManager().persist(link); @@ -314,22 +340,22 @@ public class ACMethodDAO implements GenericEventListener { } return link; } - + public void delete(OfferAccess link) { OfferAccessImpl access = (OfferAccessImpl)link; access.setValid(false); - + if(link.getKey() == null) return; dbInstance.updateObject(access); } - + /** * Activate the token method if not already configured. */ protected void activateTokenMethod(boolean enable) { StringBuilder sb = new StringBuilder(); sb.append("select method from actokenmethod method"); - + List<AccessMethod> methods = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), AccessMethod.class) .getResultList(); @@ -348,12 +374,12 @@ public class ACMethodDAO implements GenericEventListener { } } } - + protected void activateFreeMethod(boolean enable) { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(AbstractAccessMethod.class.getName()) .append(" method where method.class=").append(FreeAccessMethod.class.getName()); - + TypedQuery<AccessMethod> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), AccessMethod.class); List<AccessMethod> methods = query.getResultList(); if(methods.isEmpty() && enable) { @@ -371,4 +397,6 @@ public class ACMethodDAO implements GenericEventListener { } } } + + } \ No newline at end of file diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferDAO.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferDAO.java index 76dbcce208c2319949d840bd869ce3d2653b6073..398013d122564e92ec00f6a1b2f11fe7ac74c60e 100644 --- a/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferDAO.java +++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferDAO.java @@ -34,43 +34,55 @@ import javax.persistence.TypedQuery; import org.olat.core.commons.persistence.DB; import org.olat.resource.OLATResource; import org.olat.resource.accesscontrol.Offer; +import org.olat.resource.accesscontrol.model.AccessMethod; import org.olat.resource.accesscontrol.model.OfferImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** - * + * * Description:<br> - * + * * <P> * Initial Date: 14 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Service public class ACOfferDAO { - + @Autowired private DB dbInstance; - + public List<Offer> findOfferByResource(OLATResource resource, boolean valid, Date atDate) { StringBuilder sb = new StringBuilder(); - sb.append("select offer from acoffer offer") - .append(" left join fetch offer.resource resource") - .append(" where resource.key=:resourceKey") - .append(" and offer.valid=").append(valid); + sb.append("select offer, access.method from acofferaccess access ") + .append(" inner join access.offer offer") + .append(" left join offer.resource resource") + .append(" where resource.key=:resourceKey") + .append(" and offer.valid=").append(valid); + if(atDate != null) { sb.append(" and (offer.validFrom is null or offer.validFrom<=:atDate)") .append(" and (offer.validTo is null or offer.validTo>=:atDate)"); } - TypedQuery<Offer> query = dbInstance.getCurrentEntityManager() - .createQuery(sb.toString(), Offer.class) + TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Object[].class) .setParameter("resourceKey", resource.getKey()); if(atDate != null) { query.setParameter("atDate", atDate, TemporalType.TIMESTAMP); } - - List<Offer> offers = query.getResultList(); + + List<Object[]> loadedObjects = query.getResultList(); + List<Offer> offers = new ArrayList<>(); + for(Object[] objects:loadedObjects) { + Offer offer = (Offer)objects[0]; + AccessMethod method = (AccessMethod)objects[1]; + if(method.isVisibleInGui()) { + offers.add(offer); + } + } + return offers; } @@ -90,7 +102,7 @@ public class ACOfferDAO { public Set<Long> filterResourceWithOffer(Collection<Long> resourceKeys) { if(resourceKeys == null || resourceKeys.isEmpty()) return Collections.emptySet(); - + StringBuilder sb = new StringBuilder(); sb.append("select offer.resource.key from acoffer offer") .append(" inner join offer.resource resource") @@ -99,7 +111,7 @@ public class ACOfferDAO { Set<Long> resourceWithOffers = new HashSet<Long>(); List<Long> keys = new ArrayList<Long>(resourceKeys); - + //too much in with hibernate can generate a stack overflow int hibernateInBatch = 500; int firstResult = 0; @@ -108,14 +120,14 @@ public class ACOfferDAO { List<Long> inParameter = keys.subList(firstResult, toIndex); query.setParameter("resourceKeys", inParameter); firstResult += inParameter.size(); - + List<Long> offerKeys = query.getResultList(); resourceWithOffers.addAll(offerKeys); } while(firstResult < keys.size()); return resourceWithOffers; } - + public Offer createOffer(OLATResource resource, String resourceName) { OfferImpl offer = new OfferImpl(); Date now = new Date(); @@ -135,7 +147,7 @@ public class ACOfferDAO { offer.setResourceTypeName(resourceTypeName); return offer; } - + public void deleteOffer(Offer offer) { if(offer instanceof OfferImpl) { ((OfferImpl)offer).setValid(false); diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderDAO.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderDAO.java index 318e6b310fcae843dfd308723a954155edd5d86c..fd674822e7c61a5f1b1c721857403587ccb2741c 100644 --- a/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderDAO.java +++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderDAO.java @@ -43,6 +43,7 @@ import org.olat.resource.accesscontrol.Order; import org.olat.resource.accesscontrol.OrderLine; import org.olat.resource.accesscontrol.OrderPart; import org.olat.resource.accesscontrol.OrderStatus; +import org.olat.resource.accesscontrol.model.AccessMethod; import org.olat.resource.accesscontrol.model.OrderImpl; import org.olat.resource.accesscontrol.model.OrderLineImpl; import org.olat.resource.accesscontrol.model.OrderPartImpl; @@ -52,21 +53,21 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** - * + * * Description:<br> * manager for the order. Orders are a part of the confirmation of an access * to a resource. The second part is the transaction. - * + * * <P> * Initial Date: 19 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Service public class ACOrderDAO { - + @Autowired private DB dbInstance; - + public OrderImpl createOrder(Identity delivery) { OrderImpl order = new OrderImpl(); Date now = new Date(); @@ -92,7 +93,7 @@ public class ACOrderDAO { part.getOrderLines().add(line); return line; } - + private OrderLineImpl createOrderLine(Offer offer) { OrderLineImpl line = new OrderLineImpl(); line.setCreationDate(new Date()); @@ -101,7 +102,7 @@ public class ACOrderDAO { line.setTotal(line.getUnitPrice().clone()); return line; } - + public Order save(Order order) { if(order.getKey() == null) { dbInstance.saveObject(order); @@ -110,7 +111,7 @@ public class ACOrderDAO { } return order; } - + public Order save(Order order, OrderStatus status) { ((OrderImpl)order).setOrderStatus(status); if(order.getKey() == null) { @@ -120,11 +121,11 @@ public class ACOrderDAO { } return order; } - + public Order saveOneClick(Identity delivery, OfferAccess link) { return saveOneClick(delivery, link, OrderStatus.PAYED); } - + public Order saveOneClick(Identity delivery, OfferAccess link, OrderStatus status) { OrderImpl order = createOrder(delivery); order.setOrderStatus(status); @@ -143,9 +144,10 @@ public class ACOrderDAO { dbInstance.getCurrentEntityManager().persist(order); dbInstance.getCurrentEntityManager().persist(part); dbInstance.getCurrentEntityManager().persist(line); + return order; } - + public List<Order> findOrdersByDelivery(Identity delivery, OrderStatus... status) { StringBuilder sb = new StringBuilder(); sb.append("select order from ").append(OrderImpl.class.getName()).append(" order") @@ -153,7 +155,7 @@ public class ACOrderDAO { if(status != null && status.length > 0) { sb.append(" and order.orderStatusStr in (:status)"); } - + TypedQuery<Order> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Order.class) .setParameter("deliveryKey", delivery.getKey()); @@ -164,22 +166,22 @@ public class ACOrderDAO { } query.setParameter("status", statusStr); } - + List<Order> orders = query.getResultList(); return orders; } - + /** * The method is optimized for our settings: 1 order -> 1 order part -> 1 order line - * + * * @param resource * @param delivery * @return */ public int countNativeOrderItems(OLATResource resource, IdentityRef delivery, Long orderNr, Date from, Date to, OrderStatus... status) { - + NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance); sb.append("select count(o.order_id)") .append(" from o_ac_order o") @@ -248,14 +250,14 @@ public class ACOrderDAO { cal.set(Calendar.MILLISECOND, 0); query.setParameter("to", cal.getTime(), TemporalType.TIMESTAMP); } - + Object rawOrders = query.getSingleResult(); return rawOrders instanceof Number ? ((Number)rawOrders).intValue() : 0; } - + /** * The method is optimized for our settings: 1 order -> 1 order part -> 1 order line - * + * * @param resource * @param delivery * @return @@ -263,7 +265,7 @@ public class ACOrderDAO { public List<RawOrderItem> findNativeOrderItems(OLATResource resource, IdentityRef delivery, Long orderNr, Date from, Date to, OrderStatus[] status, int firstResult, int maxResults, List<UserPropertyHandler> userPropertyHandlers, SortKey... orderBy) { - + NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance); sb.append("select") .append(" o.order_id as order_id,") @@ -293,11 +295,11 @@ public class ACOrderDAO { .append(" inner join o_ac_offer offer on (order_line.fk_offer_id=offer.offer_id)"); if(delivery == null) { sb.append(" inner join o_bs_identity delivery on (delivery.id=o.fk_delivery_id)") - .append(" inner join o_user delivery_user on (delivery_user.fk_identity=delivery.id)"); + .append(" inner join o_user delivery_user on (delivery_user.fk_identity=delivery.id)"); } sb.append(" left join o_ac_paypal_transaction pspTrx on (o.order_id = pspTrx.order_id)") .append(" left join o_ac_transaction trx on (o.order_id = trx.fk_order_id)"); - + boolean where = false; if(resource != null) { where = PersistenceHelper.appendAnd(sb, where); @@ -323,7 +325,7 @@ public class ACOrderDAO { where = PersistenceHelper.appendAnd(sb, where); sb.append("o.order_id=:orderNr"); } - + sb.append(" group by o.order_id"); if(dbInstance.isOracle()) { sb.append(", o.total_currency_code, o.total_amount, o.creationdate, o.order_status, o.fk_delivery_id"); @@ -380,7 +382,7 @@ public class ACOrderDAO { cal.set(Calendar.MILLISECOND, 0); query.setParameter("to", cal.getTime(), TemporalType.TIMESTAMP); } - + if(maxResults > 0) { query.setFirstResult(firstResult).setMaxResults(maxResults); } @@ -391,7 +393,7 @@ public class ACOrderDAO { for(Object rawOrder:rawOrders) { Object[] order = (Object[])rawOrder; int pos = 0; - + Long orderKey = ((Number)order[pos++]).longValue(); String totalCurrencyCode = (String)order[pos++]; BigDecimal totalAmount = (BigDecimal)order[pos++]; @@ -402,7 +404,7 @@ public class ACOrderDAO { String trxStatus = (String)order[pos++]; String trxMethodIds = (String)order[pos++]; String pspTrxStatus = (String)order[pos++]; - + String username = null; String[] userProperties = null; if(numOfProperties > 0) { @@ -413,8 +415,8 @@ public class ACOrderDAO { for(int i=0; i<numOfProperties; i++) { userProperties[i] = (String)order[pos++]; } - } - + } + RawOrderItem item = new RawOrderItem(orderKey, orderKey.toString(), totalCurrencyCode, totalAmount, creationDate, orderStatus, deliveryKey, resourceName, trxStatus, trxMethodIds, pspTrxStatus, username, userProperties); @@ -433,7 +435,7 @@ public class ACOrderDAO { if(status != null && status.length > 0) { sb.append(" and o.orderStatusStr in (:status)"); } - + TypedQuery<Order> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Order.class) .setParameter("resourceKey", resource.getKey()); @@ -444,7 +446,36 @@ public class ACOrderDAO { } query.setParameter("status", statusStr); } - + + return query.getResultList(); + } + + public List<Order> findOrdersByResource(OLATResource resource, Identity identity, AccessMethod method) { + StringBuilder sb = new StringBuilder(); + sb.append("select distinct(o) from ").append(OrderImpl.class.getName()).append(" o") + .append(" inner join o.parts orderPart ") + .append(" inner join orderPart.lines orderLine ") + .append(" inner join orderLine.offer offer ") + .append(" left join offer.offerAccess offeraccess ") + .append(" left join offeraccess.method method ") + .append(" where offer.resource.key=:resourceKey"); + if(identity != null) { + sb.append(" and o.delivery.key=:deliveryKey"); + } + if(method != null) { + sb.append(" and method.type=:methodKey"); + } + + TypedQuery<Order> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Order.class) + .setParameter("resourceKey", resource.getKey()); + if(identity != null) { + query.setParameter("deliveryKey", identity.getKey()); + } + if (method != null) { + query.setParameter("methodKey", method.getKey()); + } + return query.getResultList(); } @@ -452,7 +483,7 @@ public class ACOrderDAO { StringBuilder sb = new StringBuilder(); sb.append("select o from ").append(OrderImpl.class.getName()).append(" o") .append(" left join fetch o.parts parts where o.key=:orderKey"); - + List<Order> orders = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Order.class) .setParameter("orderKey", orderKey) @@ -460,7 +491,7 @@ public class ACOrderDAO { if(orders.isEmpty()) return null; return orders.get(0); } - + public Order loadOrderByNr(String orderNr) { Long orderKey = new Long(orderNr); return loadOrderByKey(orderKey); diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AbstractAccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/model/AbstractAccessMethod.java index 038e93f52ececb0453dece9f1b604325eb470ba1..ec1d9fd909d2063f5a984126319238cf0b859e72 100644 --- a/src/main/java/org/olat/resource/accesscontrol/model/AbstractAccessMethod.java +++ b/src/main/java/org/olat/resource/accesscontrol/model/AbstractAccessMethod.java @@ -42,25 +42,25 @@ import org.olat.core.id.ModifiedInfo; import org.olat.core.id.Persistable; /** - * + * * Description:<br> * The root object for access method. The concret implementation must inherent for this - * and use the subclass of hibernate to map the object on the DB. - * + * and use the subclass of hibernate to map the object on the DB. + * * <P> * Initial Date: 18 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -@Entity -@Table(name="o_ac_method") -@Inheritance(strategy=InheritanceType.SINGLE_TABLE) -@DiscriminatorColumn(name="access_method", discriminatorType=DiscriminatorType.STRING) -@DiscriminatorValue(value="abstract") +@Entity +@Table(name="o_ac_method") +@Inheritance(strategy=InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name="access_method", discriminatorType=DiscriminatorType.STRING) +@DiscriminatorValue(value="abstract") public abstract class AbstractAccessMethod implements Persistable, AccessMethod, ModifiedInfo { private static final long serialVersionUID = 5656490927761461774L; - + @Id @GeneratedValue(generator = "system-uuid") @GenericGenerator(name = "system-uuid", strategy = "enhanced-sequence", parameters={ @@ -75,7 +75,7 @@ public abstract class AbstractAccessMethod implements Persistable, AccessMethod, private Long key; @Version private int version = 0; - + @Temporal(TemporalType.TIMESTAMP) @Column(name="creationdate", nullable=false, insertable=true, updatable=false) private Date creationDate; @@ -94,11 +94,11 @@ public abstract class AbstractAccessMethod implements Persistable, AccessMethod, @Temporal(TemporalType.TIMESTAMP) @Column(name="validto", nullable=true, insertable=true, updatable=true) private Date validTo; - + public AbstractAccessMethod() { // } - + @Override public Long getKey() { return key; @@ -108,6 +108,7 @@ public abstract class AbstractAccessMethod implements Persistable, AccessMethod, this.key = key; } + @Override public Date getCreationDate() { return creationDate; } @@ -124,7 +125,7 @@ public abstract class AbstractAccessMethod implements Persistable, AccessMethod, public void setValid(boolean valid) { this.valid = valid; } - + @Override public boolean isEnabled() { return enabled; @@ -134,9 +135,6 @@ public abstract class AbstractAccessMethod implements Persistable, AccessMethod, this.enabled = enabled; } - @Override - public abstract String getType(); - @Override public Date getLastModified() { return lastModified; @@ -162,12 +160,12 @@ public abstract class AbstractAccessMethod implements Persistable, AccessMethod, public void setValidTo(Date validTo) { this.validTo = validTo; } - + @Override public int hashCode() { return getKey() == null ? 34688 : getKey().hashCode(); } - + @Override public boolean equals(Object obj) { if(this == obj) { diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.hbm.xml b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.hbm.xml index d825b051bd122de22c78fd8b52303aa05ac2fc0b..c53976e1df9414ee54099fe7a6977265ce6f3d1b 100644 --- a/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.hbm.xml +++ b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.hbm.xml @@ -1,7 +1,7 @@ <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping default-lazy="false"> - + <class name="org.olat.resource.accesscontrol.model.AbstractAccessMethod" table="o_ac_method"> <id name="key" column="method_id" type="long" unsaved-value="null"> <generator class="enhanced-sequence"> @@ -14,7 +14,7 @@ </generator> </id> <discriminator column="access_method" type="string"/> - + <version name="version" access="field" column="version" type="int"/> <property name="lastModified" column="lastmodified" type="timestamp" /> <property name="creationDate" column="creationdate" type="timestamp" /> @@ -23,14 +23,18 @@ <property name="validFrom" column="validfrom" type="timestamp" /> <property name="validTo" column="validto" type="timestamp" /> - + <subclass name="org.olat.resource.accesscontrol.model.TokenAccessMethod" discriminator-value="token.method"> - + + </subclass> + + <subclass name="org.olat.shibboleth.manager.ShibbolethAutoAccessMethod" discriminator-value="auto.shib.method"> + </subclass> - + <subclass name="org.olat.resource.accesscontrol.model.FreeAccessMethod" discriminator-value="free.method"> - + </subclass> </class> - + </hibernate-mapping> diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.java index 18c2cd8b750b48014d13db9e04ceec04faf880a9..ad18d440161db6e6fc1f69e3dd74304d8a4f5209 100644 --- a/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.java +++ b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.java @@ -24,29 +24,31 @@ import java.util.Date; /** - * + * * Description:<br> * Interface for payment method - * + * * <P> * Initial Date: 18 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public interface AccessMethod { - + public Long getKey(); - + public Date getCreationDate(); - + public boolean isValid(); - + public boolean isEnabled(); - + public String getType(); - + public boolean isNeedUserInteraction(); - + public boolean isPaymentMethod(); public String getMethodCssClass(); + + public boolean isVisibleInGui(); } diff --git a/src/main/java/org/olat/resource/accesscontrol/model/FreeAccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/model/FreeAccessMethod.java index e26bf618927e5fb5eecd26f3d6fb1b7bffd75435..2823e12ea3c3547d5806e74567fc702603c594ba 100644 --- a/src/main/java/org/olat/resource/accesscontrol/model/FreeAccessMethod.java +++ b/src/main/java/org/olat/resource/accesscontrol/model/FreeAccessMethod.java @@ -27,16 +27,16 @@ import org.olat.resource.accesscontrol.provider.free.FreeAccessHandler; /** - * + * * Description:<br> * This a "static" payment method. There is only one instance. - * + * * <P> * Initial Date: 27 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Entity(name="acfreemethod") -@DiscriminatorValue(value="free.method") +@DiscriminatorValue(value="free.method") public class FreeAccessMethod extends AbstractAccessMethod { private static final long serialVersionUID = -6028245920419886453L; @@ -55,9 +55,14 @@ public class FreeAccessMethod extends AbstractAccessMethod { public boolean isNeedUserInteraction() { return false; } - + @Override public boolean isPaymentMethod() { return false; } + + @Override + public boolean isVisibleInGui() { + return true; + } } diff --git a/src/main/java/org/olat/resource/accesscontrol/model/SystemACSecurityCallback.java b/src/main/java/org/olat/resource/accesscontrol/model/SystemACSecurityCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..743b9f590761671f13bd402b3d27cadcce884ff2 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/model/SystemACSecurityCallback.java @@ -0,0 +1,36 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.model; + +/** + * Access only by the System. No user can use in the GUI. + * + * Initial date: 11.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class SystemACSecurityCallback implements AccessMethodSecurityCallback { + + @Override + public boolean canUse() { + return false; + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/model/TokenAccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/model/TokenAccessMethod.java index af984686ec74eec157b5a219c4d525350c6a876f..74fcfcd99254de566a8f073e2017b7da2529c349 100644 --- a/src/main/java/org/olat/resource/accesscontrol/model/TokenAccessMethod.java +++ b/src/main/java/org/olat/resource/accesscontrol/model/TokenAccessMethod.java @@ -27,16 +27,16 @@ import org.olat.resource.accesscontrol.provider.token.TokenAccessHandler; /** - * + * * Description:<br> * This a "static" payment method. There is only one instance. - * + * * <P> * Initial Date: 18 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Entity(name="actokenmethod") -@DiscriminatorValue(value="token.method") +@DiscriminatorValue(value="token.method") public class TokenAccessMethod extends AbstractAccessMethod { private static final long serialVersionUID = -8066110993424490600L; @@ -44,20 +44,25 @@ public class TokenAccessMethod extends AbstractAccessMethod { @Override public String getType() { return TokenAccessHandler.METHOD_TYPE; - } - + } + @Override public String getMethodCssClass() { return TokenAccessHandler.METHOD_CSS_CLASS; } - + @Override public boolean isNeedUserInteraction() { return true; } - + @Override public boolean isPaymentMethod() { return false; } + + @Override + public boolean isVisibleInGui() { + return true; + } } diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/AdvanceOrder.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/AdvanceOrder.java new file mode 100644 index 0000000000000000000000000000000000000000..0756c1b6e18119b4aaf0fa9cb13de64531201fcb --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/AdvanceOrder.java @@ -0,0 +1,58 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto; + +import java.util.Date; + +import org.olat.core.id.CreateInfo; +import org.olat.core.id.Identity; +import org.olat.core.id.ModifiedInfo; +import org.olat.resource.accesscontrol.model.AccessMethod; + +/** + * + * Initial date: 14.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface AdvanceOrder extends CreateInfo, ModifiedInfo { + + public enum Status { + PENDING, + DONE} + + public Long getKey(); + + public AccessMethod getMethod(); + + public IdentifierKey getIdentifierKey(); + + public String getIdentifierValue(); + + public Status getStatus(); + + public void setStatus(Status status); + + public Date getStatusModified(); + + public void setStatusModified(Date modified); + + public Identity getIdentity(); +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/AdvanceOrderInput.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/AdvanceOrderInput.java new file mode 100644 index 0000000000000000000000000000000000000000..040eed76580bf41f38294c38e55ba536128936c0 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/AdvanceOrderInput.java @@ -0,0 +1,60 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto; + +import java.util.Set; + +import org.olat.core.id.Identity; +import org.olat.resource.accesscontrol.provider.auto.model.AutoAccessMethod; + +/** + * Parameter Object to bundle the parameters to create the advance orders. + * + * Initial date: 17.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface AdvanceOrderInput { + + /** + * The class of the AccessMethod to choose. + */ + public Class<? extends AutoAccessMethod> getMethodClass(); + + /** + * The identity for which the advance orders are created. + */ + public Identity getIdentity(); + + /** + * The keys of the course attributes to search for. + */ + public Set<IdentifierKey> getKeys(); + + /** + * The raw values to search. + */ + public String getRawValues(); + + /** + * Type of the splitter to split the raw values in a set of single values. + */ + public String getSplitterType(); +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/AutoAccessHandler.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/AutoAccessHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..8b03cd1520475f6143aaa37d216eb1d939130642 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/AutoAccessHandler.java @@ -0,0 +1,100 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto; + +import java.util.Collections; +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.resource.accesscontrol.OfferAccess; +import org.olat.resource.accesscontrol.Order; +import org.olat.resource.accesscontrol.OrderPart; +import org.olat.resource.accesscontrol.method.AccessMethodHandler; +import org.olat.resource.accesscontrol.model.AccessMethod; +import org.olat.resource.accesscontrol.model.AccessMethodSecurityCallback; +import org.olat.resource.accesscontrol.model.PSPTransaction; +import org.olat.resource.accesscontrol.model.SystemACSecurityCallback; +import org.olat.resource.accesscontrol.ui.AbstractConfigurationMethodController; +import org.olat.resource.accesscontrol.ui.FormController; + +/** + * AccessMethodHander for the automatic booking module. This module allows to + * save proposed assignments of users to a course by a third party service. The + * module effectively assigns the user to a course if the course for the saved + * key is available. + * + * Initial date: 11.08.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public abstract class AutoAccessHandler implements AccessMethodHandler { + + private static final SystemACSecurityCallback SYSTEM_AC_SECURITY_CALLBACK = new SystemACSecurityCallback(); + + @Override + public boolean isPaymentMethod() { + return false; + } + + @Override + public AccessMethodSecurityCallback getSecurityCallback(Identity identity, Roles roles) { + return SYSTEM_AC_SECURITY_CALLBACK; + } + + @Override + public FormController createAccessController(UserRequest ureq, WindowControl wControl, OfferAccess link, + Form form) { + return null; + } + + @Override + public AbstractConfigurationMethodController createConfigurationController(UserRequest ureq, WindowControl wControl, + OfferAccess link) { + return null; + } + + @Override + public AbstractConfigurationMethodController editConfigurationController(UserRequest ureq, WindowControl wControl, + OfferAccess link) { + return null; + } + + @Override + public FormController createTransactionDetailsController(UserRequest ureq, WindowControl wControl, Order order, + OrderPart part, AccessMethod method, Form form) { + return null; + } + + @Override + public boolean checkArgument(OfferAccess link, Object argument) { + return true; + } + + @Override + public List<PSPTransaction> getPSPTransactions(List<Order> orders) { + return Collections.emptyList(); + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/AutoAccessManager.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/AutoAccessManager.java new file mode 100644 index 0000000000000000000000000000000000000000..11e0f2ea5df994f4cc276c3f36d0d2a8884ba021 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/AutoAccessManager.java @@ -0,0 +1,101 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto; + +import java.util.Collection; + +import org.olat.core.id.Identity; +import org.olat.repository.RepositoryEntry; + +/** + * Manager for the automatic access control provider. This provider allows to + * save proposed assignments of users to a course by a third party service like + * Shibboleth, REST, LDAP etc. The module effectively assigns the user to a + * course if the course for the saved key is available. + * + * Initial date: 14.08.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface AutoAccessManager { + + /** + * Create a pending advance order for the combination of every identifier + * key and every single identifier value in the input. You can specify an + * parser to split the raw input value in singles values. + * + * @param input + */ + public void createAdvanceOrders(AdvanceOrderInput input); + + /** + * Load all pending advance orders of an identity. + * + * @param identity + */ + public Collection<AdvanceOrder> loadPendingAdvanceOrders(Identity identity); + + /** + * Load all pending advance orders for a ReposiotyEntry. + * + * @param resourse + */ + public Collection<AdvanceOrder> loadPendingAdvanceOrders(RepositoryEntry entry); + + /** + * Delete an advance order. + * + * @param advanceOrder + */ + public void deleteAdvanceOrder(AdvanceOrder advanceOrder); + + /** + * Delete all advance order of a user. + * + * @param identity + */ + public void deleteAdvanceOrders(Identity identity); + + /** + * Load all pending advance orders for the identity and try to grant access. + * + * @param identity + */ + public void grantAccessToCourse(Identity identity); + + /** + * Load all pending advance orders for the RepositoryEntry and try to grant access. + * + * @param repositoryEntry + */ + public void grantAccess(RepositoryEntry entry); + + /** + * Try to grant access to a resource for the identity in the pending advance + * orders. If the resource is found and the access is granted, the status of the + * advance order is set to done. If no resource for the identifier key and + * value is found, the advance order remains pending. + * + * @param advanceOrders + */ + public void grantAccess(Collection<AdvanceOrder> advancedOrders); + +} \ No newline at end of file diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/IdentifierKey.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/IdentifierKey.java new file mode 100644 index 0000000000000000000000000000000000000000..30581a3b45178dce88ccad74e4519ba821fa4cbf --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/IdentifierKey.java @@ -0,0 +1,34 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto; + +/** + * Options of course key which can be used to get the course by an advance order. + * + * Initial date: 14.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public enum IdentifierKey { + + internalId, + externalId, + externalRef +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAO.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAO.java new file mode 100644 index 0000000000000000000000000000000000000000..d8549833abd9b81c0e9e20371fde811df7d12c3a --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAO.java @@ -0,0 +1,159 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import javax.persistence.TypedQuery; + +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.core.util.StringHelper; +import org.olat.resource.accesscontrol.model.AccessMethod; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder.Status; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.olat.resource.accesscontrol.provider.auto.model.AdvanceOrderImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 14.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Service +class AdvanceOrderDAO { + + @Autowired + private DB dbInstance; + + AdvanceOrder create(Identity identity, IdentifierKey key, String identifierValue, AccessMethod method) { + AdvanceOrderImpl advanceOrder = new AdvanceOrderImpl(); + Date creationDate = new Date(); + advanceOrder.setCreationDate(creationDate); + advanceOrder.setLastModified(creationDate); + advanceOrder.setIdentity(identity); + advanceOrder.setIdentifierKey(key); + advanceOrder.setIdentifierValue(identifierValue); + advanceOrder.setStatus(Status.PENDING); + advanceOrder.setStatusModified(creationDate); + advanceOrder.setMethod(method); + return advanceOrder; + } + + boolean exists(Identity identity, IdentifierKey identifierKey, String identifierValue, AccessMethod method) { + Long numberOfAdvanceOrder = dbInstance.getCurrentEntityManager() + .createNamedQuery("exists", Long.class) + .setParameter("identityKey", identity.getKey()) + .setParameter("identifierKey", identifierKey) + .setParameter("identifierValue", identifierValue) + .setParameter("methodKey", method.getKey()) + .getSingleResult(); + return numberOfAdvanceOrder != null && numberOfAdvanceOrder > 0; + } + + Collection<AdvanceOrder> loadPendingAdvanceOrders(Identity identity) { + if (identity == null) return new ArrayList<>(0); + + StringBuilder sb = new StringBuilder(); + sb.append("select advanceOrder from advanceOrder advanceOrder") + .append(" where advanceOrder.identity.key=:identityKey") + .append(" and advanceOrder.status=:status"); + + List<AdvanceOrder> advanceOrder = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), AdvanceOrder.class) + .setParameter("identityKey", identity.getKey()) + .setParameter("status", Status.PENDING) + .getResultList(); + + return advanceOrder; + } + + Collection<AdvanceOrder> loadPendingAdvanceOrders(Map<IdentifierKey, String> identifiers) { + if (identifiers == null || identifiers.isEmpty()) return new ArrayList<>(); + + StringBuilder sb = new StringBuilder(); + sb.append("select advanceOrder from advanceOrder advanceOrder") + .append(" where advanceOrder.status=:status") + .append(" and ((1 = 2)"); + + for (Map.Entry<IdentifierKey, String> entry : identifiers.entrySet()) { + if (entry.getKey() != null && StringHelper.containsNonWhitespace(entry.getValue())) { + sb.append(" or (advanceOrder.identifierKey=:").append(entry.getKey()); + sb.append(" and advanceOrder.identifierValue=:").append(entry.getKey()).append(entry.getKey()).append(")"); + } + } + sb.append(")"); + + TypedQuery<AdvanceOrder> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), AdvanceOrder.class) + .setParameter("status", Status.PENDING); + + for (Map.Entry<IdentifierKey, String> entry : identifiers.entrySet()) { + if (entry.getKey() != null && StringHelper.containsNonWhitespace(entry.getValue())) { + query.setParameter(entry.getKey().toString(), entry.getKey()); + query.setParameter(entry.getKey().toString().concat(entry.getKey().toString()), entry.getValue()); + } + } + + return query.getResultList(); + } + + public void deleteAdvanceOrder(AdvanceOrder advanceOrder) { + dbInstance.getCurrentEntityManager() + .createNamedQuery("deleteByKey") + .setParameter("key", advanceOrder.getKey()) + .executeUpdate(); + } + + void deleteAdvanceOrders(Identity identity) { + dbInstance.getCurrentEntityManager() + .createNamedQuery("deleteByIdentity") + .setParameter("identityKey", identity.getKey()) + .executeUpdate(); + } + + AdvanceOrder save(AdvanceOrder advanceOrder) { + if(advanceOrder.getKey() == null) { + dbInstance.getCurrentEntityManager().persist(advanceOrder); + } else { + advanceOrder.setLastModified(new Date()); + advanceOrder = dbInstance.getCurrentEntityManager().merge(advanceOrder); + } + return advanceOrder; + } + + AdvanceOrder accomplishAndSave(AdvanceOrder advanceOrder) { + if (advanceOrder == null) return advanceOrder; + + advanceOrder.setStatus(Status.DONE); + advanceOrder.setStatusModified(new Date()); + advanceOrder = save(advanceOrder); + + return advanceOrder; + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a96e49e9c387d23cbefbf93ac4f93b12046a3253 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java @@ -0,0 +1,222 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +import org.olat.basesecurity.GroupRoles; +import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.manager.RepositoryEntryRelationDAO; +import org.olat.resource.OLATResource; +import org.olat.resource.accesscontrol.ACService; +import org.olat.resource.accesscontrol.AccessControlModule; +import org.olat.resource.accesscontrol.Offer; +import org.olat.resource.accesscontrol.OfferAccess; +import org.olat.resource.accesscontrol.model.AccessMethod; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder.Status; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrderInput; +import org.olat.resource.accesscontrol.provider.auto.AutoAccessManager; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.olat.resource.accesscontrol.provider.auto.model.AutoAccessMethod; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + + +/** + * + * Initial date: 14.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Service +public class AutoAccessManagerImpl implements AutoAccessManager { + + private static final OLog log = Tracing.createLoggerFor(AutoAccessManagerImpl.class); + + @Autowired + private IdentifierHandler identifierHandler; + @Autowired + private SplitterFactory splitterFactory; + @Autowired + private InputValidator inputValidator; + @Autowired + private AdvanceOrderDAO advanceOrderDAO; + @Autowired + private AccessControlModule acModule; + @Autowired + private ACService acService; + @Autowired + private RepositoryEntryRelationDAO repositoryEntryRelationDao; + + @Override + public void createAdvanceOrders(AdvanceOrderInput input) { + if (!inputValidator.isValid(input)) return; + + IdentifierValueSplitter splitter = splitterFactory.getSplitter(input.getSplitterType()); + Collection<String> values = splitter.split(input.getRawValues()); + for (IdentifierKey key : input.getKeys()) { + for (String value : values) { + createAndPersistAdvanceOrderIfNotExist(input.getIdentity(), key, value, input.getMethodClass()); + } + } + } + + private void createAndPersistAdvanceOrderIfNotExist(Identity identity, IdentifierKey key, String value, Class<? extends AutoAccessMethod> type) { + List<AccessMethod> methods = acService.getAvailableMethodsByType(type); + AccessMethod method = methods.get(0); + if (doesNotExist(identity, key, value, method)) { + AdvanceOrder advanceOrder = advanceOrderDAO.create(identity, key, value, method); + advanceOrderDAO.save(advanceOrder); + } + } + + private boolean doesNotExist(Identity identity, IdentifierKey key, String value, AccessMethod method) { + return !advanceOrderDAO.exists(identity, key, value, method); + } + + @Override + public Collection<AdvanceOrder> loadPendingAdvanceOrders(Identity identity) { + return advanceOrderDAO.loadPendingAdvanceOrders(identity); + } + + @Override + public Collection<AdvanceOrder> loadPendingAdvanceOrders(RepositoryEntry entry) { + if (entry == null) return new ArrayList<>(); + + Map<IdentifierKey, String> searchValues = new EnumMap<>(IdentifierKey.class); + for (IdentifierKey key: IdentifierKey.values()) { + String value = identifierHandler.getRepositoryEntryValue(key, entry); + searchValues.put(key, value); + } + + return advanceOrderDAO.loadPendingAdvanceOrders(searchValues); + } + + @Override + public void deleteAdvanceOrder(AdvanceOrder advanceOrder) { + advanceOrderDAO.deleteAdvanceOrder(advanceOrder); + } + + @Override + public void deleteAdvanceOrders(Identity identity) { + advanceOrderDAO.deleteAdvanceOrders(identity); + } + + @Override + public void grantAccessToCourse(Identity identity) { + Collection<AdvanceOrder> pendingAdvanceOrders = loadPendingAdvanceOrders(identity); + grantAccess(pendingAdvanceOrders); + } + + @Override + public void grantAccess(RepositoryEntry entry) { + Collection<AdvanceOrder> pendingAdvanceOrders = loadPendingAdvanceOrders(entry); + grantAccess(pendingAdvanceOrders); + } + + @Override + public void grantAccess(Collection<AdvanceOrder> advanceOrders) { + if (!acModule.isAutoEnabled()) return; + + for (AdvanceOrder advanceOrder : advanceOrders) { + try { + tryToGrantAccess(advanceOrder); + } catch (Exception e) { + log.error("Advance order can not be booked.", e); + } + } + } + + private void tryToGrantAccess(AdvanceOrder advanceOrder) { + if (isAdvanceOrderAccomplished(advanceOrder)) + return; + + List<RepositoryEntry> entries = findRepositoryEntries(advanceOrder); + if (!entries.isEmpty()) { + for (RepositoryEntry entry: entries) { + grantAccessIfHasNoAccess(advanceOrder, entry); + } + advanceOrderDAO.accomplishAndSave(advanceOrder); + } + } + + private void grantAccessIfHasNoAccess(AdvanceOrder advanceOrder, RepositoryEntry entry) { + if (hasNoAccess(advanceOrder, entry)) { + OLATResource resource = entry.getOlatResource(); + OfferAccess offerAccess = getOrCreateOfferAccess(resource, entry, advanceOrder.getMethod()); + makeOrder(offerAccess, advanceOrder); + } + } + + private boolean isAdvanceOrderAccomplished(AdvanceOrder advanceOrder) { + return !Status.PENDING.equals(advanceOrder.getStatus()); + } + + private List<RepositoryEntry> findRepositoryEntries(AdvanceOrder advanceOrder) { + IdentifierKey identifierKey = advanceOrder.getIdentifierKey(); + String identifierValue = advanceOrder.getIdentifierValue(); + return identifierHandler.findRepositoryEntries(identifierKey, identifierValue); + } + + private boolean hasNoAccess(AdvanceOrder advanceOrder, RepositoryEntry entry) { + Identity identity = advanceOrder.getIdentity(); + boolean hasNoAccess = true; + if (repositoryEntryRelationDao.hasRole(identity, entry, GroupRoles.participant.name())) { + hasNoAccess = false; + } + return hasNoAccess; + } + + private OfferAccess getOrCreateOfferAccess(OLATResource resource, RepositoryEntry entry, AccessMethod method) { + OfferAccess offerAccess; + List<OfferAccess> offerAccesses = acService.getValidOfferAccess(resource, method); + if (offerAccesses.isEmpty()) { + offerAccess = createOfferAccess(resource, entry, method); + } else { + offerAccess = offerAccesses.get(0); + } + return offerAccess; + } + + private OfferAccess createOfferAccess(OLATResource resource, RepositoryEntry entry, AccessMethod method) { + OfferAccess offerAccess; + String displayName = entry.getDisplayname(); + Offer offer = acService.createOffer(resource, displayName); + offer.setAutoBooking(true); + offerAccess = acService.createOfferAccess(offer, method); + acService.save(offer); + acService.saveOfferAccess(offerAccess); + return offerAccess; + } + + private void makeOrder(OfferAccess offerAccess, AdvanceOrder advanceOrder) { + Identity identity = advanceOrder.getIdentity(); + acService.accessResource(identity, offerAccess, null); + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalIdHandler.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalIdHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..8f5202ecb204a5c429a40f279de478b06068aba5 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalIdHandler.java @@ -0,0 +1,66 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.ArrayList; +import java.util.List; + +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryService; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + * Initial date: 15.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +class ExternalIdHandler implements IdentifierKeyHandler { + + @Autowired + private RepositoryService repositoryService; + + @Override + public IdentifierKey getIdentifierKey() { + return IdentifierKey.externalId; + } + + @Override + public List<RepositoryEntry> find(String value) { + List<RepositoryEntry> entries = new ArrayList<>(); + + try { + entries = repositoryService.loadRepositoryEntriesByExternalId(value); + } catch (Exception e) { + // nothing to add + } + + return entries; + } + + @Override + public String getRepositoryEntryValue(RepositoryEntry entry) { + return entry.getExternalId(); + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalRefHandler.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalRefHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..77d09bbba247cd1cb179952f768a2fe3962f98de --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalRefHandler.java @@ -0,0 +1,66 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.ArrayList; +import java.util.List; + +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryService; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + * Initial date: 15.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +class ExternalRefHandler implements IdentifierKeyHandler { + + @Autowired + private RepositoryService repositoryService; + + @Override + public IdentifierKey getIdentifierKey() { + return IdentifierKey.externalRef; + } + + @Override + public List<RepositoryEntry> find(String value) { + List<RepositoryEntry> entries = new ArrayList<>(); + + try { + entries = repositoryService.loadRepositoryEntriesByExternalRef(value); + } catch (Exception e) { + // nothing to add + } + + return entries; + } + + @Override + public String getRepositoryEntryValue(RepositoryEntry entry) { + return entry.getExternalRef(); + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierHandler.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..9dda0ed2271e8e274544ac9ba52f3c2e15f01864 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierHandler.java @@ -0,0 +1,92 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.annotation.PostConstruct; + +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.repository.RepositoryEntry; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + * Initial date: 15.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +class IdentifierHandler { + + private static final OLog log = Tracing.createLoggerFor(IdentifierHandler.class); + + @Autowired + private Collection<IdentifierKeyHandler> loadedHandlers; + + private Map<IdentifierKey, IdentifierKeyHandler> handlers = new HashMap<>(); + + @PostConstruct + void initHandlerCache() { + for(IdentifierKeyHandler handler : loadedHandlers) { + handlers.put(handler.getIdentifierKey(), handler); + } + } + + /** + * Finds the RepositoryEntries for a given identifier key and value. + * It is a explicit requirement to return all entries. Maybe in other + * setups it would be appropriate to only return one entry because + * we are searching by an identifier. + * + * @param key + * @param value + * @returns the course or null if not found or too many found + */ + List<RepositoryEntry> findRepositoryEntries(IdentifierKey key, String value) { + List<RepositoryEntry> entries = handlers.get(key).find(value); + if (entries.size() > 1) { + String keys = entries.stream() + .map(re -> re.getSoftkey()) + .collect(Collectors.joining(", ")); + log.debug("Found more then one RepositotyEntry for " + key + "=" + value + ". Keys: " + keys); + } + return entries; + } + + /** + * Takes a RepostoryEntry and returns the value for a given IdenifierKey + * + * @param key + * @param entry + * @return + */ + String getRepositoryEntryValue(IdentifierKey key, RepositoryEntry entry) { + return handlers.get(key).getRepositoryEntryValue(entry); + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierKeyHandler.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierKeyHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..6c256fdcfb77d629da71412a8e2a6a2ce4845959 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierKeyHandler.java @@ -0,0 +1,57 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.List; + +import org.olat.repository.RepositoryEntry; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; + +/** + * Strategy to handle the IdentifierKeys + * + * Initial date: 14.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +interface IdentifierKeyHandler { + + /** + * Specifies for which identifier the handler can be used. + */ + public IdentifierKey getIdentifierKey(); + + /** + * Find the RepositoryEntries by a given value. + * + * @param value the value to search for + * @return the RepositoryEntries found for the given value + */ + public List<RepositoryEntry> find(String value); + + /** + * Finds the appropriate Value in the RepositoryEntry. + * + * @param entry + * @return + */ + public String getRepositoryEntryValue(RepositoryEntry entry); + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierValueSplitter.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierValueSplitter.java new file mode 100644 index 0000000000000000000000000000000000000000..29009b3d4f1dd02a9fcc6cf4a5be276643b7a2de --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierValueSplitter.java @@ -0,0 +1,36 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.Collection; + +/** + * Split the raw identifier value in single values. + * + * Initial date: 23.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +interface IdentifierValueSplitter { + + public String getType(); + + public Collection<String> split(String rawValue); +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/InputValidator.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/InputValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..4e85e307fcd07374324e90daf2e7c28889a86f10 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/InputValidator.java @@ -0,0 +1,58 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrderInput; +import org.springframework.stereotype.Component; + +/** + * Helper to validate the values of the AdvanceOrderInput. + * + * Initial date: 17.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +class InputValidator { + + boolean isValid(AdvanceOrderInput input) { + boolean isValid = true; + + if (input == null) { + isValid &= false; + } else { + isValid &= notNull(input.getIdentity()); + isValid &= notNull(input.getMethodClass()); + isValid &= notNull(input.getRawValues()); + + if (input.getKeys() == null) { + isValid &= false; + } else { + isValid &= input.getKeys().isEmpty() ? false: true; + } + } + + return isValid; + } + + private boolean notNull(Object input) { + return input == null? false: true; + } +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/InternalIdHandler.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/InternalIdHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..9a0482ff67f3edb48e93f16f18aa323161fb8e49 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/InternalIdHandler.java @@ -0,0 +1,69 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.ArrayList; +import java.util.List; + +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryService; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Initial date: 15.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +class InternalIdHandler implements IdentifierKeyHandler { + + @Autowired + private RepositoryService repositoryService; + + @Override + public IdentifierKey getIdentifierKey() { + return IdentifierKey.internalId; + } + + @Override + public List<RepositoryEntry> find(String value) { + List<RepositoryEntry> entries = new ArrayList<>(); + + try { + Long repositoryEntryKey = Long.parseLong(value); + RepositoryEntry entry = repositoryService.loadByKey(repositoryEntryKey); + if (entry != null) { + entries.add(entry); + } + } catch (Exception e) { + // nothing to add + } + + return entries; + } + + @Override + public String getRepositoryEntryValue(RepositoryEntry entry) { + return Long.toString(entry.getKey()); + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/SemicolonSplitter.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/SemicolonSplitter.java new file mode 100644 index 0000000000000000000000000000000000000000..67e7e2f24053c6d3325f489141e90b196e6abda9 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/SemicolonSplitter.java @@ -0,0 +1,52 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import org.springframework.stereotype.Component; + + +/** + * + * Initial date: 23.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +public class SemicolonSplitter implements IdentifierValueSplitter { + + public static final String TYPE = "Semicolon"; + + @Override + public String getType() { + return TYPE; + } + + @Override + public Collection<String> split(String rawValue) { + if (rawValue == null) return new ArrayList<>(); + + return Arrays.asList(rawValue.split(";")); + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/SplitterFactory.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/SplitterFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..21127752c0623c4b4ecbce11137e1ce9851d32ea --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/SplitterFactory.java @@ -0,0 +1,59 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + * Initial date: 23.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +public class SplitterFactory { + + @Autowired + private List<IdentifierValueSplitter> services; + + private static final Map<String, IdentifierValueSplitter> cache = new HashMap<>(); + + @PostConstruct + void initIdentifierValueSplitterCache() { + for(IdentifierValueSplitter service : services) { + cache.put(service.getType(), service); + } + } + + public IdentifierValueSplitter getSplitter(String type) { + IdentifierValueSplitter splitter = cache.get(type); + if (splitter == null) { + splitter = cache.get(SemicolonSplitter.TYPE); + } + return splitter; + } +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/model/AdvanceOrderImpl.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/model/AdvanceOrderImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a5638ba2902fdc2e3fa33556dde37e2c57226ba4 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/model/AdvanceOrderImpl.java @@ -0,0 +1,215 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.olat.basesecurity.IdentityImpl; +import org.olat.core.id.Identity; +import org.olat.core.id.Persistable; +import org.olat.resource.accesscontrol.model.AbstractAccessMethod; +import org.olat.resource.accesscontrol.model.AccessMethod; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; + +/** + * + * Initial date: 14.08.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Entity(name="advanceOrder") +@Table(name="o_ac_auto_advance_order") +@NamedQueries({ + @NamedQuery(name="exists", query= + "select count(*) " + + "from advanceOrder ao " + + "where ao.identity.key =:identityKey " + + "and ao.identifierKey =:identifierKey " + + "and ao.identifierValue =:identifierValue " + + "and ao.method.key =:methodKey"), + @NamedQuery(name="deleteByKey", query = + "delete from advanceOrder ao where ao.key=:key"), + @NamedQuery(name="deleteByIdentity", query = + "delete from advanceOrder ao" + + " where ao.identity.key=:identityKey") +}) +public class AdvanceOrderImpl implements Persistable, AdvanceOrder { + + private static final long serialVersionUID = -536425559285612562L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="lastmodified", nullable=false, insertable=true, updatable=true) + private Date lastModified; + + @Enumerated(EnumType.STRING) + @Column(name="a_identifier_key", nullable=false, insertable=true, updatable=false) + private IdentifierKey identifierKey; + @Column(name="a_identifier_value", nullable=false, insertable=true, updatable=false) + private String identifierValue; + + @Enumerated(EnumType.STRING) + @Column(name="a_status", nullable=false, insertable=true, updatable=true) + private Status status; + @Column(name="a_status_modified", nullable=false, insertable=true, updatable=true) + private Date statusModified; + + @ManyToOne(targetEntity=IdentityImpl.class, fetch=FetchType.LAZY, optional=false) + @JoinColumn(name="fk_identity", nullable=false, insertable=true, updatable=false) + private Identity identity; + + @ManyToOne(targetEntity=AbstractAccessMethod.class,fetch=FetchType.LAZY,optional=false) + @JoinColumn(name="fk_method", nullable=false, insertable=true, updatable=false) + private AccessMethod method; + + @Override + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public Date getLastModified() { + return lastModified; + } + + @Override + public void setLastModified(Date date) { + lastModified = date; + } + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + @Override + public AccessMethod getMethod() { + return method; + } + + public void setMethod(AccessMethod method) { + this.method = method; + } + + @Override + public IdentifierKey getIdentifierKey() { + return identifierKey; + } + + public void setIdentifierKey(IdentifierKey key) { + this.identifierKey = key; + } + + @Override + public String getIdentifierValue() { + return identifierValue; + } + + public void setIdentifierValue(String identifierValue) { + this.identifierValue = identifierValue; + } + + @Override + public Status getStatus() { + return status; + } + + @Override + public void setStatus(Status status) { + this.status = status; + } + + @Override + public Date getStatusModified() { + return statusModified; + } + + @Override + public void setStatusModified(Date statusModified) { + this.statusModified = statusModified; + } + + @Override + public Identity getIdentity() { + return identity; + } + + public void setIdentity(Identity identity) { + this.identity = identity; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((identifierKey == null) ? 0 : identifierKey.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } else if(obj instanceof AdvanceOrderImpl) { + AdvanceOrderImpl other = (AdvanceOrderImpl)obj; + return getKey() != null && getKey().equals(other.getKey()); + } + return false; + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/model/AutoAccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/model/AutoAccessMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..252d4ce401324396bda4acdfc65c321d58689420 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/model/AutoAccessMethod.java @@ -0,0 +1,54 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.model; + +import org.olat.resource.accesscontrol.model.AbstractAccessMethod; + +/** + * + * Initial date: 11.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public abstract class AutoAccessMethod extends AbstractAccessMethod { + + private static final long serialVersionUID = -3537267568105282400L; + + @Override + public boolean isNeedUserInteraction() { + return false; + } + + @Override + public boolean isPaymentMethod() { + return false; + } + + @Override + public String getMethodCssClass() { + return null; + } + + @Override + public boolean isVisibleInGui() { + return false; + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/AdvanceOrderController.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/AdvanceOrderController.java new file mode 100644 index 0000000000000000000000000000000000000000..c6fea5aaced910fe3a7a69c49f44c59c8da888cb --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/AdvanceOrderController.java @@ -0,0 +1,150 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.ui; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; +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.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.id.Identity; +import org.olat.resource.accesscontrol.AccessControlModule; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder; +import org.olat.resource.accesscontrol.provider.auto.AutoAccessManager; +import org.olat.resource.accesscontrol.provider.auto.ui.AdvanceOrderDataModel.AdvanceOrderCol; +import org.olat.resource.accesscontrol.ui.AccessMethodRenderer; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 08.09.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class AdvanceOrderController extends FormBasicController { + + private static final String CMD_DELETE = "deleteAdvanceOrder"; + + private FlexiTableElement tableEl; + private DialogBoxController confirmDeleteDialogCtrl; + + private AdvanceOrderDataModel dataModel; + private Identity identity; + + @Autowired + private AutoAccessManager autoAccessManager; + @Autowired + private AccessControlModule acModule; + + public AdvanceOrderController(UserRequest ureq, WindowControl wControl, Identity identity) { + super(ureq, wControl, "advance_order_table"); + this.identity = identity; + + initForm(ureq); + loadModel(); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(AdvanceOrderCol.creationDate)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(AdvanceOrderCol.identifierKey)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(AdvanceOrderCol.identifierValue)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(AdvanceOrderCol.method, new AccessMethodRenderer(acModule))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.advanceOrder.delete", translate("delete"), CMD_DELETE)); + + dataModel = new AdvanceOrderDataModel(columnsModel, getLocale()); + tableEl = uifactory.addTableElement(getWindowControl(), "table", dataModel, getTranslator(), formLayout); + tableEl.setEmtpyTableMessageKey("table.advanceOrder.empty"); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if (source == tableEl) { + if (event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent)event; + if (CMD_DELETE.equals(se.getCommand())) { + AdvanceOrderRow row = dataModel.getObject(se.getIndex()); + doConfirmDelete(ureq, row); + } + } + } + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(confirmDeleteDialogCtrl == source) { + doDeleteAdvanceOrderIfConfirmed(event); + removeAsListenerAndDispose(confirmDeleteDialogCtrl); + confirmDeleteDialogCtrl = null; + } + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + @Override + protected void doDispose() { + // + } + + private void doConfirmDelete(UserRequest ureq, AdvanceOrderRow row) { + AdvanceOrder advanceOrder = row.getAdvanceOrder(); + String title = translate("confirm.delete.advanceOrder.title"); + String message = translate("confirm.delete.advanceOrder"); + confirmDeleteDialogCtrl = activateYesNoDialog(ureq, title, message, confirmDeleteDialogCtrl); + confirmDeleteDialogCtrl.setUserObject(advanceOrder); + } + + private void doDeleteAdvanceOrderIfConfirmed(Event event) { + if (DialogBoxUIFactory.isYesEvent(event) || DialogBoxUIFactory.isOkEvent(event)) { + AdvanceOrder advanceOrder = (AdvanceOrder) confirmDeleteDialogCtrl.getUserObject(); + autoAccessManager.deleteAdvanceOrder(advanceOrder); + loadModel(); + } + } + + private void loadModel() { + Collection<AdvanceOrder> advanceOrders = autoAccessManager.loadPendingAdvanceOrders(identity); + List<AdvanceOrderRow> rows = new ArrayList<>(advanceOrders.size()); + for(AdvanceOrder advanceOrder: advanceOrders) { + rows.add(new AdvanceOrderRow(advanceOrder)); + } + dataModel.setObjects(rows); + tableEl.reset(true, true, true); + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/AdvanceOrderDataModel.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/AdvanceOrderDataModel.java new file mode 100644 index 0000000000000000000000000000000000000000..499318cf848c8dd5e804b341c9ec5c891dd06fcf --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/AdvanceOrderDataModel.java @@ -0,0 +1,113 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.ui; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import org.olat.core.commons.persistence.SortKey; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; + + +/** + * + * Initial date: 08.09.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class AdvanceOrderDataModel extends DefaultFlexiTableDataModel<AdvanceOrderRow> + implements SortableFlexiTableDataModel<AdvanceOrderRow> { + + private final Locale locale; + + public AdvanceOrderDataModel(FlexiTableColumnModel columnModel, Locale locale) { + super(columnModel); + this.locale = locale; + } + + @Override + public void sort(SortKey orderBy) { + List<AdvanceOrderRow> rows = new SortableFlexiTableModelDelegate<>(orderBy, this, locale).sort(); + super.setObjects(rows); + } + + @Override + public Object getValueAt(int row, int col) { + AdvanceOrderRow advanceOrder = getObject(row); + return getValueAt(advanceOrder, col); + } + + @Override + public Object getValueAt(AdvanceOrderRow row, int col) { + switch(AdvanceOrderCol.values()[col]) { + case creationDate: + return row.getAdvanceOrder().getCreationDate(); + case identifierKey: + return row.getAdvanceOrder().getIdentifierKey().toString(); + case identifierValue: + return row.getAdvanceOrder().getIdentifierValue(); + case method: + return Arrays.asList(row.getAdvanceOrder().getMethod()); + default: + return row.getAdvanceOrder(); + } + } + + @Override + public DefaultFlexiTableDataModel<AdvanceOrderRow> createCopyWithEmptyList() { + return new AdvanceOrderDataModel(getTableColumnModel(), locale); + } + + public enum AdvanceOrderCol implements FlexiSortableColumnDef { + creationDate("advanceOrder.creationDate", "creationdate"), + identifierKey("advanceOrder.identitfier.key", "a_identitfier_key"), + identifierValue("advanceOrder.identitfier.value", "a_identitfier_value"), + method("advanceOrder.method", "trxMethodIds"); + + private final String i18nKey; + private final String sortKey; + + private AdvanceOrderCol(String i18nKey, String sortKey) { + this.i18nKey = i18nKey; + this.sortKey = sortKey; + } + + @Override + public String i18nHeaderKey() { + return i18nKey; + } + + @Override + public boolean sortable() { + return true; + } + + @Override + public String sortKey() { + return sortKey; + } + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/AdvanceOrderRow.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/AdvanceOrderRow.java new file mode 100644 index 0000000000000000000000000000000000000000..cbedf2468cd89e6ed1a3ae6c4835519ff27cc5cf --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/AdvanceOrderRow.java @@ -0,0 +1,42 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.ui; + +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder; + +/** + * + * Initial date: 08.09.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class AdvanceOrderRow { + + private final AdvanceOrder advanceOrder; + + public AdvanceOrderRow(AdvanceOrder advanceOrder) { + this.advanceOrder = advanceOrder; + } + + public AdvanceOrder getAdvanceOrder() { + return advanceOrder; + } + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/_content/advance_order_table.html b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/_content/advance_order_table.html new file mode 100644 index 0000000000000000000000000000000000000000..bade9402acda206e8171adcb2d85adb1b884ea54 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/_content/advance_order_table.html @@ -0,0 +1 @@ +$r.render("table") \ No newline at end of file diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/_i18n/LocalStrings_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..82a8cb28915f36c60eca9572acb995ffc9bf586e --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/_i18n/LocalStrings_de.properties @@ -0,0 +1,8 @@ +advanceOrder.creationDate=Erstellungsdatum +advanceOrder.identitfier.key=Schl\u00FCssel +advanceOrder.identitfier.value=Wert +advanceOrder.method=Buchungsmethode +confirm.delete.advanceOrder=Wollen Sie diese Vorbestellung wirklich l\u00F6schen? +confirm.delete.advanceOrder.title=Vorbestellung l\u00F6schen +table.advanceOrder.delete=L\u00F6schen +table.advanceOrder.empty=Es sind keine Vorbestelllungen vorhanden. \ No newline at end of file diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/_i18n/LocalStrings_en.properties new file mode 100644 index 0000000000000000000000000000000000000000..078869f0f3d06c8aa49bdc6ae955bcdd777fc81d --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/ui/_i18n/LocalStrings_en.properties @@ -0,0 +1,8 @@ +advanceOrder.creationDate=Creation date +advanceOrder.identitfier.key=Key +advanceOrder.identitfier.value=Value +advanceOrder.method=Booking method +confirm.delete.advanceOrder=Do you really want to delete this advance order? +confirm.delete.advanceOrder.title=Delete advance order +table.advanceOrder.delete=Delete +table.advanceOrder.empty=There are no advance orders at this time to display. \ No newline at end of file diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/free/ui/FreeAccessConfigurationController.java b/src/main/java/org/olat/resource/accesscontrol/provider/free/ui/FreeAccessConfigurationController.java index cfa9daaef48b0dfb344d045f927d15624c0836f5..ad3238f3167fe5dbdacb207d48884d9340a07e9b 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/free/ui/FreeAccessConfigurationController.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/free/ui/FreeAccessConfigurationController.java @@ -76,7 +76,9 @@ public class FreeAccessConfigurationController extends AbstractConfigurationMeth } dateFrom = uifactory.addDateChooser("from_" + link.getKey(), "from", link.getValidFrom(), formLayout); + dateFrom.setHelpText(translate("from.hint")); dateTo = uifactory.addDateChooser("to_" + link.getKey(), "to", link.getValidTo(), formLayout); + dateTo.setHelpText(translate("from.hint")); super.initForm(formLayout, listener, ureq); } diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypal/model/PaypalAccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/provider/paypal/model/PaypalAccessMethod.java index dfd12138117ae860f0bbcb11bbf9eefdf98c4732..4fc2d30954f8b2cc0a92cdfb2cf24e35c94d796a 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypal/model/PaypalAccessMethod.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypal/model/PaypalAccessMethod.java @@ -28,37 +28,42 @@ import org.olat.resource.accesscontrol.provider.paypal.PaypalAccessHandler; /** - * + * * Description:<br> * This a paypal payment method. - * + * * <P> * Initial Date: 18 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Entity(name="acpaypalmethod") -@DiscriminatorValue(value="paypal.method") +@DiscriminatorValue(value="paypal.method") public class PaypalAccessMethod extends AbstractAccessMethod { - + private static final long serialVersionUID = 7682228653442368290L; @Override public String getType() { return PaypalAccessHandler.METHOD_TYPE; - } - + } + @Override public String getMethodCssClass() { return PaypalAccessHandler.METHOD_CSS_CLASS; } - + @Override public boolean isNeedUserInteraction() { return true; } - + @Override public boolean isPaymentMethod() { return true; } + + @Override + public boolean isVisibleInGui() { + return true; + } } diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypal/ui/PaypalAccessConfigurationController.java b/src/main/java/org/olat/resource/accesscontrol/provider/paypal/ui/PaypalAccessConfigurationController.java index 53529642b7e5ff47a9cc6454f798079d7314a58a..3fe1b2a8a1efbcb6029dbe1646828f9473b48412 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypal/ui/PaypalAccessConfigurationController.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypal/ui/PaypalAccessConfigurationController.java @@ -150,7 +150,9 @@ public class PaypalAccessConfigurationController extends AbstractConfigurationMe vatEnabledEl.setEnabled(false); dateFrom = uifactory.addDateChooser("from_" + link.getKey(), "from", link.getValidFrom(), formLayout); + dateFrom.setHelpText(translate("from.hint")); dateTo = uifactory.addDateChooser("to_" + link.getKey(), "to", link.getValidTo(), formLayout); + dateTo.setHelpText(translate("from.hint")); super.initForm(formLayout, listener, ureq); } diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/token/ui/TokenAccessConfigurationController.java b/src/main/java/org/olat/resource/accesscontrol/provider/token/ui/TokenAccessConfigurationController.java index c90cdca2582da53e6bcd28a882a8438f1ae98084..0713551a7cd1694b83aab8740da0d5a6276536c6 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/token/ui/TokenAccessConfigurationController.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/token/ui/TokenAccessConfigurationController.java @@ -76,7 +76,9 @@ public class TokenAccessConfigurationController extends AbstractConfigurationMet tokenEl.setElementCssClass("o_sel_accesscontrol_token"); dateFrom = uifactory.addDateChooser("from_" + link.getKey(), "from", link.getValidFrom(), formLayout); + dateFrom.setHelpText(translate("from.hint")); dateTo = uifactory.addDateChooser("to_" + link.getKey(), "to", link.getValidTo(), formLayout); + dateTo.setHelpText(translate("to.hint")); super.initForm(formLayout, listener, ureq); } diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java b/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java index 415479233476a4b7c64437eb7774016104d4d5ab..5f30e7fa5e75db21fa9bfb89c99f6bbee46b72dc 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java +++ b/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java @@ -55,10 +55,10 @@ import org.olat.resource.accesscontrol.model.OfferImpl; import org.springframework.beans.factory.annotation.Autowired; /** - * + * * Description:<br> - * - * + * + * * <P> * Initial Date: 14 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com @@ -72,21 +72,21 @@ public class AccessConfigurationController extends FormBasicController { private CloseableModalController cmc; private FormLayoutContainer confControllerContainer; private AbstractConfigurationMethodController newMethodCtrl, editMethodCtrl; - + private final List<AccessInfo> confControllers = new ArrayList<AccessInfo>(); - + private final boolean embbed; private final boolean emptyConfigGrantsFullAccess; private boolean allowPaymentMethod; private final boolean editable; - + private final Formatter formatter; - + @Autowired private ACService acService; @Autowired private AccessControlModule acModule; - + public AccessConfigurationController(UserRequest ureq, WindowControl wControl, OLATResource resource, String displayName, boolean allowPaymentMethod, boolean editable) { super(ureq, wControl, "access_configuration"); @@ -96,16 +96,16 @@ public class AccessConfigurationController extends FormBasicController { this.allowPaymentMethod = allowPaymentMethod; embbed = false; this.editable = editable; - emptyConfigGrantsFullAccess = true; + emptyConfigGrantsFullAccess = true; formatter = Formatter.getInstance(getLocale()); - + initForm(ureq); } - + public AccessConfigurationController(UserRequest ureq, WindowControl wControl, OLATResource resource, String displayName, boolean allowPaymentMethod, boolean editable, Form form) { super(ureq, wControl, FormBasicController.LAYOUT_CUSTOM, "access_configuration", form); - + this.editable = editable; this.resource = resource; this.displayName = displayName; @@ -113,10 +113,10 @@ public class AccessConfigurationController extends FormBasicController { embbed = true; emptyConfigGrantsFullAccess = false; formatter = Formatter.getInstance(getLocale()); - + initForm(ureq); } - + public int getNumOfBookingConfigurations() { return confControllers.size(); } @@ -134,7 +134,7 @@ public class AccessConfigurationController extends FormBasicController { if(handler.isPaymentMethod() && !allowPaymentMethod) { continue; } - + String title = handler.getMethodName(getLocale()); FormLink add = uifactory.addFormLink("create." + handler.getType(), title, null, formLayout, Link.LINK | Link.NONTRANSLATED); add.setUserObject(method); @@ -144,16 +144,16 @@ public class AccessConfigurationController extends FormBasicController { } ((FormLayoutContainer)formLayout).contextPut("methods", addMethods); } - + String confPage = velocity_root + "/configuration_list.html"; confControllerContainer = FormLayoutContainer.createCustomFormLayout("conf-controllers", getTranslator(), confPage); confControllerContainer.setRootForm(mainForm); formLayout.add(confControllerContainer); - + loadConfigurations(); - + confControllerContainer.contextPut("confControllers", confControllers); - + if(!embbed) { setFormTitle("accesscontrol.title"); @@ -166,14 +166,14 @@ public class AccessConfigurationController extends FormBasicController { uifactory.addFormSubmitButton("save", buttonGroupLayout); } } - - confControllerContainer.contextPut("emptyConfigGrantsFullAccess", Boolean.valueOf(emptyConfigGrantsFullAccess)); + + confControllerContainer.contextPut("emptyConfigGrantsFullAccess", Boolean.valueOf(emptyConfigGrantsFullAccess)); } - + public void setAllowPaymentMethod(boolean allowPayment) { this.allowPaymentMethod = allowPayment; } - + public boolean isPaymentMethodInUse() { boolean paymentMethodInUse = false; for(AccessInfo info:confControllers) { @@ -181,7 +181,7 @@ public class AccessConfigurationController extends FormBasicController { } return paymentMethodInUse; } - + @Override protected void doDispose() { // @@ -223,7 +223,7 @@ public class AccessConfigurationController extends FormBasicController { super.event(ureq, source, event); } } - + private void cleanUp() { removeAsListenerAndDispose(editMethodCtrl); removeAsListenerAndDispose(newMethodCtrl); @@ -257,7 +257,7 @@ public class AccessConfigurationController extends FormBasicController { @Override public void formOK(UserRequest ureq) { Map<String,FormItem> formItemMap = confControllerContainer.getFormComponents(); - + List<OfferAccess> links = new ArrayList<OfferAccess>(); for(AccessInfo info:confControllers) { FormItem dateFrom = formItemMap.get("from_" + info.getLink().getKey()); @@ -266,18 +266,18 @@ public class AccessConfigurationController extends FormBasicController { info.getLink().setValidFrom(from); info.getLink().getOffer().setValidFrom(from); } - + FormItem dateTo = formItemMap.get("to_" + info.getLink().getKey()); if(dateTo instanceof DateChooser) { Date to = ((DateChooser)dateTo).getDate(); info.getLink().setValidTo(to); info.getLink().getOffer().setValidTo(to); } - + links.add(info.getLink()); } } - + protected void loadConfigurations() { List<Offer> offers = acService.findOfferByResource(resource, true, null); for(Offer offer:offers) { @@ -287,7 +287,7 @@ public class AccessConfigurationController extends FormBasicController { } } } - + protected void replace(OfferAccess link) { boolean updated = false; for(AccessInfo confController:confControllers) { @@ -296,41 +296,41 @@ public class AccessConfigurationController extends FormBasicController { updated = true; } } - + if(!updated) { addConfiguration(link); } else { confControllerContainer.setDirty(true); } } - + protected void addConfiguration(OfferAccess link) { AccessMethodHandler handler = acModule.getAccessMethodHandler(link.getMethod().getType()); AccessInfo infos = new AccessInfo(handler.getMethodName(getLocale()), handler.isPaymentMethod(), null, link); confControllers.add(infos); - + if(editable) { FormLink editLink = uifactory.addFormLink("edit_" + link.getKey(), "edit", "edit", null, confControllerContainer, Link.BUTTON_SMALL); editLink.setUserObject(infos); editLink.setIconLeftCSS("o_icon o_icon-fw o_icon_edit"); confControllerContainer.add(editLink.getName(), editLink); - + FormLink delLink = uifactory.addFormLink("del_" + link.getKey(), "delete", "delete", null, confControllerContainer, Link.BUTTON_SMALL); delLink.setUserObject(infos); delLink.setIconLeftCSS("o_icon o_icon-fw o_icon_delete_item"); confControllerContainer.add(delLink.getName(), delLink); } } - + private void editMethod(UserRequest ureq, AccessInfo infos) { OfferAccess link = infos.getLink(); - + removeAsListenerAndDispose(editMethodCtrl); AccessMethodHandler handler = acModule.getAccessMethodHandler(link.getMethod().getType()); if (handler != null) { editMethodCtrl = handler.editConfigurationController(ureq, getWindowControl(), link); } - + if(editMethodCtrl != null) { listenTo(editMethodCtrl); @@ -340,11 +340,11 @@ public class AccessConfigurationController extends FormBasicController { listenTo(cmc); } } - + protected void addMethod(UserRequest ureq, AccessMethod method) { Offer offer = acService.createOffer(resource, displayName); OfferAccess link = acService.createOfferAccess(offer, method); - + removeAsListenerAndDispose(newMethodCtrl); AccessMethodHandler handler = acModule.getAccessMethodHandler(link.getMethod().getType()); if (handler != null) { @@ -362,29 +362,29 @@ public class AccessConfigurationController extends FormBasicController { addConfiguration(newLink); } } - + public class AccessInfo { private String name; private String infos; private String dates; private OfferAccess link; private final boolean paymentMethod; - + public AccessInfo(String name, boolean paymentMethod, String infos, OfferAccess link) { this.name = name; this.paymentMethod = paymentMethod; this.infos = infos; this.link = link; } - + public String getName() { return name; } - + public void setName(String name) { this.name = name; } - + public boolean isPaymentMethod() { return paymentMethod; } @@ -416,7 +416,7 @@ public class AccessConfigurationController extends FormBasicController { BigDecimal vat = acModule.getVat(); String vatStr = vat == null ? "" : vat.setScale(3, BigDecimal.ROUND_HALF_EVEN).toPlainString(); return translate("access.info.price.vat", new String[]{price, vatStr}); - + } else { return translate("access.info.price.noVat", new String[]{price}); } @@ -427,7 +427,7 @@ public class AccessConfigurationController extends FormBasicController { } return ""; } - + public void setInfos(String infos) { this.infos = infos; } diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/AccessControlAdminController.java b/src/main/java/org/olat/resource/accesscontrol/ui/AccessControlAdminController.java index ff0a9d537765b8bbb8a69a9699b53639d7a9c9ca..65ba7e2112d4e57d75351dabd56a577c72c6018c 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/AccessControlAdminController.java +++ b/src/main/java/org/olat/resource/accesscontrol/ui/AccessControlAdminController.java @@ -34,53 +34,59 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.resource.accesscontrol.AccessControlModule; import org.olat.resource.accesscontrol.method.AccessMethodHandler; +import org.olat.resource.accesscontrol.provider.free.FreeAccessHandler; +import org.olat.resource.accesscontrol.provider.paypal.PaypalAccessHandler; +import org.olat.resource.accesscontrol.provider.token.TokenAccessHandler; /** - * + * * Description:<br> - * + * * <P> * Initial Date: 26 mai 2011 <br> * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public class AccessControlAdminController extends FormBasicController { - + + private final static String METHOD_AUTO = "ac.method.auto.name"; private MultipleSelectionElement enabled, homeEnabled; private MultipleSelectionElement methods; - + private String[] values = {""}; private String[] keys = {"on"}; - + private String[] methodValues = {""}; private String[] methodKeys = {""}; - + private final AccessControlModule acModule; public AccessControlAdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); - + acModule = CoreSpringFactory.getImpl(AccessControlModule.class); values = new String[] { getTranslator().translate("ac.on") }; - + methodKeys = new String[] { - "free.method", - "token.method", - "paypal.method" + FreeAccessHandler.METHOD_TYPE, + TokenAccessHandler.METHOD_TYPE, + PaypalAccessHandler.METHOD_TYPE, + METHOD_AUTO }; methodValues = new String[methodKeys.length]; - for(int i=0; i<methodKeys.length; i++) { + for(int i=0; i<methodKeys.length-1; i++) { AccessMethodHandler handler = acModule.getAccessMethodHandler(methodKeys[i]); methodValues[i] = handler.getMethodName(getLocale()); } - + methodValues[3] = getTranslator().translate(METHOD_AUTO); + initForm(ureq); } - + @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("admin.title"); @@ -88,32 +94,33 @@ public class AccessControlAdminController extends FormBasicController { enabled = uifactory.addCheckboxesHorizontal("ac.enabled", formLayout, keys, values); enabled.select(keys[0], acModule.isEnabled()); - + uifactory.addSpacerElement("spaceman", formLayout, false); - + methods = uifactory.addCheckboxesVertical("ac.methods", formLayout, methodKeys, methodValues, 1); - methods.select("free.method", acModule.isFreeEnabled()); - methods.select("token.method", acModule.isTokenEnabled()); - methods.select("paypal.method", acModule.isPaypalEnabled()); + methods.select(FreeAccessHandler.METHOD_TYPE, acModule.isFreeEnabled()); + methods.select(TokenAccessHandler.METHOD_TYPE, acModule.isTokenEnabled()); + methods.select(PaypalAccessHandler.METHOD_TYPE, acModule.isPaypalEnabled()); + methods.select(METHOD_AUTO, acModule.isAutoEnabled()); methods.setEnabled(acModule.isEnabled()); methods.addActionListener(FormEvent.ONCHANGE); - + uifactory.addSpacerElement("itgirl", formLayout, false); - + homeEnabled = uifactory.addCheckboxesHorizontal("ac.home.enabled", formLayout, keys, values); homeEnabled.select(keys[0], acModule.isPaypalEnabled() || acModule.isHomeOverviewEnabled()); - + final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator()); buttonGroupLayout.setRootForm(mainForm); uifactory.addFormSubmitButton("save", buttonGroupLayout); - + formLayout.add(buttonGroupLayout); update(); } - + public void update() { Collection<String> selectedMethods = methods.getSelectedKeys(); - if(selectedMethods.contains("paypal.method")) { + if(selectedMethods.contains(PaypalAccessHandler.METHOD_TYPE)) { homeEnabled.select(keys[0], true); homeEnabled.setEnabled(false); } else { @@ -137,16 +144,17 @@ public class AccessControlAdminController extends FormBasicController { protected void formOK(UserRequest ureq) { boolean on = !enabled.getSelectedKeys().isEmpty(); acModule.setEnabled(on); - + Collection<String> selectedMethods = methods.getSelectedKeys(); - acModule.setFreeEnabled(selectedMethods.contains("free.method")); - acModule.setTokenEnabled(selectedMethods.contains("token.method")); - boolean paypalEnabled = selectedMethods.contains("paypal.method"); + acModule.setFreeEnabled(selectedMethods.contains(FreeAccessHandler.METHOD_TYPE)); + acModule.setTokenEnabled(selectedMethods.contains(TokenAccessHandler.METHOD_TYPE)); + boolean paypalEnabled = selectedMethods.contains(PaypalAccessHandler.METHOD_TYPE); acModule.setPaypalEnabled(paypalEnabled); - + acModule.setAutoEnabled(selectedMethods.contains(METHOD_AUTO)); + boolean homeOverviewEnabled = paypalEnabled || !homeEnabled.getSelectedKeys().isEmpty(); acModule.setHomeOverviewEnabled(homeOverviewEnabled); - + methods.setEnabled(on); showInfo("ac.saved"); } diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrdersController.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersController.java index b2e6a29cc34bb101b640021ddddf9950349c2fed..261d7641b1b8b0ece9a325ef698c417f5f2d1d62 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/OrdersController.java +++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersController.java @@ -40,7 +40,9 @@ import org.olat.core.gui.components.stack.BreadcrumbPanelAware; 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.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; @@ -54,35 +56,45 @@ import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; /** - * + * * Description:<br> * List the orders - * + * * <P> * Initial Date: 20 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public class OrdersController extends FormBasicController implements Activateable2, BreadcrumbPanelAware { - + private static final String CMD_SELECT = "sel"; - + private FlexiTableElement tableEl; private OrdersDataSource dataSource; private OrdersDataModel dataModel; private BreadcrumbPanel stackPanel; + private CloseableModalController cmc; + + private Identity identity; private OrderDetailController detailController; - + @Autowired private ACService acService; @Autowired private UserManager userManager; @Autowired private AccessControlModule acModule; - + public OrdersController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl, LAYOUT_BAREBONE); + this.identity = getIdentity(); + initForm(ureq); + } + + public OrdersController(UserRequest ureq, WindowControl wControl, Identity identity) { + super(ureq, wControl, LAYOUT_BAREBONE); + this.identity = identity; initForm(ureq); } @@ -101,8 +113,8 @@ public class OrdersController extends FormBasicController implements Activateabl columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(OrderCol.methods, new AccessMethodRenderer(acModule))); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(OrderCol.total)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.order.details", translate("select"), CMD_SELECT)); - - dataSource = new OrdersDataSource(acService, null, getIdentity(), null); + + dataSource = new OrdersDataSource(acService, null, identity, null); dataModel = new OrdersDataModel(dataSource, getLocale(), userManager, columnsModel); tableEl = uifactory.addTableElement(getWindowControl(), "orderList", dataModel, 25, true, getTranslator(), formLayout); tableEl.setExportEnabled(true); @@ -112,7 +124,7 @@ public class OrdersController extends FormBasicController implements Activateabl filters.add(new FlexiTableFilter(translate("order.status.payed"), OrderStatus.PAYED.name())); filters.add(new FlexiTableFilter(translate("order.status.error"), OrderStatus.ERROR.name())); tableEl.setFilters("", filters, false); - + if(formLayout instanceof FormLayoutContainer) { FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; layoutCont.contextPut("title", translate("orders.my")); @@ -122,9 +134,10 @@ public class OrdersController extends FormBasicController implements Activateabl @Override protected void doDispose() { - // + removeAsListenerAndDispose(cmc); + cmc = null; } - + @Override protected void formOK(UserRequest ureq) { // @@ -144,7 +157,7 @@ public class OrdersController extends FormBasicController implements Activateabl super.formInnerEvent(ureq, source, event); } - + @Override protected void event(UserRequest ureq, Controller source, Event event) { if (source == detailController) { @@ -154,11 +167,11 @@ public class OrdersController extends FormBasicController implements Activateabl } } } - + @Override public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { /*if(entries == null || entries.isEmpty()) return; - + ContextEntry entry = entries.get(0); String type = entry.getOLATResourceable().getResourceableTypeName(); if(Order.class.getSimpleName().equals(type)) { @@ -180,6 +193,13 @@ public class OrdersController extends FormBasicController implements Activateabl detailController = new OrderDetailController(ureq, bwControl, order.getOrderKey()); detailController.hideBackLink(); listenTo(detailController); - stackPanel.pushController(order.getOrderNr(), detailController); + if (stackPanel != null) { + stackPanel.pushController(order.getOrderNr(), detailController); + } else { + cmc = new CloseableModalController(getWindowControl(), translate("close"), detailController.getInitialComponent(), + true, translate("order.booking")); + cmc.activate(); + listenTo(cmc); + } } } \ No newline at end of file diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/UserOrderController.java b/src/main/java/org/olat/resource/accesscontrol/ui/UserOrderController.java new file mode 100644 index 0000000000000000000000000000000000000000..15b4af5457c89e747a08931d03ec9b9e4b0aa620 --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/ui/UserOrderController.java @@ -0,0 +1,107 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.ui; + +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.segmentedview.SegmentViewComponent; +import org.olat.core.gui.components.segmentedview.SegmentViewEvent; +import org.olat.core.gui.components.segmentedview.SegmentViewFactory; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.id.Identity; +import org.olat.resource.accesscontrol.provider.auto.ui.AdvanceOrderController; + +/** + * + * Initial date: 08.09.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class UserOrderController extends BasicController { + + private final VelocityContainer mainVC; + private final Link ordersLink, advanceOrdersLink; + private final SegmentViewComponent segmentView; + + private OrdersController ordersCtrl; + private AdvanceOrderController advanceOrdersCtrl; + + private Identity identity; + + public UserOrderController(UserRequest ureq, WindowControl wControl, Identity identity) { + super(ureq, wControl); + this.identity = identity; + + mainVC = createVelocityContainer("segments"); + + segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); + ordersLink = LinkFactory.createLink("segment.orders", mainVC, this); + segmentView.addSegment(ordersLink, true); + advanceOrdersLink = LinkFactory.createLink("segment.advance.orders", mainVC, this); + segmentView.addSegment(advanceOrdersLink, false); + + doOpenOrders(ureq); + putInitialPanel(mainVC); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if(source == segmentView) { + if(event instanceof SegmentViewEvent) { + SegmentViewEvent sve = (SegmentViewEvent)event; + String segmentCName = sve.getComponentName(); + Component clickedLink = mainVC.getComponent(segmentCName); + if (clickedLink == ordersLink) { + doOpenOrders(ureq); + } else if (clickedLink == advanceOrdersLink){ + doOpenAdvanceOrders(ureq); + } + } + } + } + + private void doOpenOrders(UserRequest ureq) { + if(ordersCtrl == null) { + ordersCtrl = new OrdersController(ureq, getWindowControl(), identity); + listenTo(ordersCtrl); + } + mainVC.put("segmentCmp", ordersCtrl.getInitialComponent()); + } + + private void doOpenAdvanceOrders(UserRequest ureq) { + if(advanceOrdersCtrl == null) { + advanceOrdersCtrl = new AdvanceOrderController(ureq, getWindowControl(), identity); + listenTo(advanceOrdersCtrl); + } + mainVC.put("segmentCmp", advanceOrdersCtrl.getInitialComponent()); + } + + +} diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/segments.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/segments.html new file mode 100644 index 0000000000000000000000000000000000000000..1d39f332e91d588e0ee584a806ba66ef01c49b0a --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/segments.html @@ -0,0 +1,7 @@ +<div class="clearfix"> + $r.render("segments")<br/> + + #if($r.available("segmentCmp")) + $r.render("segmentCmp") + #end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties index dbb1d949e0a14678699af862ed5f63068158a69e..be5ad639800744c5ea0412081a581203497cc5c0 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties @@ -4,6 +4,7 @@ ac.from.label=g\u00FCltig von {0} ac.fromto.label=g\u00FCltig von {0} bis {1} ac.home.enabled=Buchungsliste im Home ac.methods=Verf\u00FCgbare Buchungsmethoden +ac.method.auto.name=Automatische Buchungen ac.methods.label=Buchungsmethoden ac.on=Ein ac.saved=Die Konfiguration der Zugangskontrolle und Buchungsmethoden wurde erfolgreich gespeichert @@ -11,7 +12,7 @@ ac.to.label=g\u00FCltig bis {0} access.button=Buchen access.desc=Diese Ressource wurde von Ihnen noch nicht gebucht. Eine Buchung ist notwendig um diese Ressource aufrufen zu k\u00F6nnen. W\u00E4hlen Sie eine der unten aufgef\u00FChren Buchungsmethoden auf um sich zu registrieren. access.free.desc=Diese Ressource ist f\u00FCr Sie frei verf\u00FCgbar. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:access.button" um sich f\u00FCr den Zugang zu registrieren. -access.free.title=Freie Ressource +access.free.title=Freie Ressource access.info.price.noVat={0} access.info.price.vat={0} (inkl. {1}% MwSt) access.refused.desc=Diese Ressource kann zur Zeit nicht gebucht werden. Bitte kontaktieren Sie den Besitzer dieser Ressource. @@ -20,7 +21,7 @@ access.token.desc=Diese Ressource ist mit einem Zugangscode gesch\u00FCtzt. Gebe access.token.title=Gesch\u00FCtzte Ressource accesscontrol.desc=Sie k\u00F6nnen die Buchungsmethoden f\u00FCr den Zugang zu dieser Ressource konfigurieren. $\:accesscontrol.desc.end accesscontrol.desc.end=W\u00E4hlen Sie die Schaltfl\u00E4che "$\:add.accesscontrol" um aus der Liste der verf\u00FCgbaren Buchungsmethoden eine oder mehrere auszuw\u00E4hlen. Optional k\u00F6nnen Buchungsmethoden mit einem G\u00FCltigkeitsdatum versehen werden. -accesscontrol.no.methods.full.access=Es ist noch keine Buchungsmethode konfiguriert.<br />Der Zugang zu dieser Ressource steht allen Systembenutzern ohne Buchung offen. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:add.accesscontrol" um den Zugang einzuschr\u00E4nken und/oder eine Buchung zu erzwingen. +accesscontrol.no.methods.full.access=Es ist noch keine Buchungsmethode konfiguriert.<br />Der Zugang zu dieser Ressource steht allen Systembenutzern ohne Buchung offen. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:add.accesscontrol" um den Zugang einzuschr\u00E4nken und/oder eine Buchung zu erzwingen. accesscontrol.no.methods.no.access=Es ist noch keine Buchungsmethode konfiguriert.<br />Diese Ressource kann nur von den Teilnehmer der Ressource verwendet werden. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:add.accesscontrol" um eine Buchungsmethode zu w\u00E4hlen und die Ressource zu ver\u00F6ffentlichen. accesscontrol.table.from=g\u00FCltig von accesscontrol.table.method=Buchungsmethode @@ -29,9 +30,9 @@ accesscontrol.title=Buchungsmethoden konfigurieren accesscontrol.token=Zugangscode accesscontrol_group.desc=Sie k\u00F6nnen die Buchungsmethoden f\u00FCr den Zugang zu dieser Gruppe konfigurieren. $\:accesscontrol.desc.end add.accesscontrol=Buchungsmethode hinzuf\u00FCgen -add.accesscontrol.intro=W\u00E4hlen Sie eine Buchungsmethode f\u00FCr die Zugangskontrolle dieser Ressource. Sie k\u00F6nnen mehrere Buchungsmethoden mit unterschiedlichen Datumseinschr\u00E4nkungen w\u00E4hlen. +add.accesscontrol.intro=W\u00E4hlen Sie eine Buchungsmethode f\u00FCr die Zugangskontrolle dieser Ressource. Sie k\u00F6nnen mehrere Buchungsmethoden mit unterschiedlichen Datumseinschr\u00E4nkungen w\u00E4hlen. add.token=Zugangscode erstellen -admin.desc=Hier k\u00F6nnen Sie die Zugangskontrolle f\u00FCr Lernressourcen und Gruppen f\u00FCr das gesamte System ein- und ausschalten. Bei eingeschalteter Zugangskontrolle k\u00F6nnen Sie die zur Verf\u00FCgung stehenden Buchungsmethoden ausw\u00E4hlen. +admin.desc=Hier k\u00F6nnen Sie die Zugangskontrolle f\u00FCr Lernressourcen und Gruppen f\u00FCr das gesamte System ein- und ausschalten. Bei eingeschalteter Zugangskontrolle k\u00F6nnen Sie die zur Verf\u00FCgung stehenden Buchungsmethoden ausw\u00E4hlen. admin.menu.title=Zugangskontrolle admin.menu.title.alt=$\:admin.title admin.title=Verwaltung der Zugangskontrolle und Buchungsmethoden @@ -40,6 +41,7 @@ cmd.title=Zugangskontrolle course.closed=$org.olat.course.run\:course.closed create=Erstellen from=Von\: +from.hint=Bis zum eingetragenen Datum bedeutet, bis zum Ende des gew\u00E4hlten Tages um 23:59:59 Uhr. info.membership.deleted=Der Benutzer wurde erfolgreich aus der Liste entfernt. members.add=Benutzer hinzuf\u00FCgen members.confirm.remove=Entfernen best\u00E4tigen @@ -49,22 +51,23 @@ members.name=Name members.owners=Besitzer members.owners.alt=Benutzer mit Besitzerrechten f\u00FCr diese Lernressource members.owners.confirm.remove=Bitte best\u00E4tigen Sie, dass Sie die Autoren "{0}" aus allen Gruppen austragen wollen\: -members.owners.info=Diese Liste zeigt die Benutzer mit Besitzerrechten f\u00FCr diese Lernressource. Diese Personen haben vollen Zugang zu allen administrativen Werkzeugen der Ressource inklusive der Verwaltung der Besitzer. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:members.add" oder "$\:members.import" um einem bzw. mehreren Benutzern die Besitzerrechte zuzuteilen. +members.owners.info=Diese Liste zeigt die Benutzer mit Besitzerrechten f\u00FCr diese Lernressource. Diese Personen haben vollen Zugang zu allen administrativen Werkzeugen der Ressource inklusive der Verwaltung der Besitzer. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:members.add" oder "$\:members.import" um einem bzw. mehreren Benutzern die Besitzerrechte zuzuteilen. members.participants=Teilnehmer members.participants.alt=Benutzer mit normalen Teilnehmerfunktionen members.participants.confirm.remove=Bitte best\u00E4tigen Sie, dass Sie die Teilnehmer "{0}" aus allen Gruppen austragen wollen\: -members.participants.info=Diese Liste zeigt die Benutzer mit Teilnehmerrechten f\u00FCr diese Lernressource. Diese Personen haben Zugang zu der Lernressource wenn sie ver\u00F6ffentlicht wurde. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:members.add" oder "$\:members.import" um einem bzw. mehreren Benutzern den Zugang zu gestatten. <br />Wenn Sie mit Lerngruppen arbeiten, dann werden Teilnehmer von Lerngruppen dieser Lernressource automatisch auch in die Teilnehmerliste eingetragen. <br /> Wenn Sie mit Buchungen arbeiten, dann werden Teilnehmer die diese Lernressource buchen automatisch in diese Teilnehmerliste eingetragen. <br /> Sie k\u00F6nnen eine Person jederzeit aus dieser Liste austragen. Die Person hat anschliessend keinen Zugang mehr zu dieser Lernressource. +members.participants.info=Diese Liste zeigt die Benutzer mit Teilnehmerrechten f\u00FCr diese Lernressource. Diese Personen haben Zugang zu der Lernressource wenn sie ver\u00F6ffentlicht wurde. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:members.add" oder "$\:members.import" um einem bzw. mehreren Benutzern den Zugang zu gestatten. <br />Wenn Sie mit Lerngruppen arbeiten, dann werden Teilnehmer von Lerngruppen dieser Lernressource automatisch auch in die Teilnehmerliste eingetragen. <br /> Wenn Sie mit Buchungen arbeiten, dann werden Teilnehmer die diese Lernressource buchen automatisch in diese Teilnehmerliste eingetragen. <br /> Sie k\u00F6nnen eine Person jederzeit aus dieser Liste austragen. Die Person hat anschliessend keinen Zugang mehr zu dieser Lernressource. members.title=Mitgliederverwaltung members.title.alt=Verwalten von Besitzern, Betreuern und Teilnehmern dieser Lernressource members.tutors=Betreuer members.tutors.alt=Benutzer mit Betreuungsfunktionen f\u00FCr diese Lernressource members.tutors.confirm.remove=Bitte best\u00E4tigen Sie, dass Sie die Betreuer "{0}" aus allen Gruppen austragen wollen\: -members.tutors.info=Diese Liste zeigt die Benutzer mit Betreuungsrechten f\u00FCr diese Lernressource. Diese Personen haben Zugang zu der Lernressource wenn sie ver\u00F6ffentlicht wurde analog zu den Teilnehmern. In Kursen stehen den Betreuern Werkzeuge wie z.B. das Bewertungswerkzeug zur Verf\u00FCgung. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:members.add" oder "$\:members.import" um einem bzw. mehreren Benutzern die Betreuungsrechte zuzuteilen. <br />Wenn Sie mit Lerngruppen arbeiten, dann werden Betreuer von Lerngruppen dieser Lernressource automatisch auch in die Liste der Betreuer eingetragen. +members.tutors.info=Diese Liste zeigt die Benutzer mit Betreuungsrechten f\u00FCr diese Lernressource. Diese Personen haben Zugang zu der Lernressource wenn sie ver\u00F6ffentlicht wurde analog zu den Teilnehmern. In Kursen stehen den Betreuern Werkzeuge wie z.B. das Bewertungswerkzeug zur Verf\u00FCgung. W\u00E4hlen Sie die Schaltfl\u00E4che "$\:members.add" oder "$\:members.import" um einem bzw. mehreren Benutzern die Betreuungsrechte zuzuteilen. <br />Wenn Sie mit Lerngruppen arbeiten, dann werden Betreuer von Lerngruppen dieser Lernressource automatisch auch in die Liste der Betreuer eingetragen. membership.delete.desc=Bitte best\u00E4tigen Sie, dass der gew\u00E4hlte Benutzer aus dieser Liste entfernt werden soll\: membership.delete.title=Benutzer entfernen menu.orders=Buchungen menu.orders.alt=Buchungen offer.description=Beschreibung +order.booking=Buchung order.creationDate=Datum order.delivery=Gebucht von order.details=Detailinformationen @@ -92,5 +95,8 @@ orders.my.desc=Im folgenden sehen Sie alle Ressourcen die Sie gebucht haben. W\u table.order.details=Ausw\u00E4hlen table.order.empty=Sie haben zur Zeit keine Buchungen. to=Bis\: +to.hint=$:from.hint transaction.date=Erstellt am transaction.details.title=Details \u00FCber Transaktion +segment.orders=Buchungen +segment.advance.orders=Vorbestellungen diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties index 9685a5e74c95dcbd50dbcb1237bc21cf661f1cbc..701fa5425c9c805a9a16402e168a5b166581a2c7 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties @@ -4,6 +4,7 @@ ac.from.label=valid from {0} ac.fromto.label=valid from {0} to {1} ac.home.enabled=Bookings in Home ac.methods=Available booking methods +ac.method.auto.name=Automatic booking ac.methods.label=Booking method ac.on=On ac.saved=The configuration for access control and booking methods has been saved @@ -31,7 +32,7 @@ accesscontrol_group.desc=You can configure booking methods for accessing this gr add.accesscontrol=Add booking method add.accesscontrol.intro=Select a booking method to control access to this resource. You can add multiple booking methods and configure different validation periods for each booking method. add.token=Create access code -admin.desc=Here you can define if the access control mechanism for learning resources and groups should be enabled system wide. If access control is enabled you can then choose the booking methods that should be enabled. +admin.desc=Here you can define if the access control mechanism for learning resources and groups should be enabled system wide. If access control is enabled you can then choose the booking methods that should be enabled. admin.menu.title=Access control admin.menu.title.alt=$\:admin.title admin.title=Access control and booking methods administration @@ -63,6 +64,7 @@ cmd.title=Access control course.closed=$org.olat.course.run\:course.closed create=Create from=From\: +from.hint=Until the inserted date means until the end of the chosen day at 11:59:59 pm. info.membership.deleted=The user has successfully been removed from the list. members.add=Add user members.confirm.remove=Confirm removal @@ -88,6 +90,7 @@ membership.delete.title=Remove user menu.orders=Bookings menu.orders.alt=Bookings offer.description=Description +order.booking=Booking order.creationDate=Date order.delivery=Booked by order.details=Detail information @@ -115,5 +118,8 @@ orders.my.desc=In the following list you see all the resources to have booked. S table.order.details=Select table.order.empty=There are no bookings at this time to display. to=To\: +to.hint=$:from.hint transaction.date=Created at transaction.details.title=Transation details +segment.orders=Bookings +segment.advance.orders=Advance bookings \ No newline at end of file diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_fr.properties index 2ca67c0b3f228ccdccb4a3c88c0f864676c22eef..cfdd91e4e3c6c3119af63dbf5f57a0eafc882411 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Wed Jan 11 18:32:38 CET 2017 +#Sun Aug 27 16:07:57 CEST 2017 ac.enabled=Activer le contr\u00F4le d'acc\u00E8s aux ressources ac.from.label=valable \u00E0 partir du {0} ac.fromto.label=valable depuis le {0} jusqu'au {1} @@ -40,6 +40,7 @@ cmd.title=Contr\u00F4le d'acc\u00E8s course.closed=$org.olat.course.run\:course.closed create=Cr\u00E9er from=De\: +from.hint=Jusqu'\u00E0 la date d\u00E9finie signifie jusqu'\u00E0 la fin de la journ\u00E9e choisie \u00E0 23h 59m 59s. info.membership.deleted=L'utilisateur a \u00E9t\u00E9 supprim\u00E9 de la liste avec succ\u00E8s. members.add=Ajouter un utilisateur members.confirm.remove=Confirmer la suppression @@ -92,5 +93,6 @@ orders.my.desc=Ci-dessous, vous pouvez voir toutes les ressources que vous avez table.order.details=Choisir table.order.empty=Vous n'avez pour l'instant aucune r\u00E9servation. to=A\: +to.hint=$\:from.hint transaction.date=Cr\u00E9er le transaction.details.title=D\u00E9tails de la transaction diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_pt_BR.properties index c1d3aea3b0e82f9b682e8d21f6f6c3bfd68b7fee..ce643cbb051b0d7609fdc8f16349cc939f03bc27 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Mon Jan 16 20:56:40 CET 2017 +#Tue Sep 19 20:29:04 CEST 2017 ac.enabled=Ative o controle de acesso a recursos ac.from.label=v\u00E1lido {0} ac.fromto.label=v\u00E1lido de {0} at\u00E9 {1} @@ -40,6 +40,7 @@ cmd.title=Controle de acesso course.closed=$org.olat.course.run\:course.closed create=Criar from=De\: +from.hint=At\u00E9 a data inserida significa at\u00E9 o final do dia escolhido \u00E0s 11\:59\:59 pm. info.membership.deleted=O utilizador foi removido da lista com sucesso. members.add=Adicionar usu\u00E1rio members.confirm.remove=Confirmar remo\u00E7\u00E3o @@ -92,5 +93,6 @@ orders.my.desc=Na lista a seguir voc\u00EA ver\u00E1 todos os recursos para que table.order.details=Selecionar table.order.empty=N\u00E3o existem reservas neste momento para mostrar. to=Para\: +to.hint=$\:from.hint transaction.date=Criado em transaction.details.title=Detalhes da transa\u00E7\u00E3o diff --git a/src/main/java/org/olat/restapi/_spring/restApiContext.xml b/src/main/java/org/olat/restapi/_spring/restApiContext.xml index 7836d4a86a0f8cf52ffb7866fd78eadddf75c6df..5240c1a4d6d5f39339902892133f78b7b93ea085 100644 --- a/src/main/java/org/olat/restapi/_spring/restApiContext.xml +++ b/src/main/java/org/olat/restapi/_spring/restApiContext.xml @@ -35,10 +35,12 @@ <value>org.olat.course.nodes.bc.BCWebService</value> <value>org.olat.course.assessment.restapi.EfficiencyStatementWebService</value> <value>org.olat.course.certificate.restapi.CertificationWebService</value> + <value>org.olat.modules.qpool.restapi.QuestionPoolWebService</value> <value>org.olat.modules.wiki.restapi.WikisWebService</value> <value>org.olat.modules.fo.restapi.ForumImportWebService</value> <value>org.olat.modules.fo.restapi.ForumCourseNodeWebService</value> <value>org.olat.modules.fo.restapi.MyForumsWebService</value> + <value>org.olat.modules.lecture.restapi.LectureBlocksRootWebService</value> <value>org.olat.modules.openmeetings.restapi.OpenMeetingsWebService</value> <value>org.olat.modules.vitero.restapi.ViteroWebService</value> <value>org.olat.core.commons.services.notifications.restapi.NotificationsWebService</value> @@ -51,7 +53,7 @@ </property> </bean> - <bean id="systemSamplerTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="systemSamplerTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="systemSamplerJob" /> <!-- adjust cron style syntax for your needs A "Cron-Expression" is a string comprised of 6 or 7 fields separated by white space. The 6 mandatory and 1 optional fields are as follows: @@ -71,32 +73,32 @@ <property name="startDelay" value="60000" /> </bean> - <bean id="systemSamplerJob" class="org.springframework.scheduling.quartz.JobDetailBean"> + <bean id="systemSamplerJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="org.olat.restapi.system.SamplerJob" /> </bean> - <bean id="procSamplerTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="procSamplerTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="procSamplerJob" /> <property name="cronExpression" value="5 3,8,13,18,23,28,33,38,43,48,53,58 * * * ?" /> <property name="startDelay" value="30000" /> </bean> - <bean id="procSamplerJob" class="org.springframework.scheduling.quartz.JobDetailBean"> + <bean id="procSamplerJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="org.olat.restapi.system.ProcSamplerJob" /> </bean> <!-- Deadline Job --> - <bean id="restTokenTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> + <bean id="restTokenTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="restTokenJob.${cluster.singleton.services}" /> <!-- every day at 1:21 --> <property name="cronExpression" value="0 21 1 * * ?" /> <property name="startDelay" value="60000" /> </bean> - <bean id="restTokenJob.enabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="restTokenJob.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.restapi.security.RestTokenJob" /> </bean> - <bean id="restTokenJob.disabled" class="org.springframework.scheduling.quartz.JobDetailBean" lazy-init="true"> + <bean id="restTokenJob.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true"> <property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" /> </bean> diff --git a/src/main/java/org/olat/restapi/api/_content/application.html b/src/main/java/org/olat/restapi/api/_content/application.html index 5854e1f9a4b7a19259746bbe0e30bfaffa1a48d3..b86538cd5b1b710869adb4aff91b256febb61add 100644 --- a/src/main/java/org/olat/restapi/api/_content/application.html +++ b/src/main/java/org/olat/restapi/api/_content/application.html @@ -200,260 +200,242 @@ </p> <ul> <li><a href="#resources">Resources</a><ul> - <li><a href="#d2e2">http://www.example.com/repo/forums</a><ul> - <li><a href="#d2e5">http://www.example.com/repo/forums/version</a></li> - <li><a href="#d2e20">http://www.example.com/repo/forums/{forumKey}</a><ul> - <li><a href="#d2e54">http://www.example.com/repo/forums/{forumKey}/threads</a></li> - <li><a href="#d2e163">http://www.example.com/repo/forums/{forumKey}/posts/{threadKey}</a></li> - <li><a href="#d2e204">http://www.example.com/repo/forums/{forumKey}/posts/{messageKey}</a></li> - <li><a href="#d2e316">http://www.example.com/repo/forums/{forumKey}/posts/{messageKey}/attachments</a></li> - <li><a href="#d2e387">http://www.example.com/repo/forums/{forumKey}/posts/{messageKey}/attachments/{filename}</a></li> + <li><a href="#d2e2">http://www.example.com/repo/courses/{courseId}/elements/folder</a><ul> + <li><a href="#d2e143">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}</a></li> + <li><a href="#d2e226">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}/files</a><ul> + <li><a href="#d2e260">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}/files/{path:.*}</a></li> + <li><a href="#d2e304">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}/files/metadata/{path:.*}</a></li> + <li><a href="#d2e310">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}/files/version</a></li> </ul> </li> </ul> </li> - <li><a href="#d2e409">http://www.example.com/auth</a><ul> - <li><a href="#d2e410">http://www.example.com/auth/version</a></li> - <li><a href="#d2e414">http://www.example.com/auth/{username}</a></li> - </ul> - </li> - <li><a href="#d2e423">http://www.example.com/groups</a><ul> - <li><a href="#d2e438">http://www.example.com/groups/version</a></li> - <li><a href="#d2e442">http://www.example.com/groups/{groupKey}</a></li> - <li><a href="#d2e458">http://www.example.com/groups/{groupKey}/news</a></li> - <li><a href="#d2e472">http://www.example.com/groups/{groupKey}/configuration</a></li> - <li><a href="#d2e479">http://www.example.com/groups/{groupKey}/infos</a></li> - <li><a href="#d2e485">http://www.example.com/groups/{groupKey}/owners</a></li> - <li><a href="#d2e491">http://www.example.com/groups/{groupKey}/participants</a></li> - <li><a href="#d2e497">http://www.example.com/groups/{groupKey}/owners/{identityKey}</a></li> - <li><a href="#d2e506">http://www.example.com/groups/{groupKey}/participants/{identityKey}</a></li> - <li><a href="#d2e516">http://www.example.com/groups/{groupKey}/forum</a><ul> - <li><a href="#d2e548">http://www.example.com/groups/{groupKey}/forum/threads</a></li> - <li><a href="#d2e657">http://www.example.com/groups/{groupKey}/forum/posts/{threadKey}</a></li> - <li><a href="#d2e698">http://www.example.com/groups/{groupKey}/forum/posts/{messageKey}</a></li> - <li><a href="#d2e810">http://www.example.com/groups/{groupKey}/forum/posts/{messageKey}/attachments</a></li> - <li><a href="#d2e881">http://www.example.com/groups/{groupKey}/forum/posts/{messageKey}/attachments/{filename}</a></li> - </ul> - </li> - <li><a href="#d2e903">http://www.example.com/groups/{groupKey}/folder</a><ul> - <li><a href="#d2e936">http://www.example.com/groups/{groupKey}/folder/{path:.*}</a></li> - <li><a href="#d2e980">http://www.example.com/groups/{groupKey}/folder/version</a></li> - <li><a href="#d2e984">http://www.example.com/groups/{groupKey}/folder/metadata/{path:.*}</a></li> + <li><a href="#d2e314">http://www.example.com/users/{identityKey}/calendars</a><ul> + <li><a href="#d2e320">http://www.example.com/users/{identityKey}/calendars/events</a></li> + <li><a href="#d2e330">http://www.example.com/users/{identityKey}/calendars/{calendarId}</a><ul> + <li><a href="#d2e335">http://www.example.com/users/{identityKey}/calendars/{calendarId}/events</a></li> + <li><a href="#d2e358">http://www.example.com/users/{identityKey}/calendars/{calendarId}/events/{eventId}</a></li> + <li><a href="#d2e364">http://www.example.com/users/{identityKey}/calendars/{calendarId}/event</a></li> </ul> </li> - <li><a href="#d2e990">http://www.example.com/groups/{groupKey}/wiki</a></li> </ul> </li> - <li><a href="#d2e1000">http://www.example.com/i18n</a><ul> - <li><a href="#d2e1001">http://www.example.com/i18n/version</a></li> - <li><a href="#d2e1005">http://www.example.com/i18n/{package}/{key}</a></li> - </ul> - </li> - <li><a href="#d2e1013">http://www.example.com/system</a><ul> - <li><a href="#d2e1014">http://www.example.com/system/environment</a></li> - <li><a href="#d2e1019">http://www.example.com/system/release</a></li> - <li><a href="#d2e1024">http://www.example.com/system/notifications</a><ul> - <li><a href="#d2e1025">http://www.example.com/system/notifications/status</a></li> - </ul> - </li> - <li><a href="#d2e1039">http://www.example.com/system/monitoring</a><ul> - <li><a href="#d2e1040">http://www.example.com/system/monitoring/configuration</a></li> - <li><a href="#d2e1045">http://www.example.com/system/monitoring/status</a></li> - <li><a href="#d2e1050">http://www.example.com/system/monitoring/runtime</a><ul> - <li><a href="#d2e1055">http://www.example.com/system/monitoring/runtime/classes</a></li> - <li><a href="#d2e1060">http://www.example.com/system/monitoring/runtime/memory</a></li> - <li><a href="#d2e1065">http://www.example.com/system/monitoring/runtime/threads</a></li> - </ul> - </li> - <li><a href="#d2e1070">http://www.example.com/system/monitoring/database</a></li> - <li><a href="#d2e1075">http://www.example.com/system/monitoring/openolat</a><ul> - <li><a href="#d2e1080">http://www.example.com/system/monitoring/openolat/tasks</a></li> - <li><a href="#d2e1085">http://www.example.com/system/monitoring/openolat/users</a></li> - <li><a href="#d2e1090">http://www.example.com/system/monitoring/openolat/repository</a></li> - <li><a href="#d2e1095">http://www.example.com/system/monitoring/openolat/sessions</a></li> - <li><a href="#d2e1100">http://www.example.com/system/monitoring/openolat/indexer</a><ul> - <li><a href="#d2e1105">http://www.example.com/system/monitoring/openolat/indexer/status</a></li> + <li><a href="#d2e380">http://www.example.com/repo/courses</a><ul> + <li><a href="#d2e425">http://www.example.com/repo/courses/version</a></li> + <li><a href="#d2e429">http://www.example.com/repo/courses/{courseId}</a><ul> + <li><a href="#d2e439">http://www.example.com/repo/courses/{courseId}/configuration</a></li> + <li><a href="#d2e457">http://www.example.com/repo/courses/{courseId}/tutors/{identityKey}</a></li> + <li><a href="#d2e462">http://www.example.com/repo/courses/{courseId}/file</a></li> + <li><a href="#d2e467">http://www.example.com/repo/courses/{courseId}/status</a></li> + <li><a href="#d2e475">http://www.example.com/repo/courses/{courseId}/runstructure</a></li> + <li><a href="#d2e479">http://www.example.com/repo/courses/{courseId}/editortreemodel</a></li> + <li><a href="#d2e483">http://www.example.com/repo/courses/{courseId}/authors/{identityKey}</a></li> + <li><a href="#d2e496">http://www.example.com/repo/courses/{courseId}/authors</a></li> + <li><a href="#d2e508">http://www.example.com/repo/courses/{courseId}/tutors</a></li> + <li><a href="#d2e519">http://www.example.com/repo/courses/{courseId}/participants</a></li> + <li><a href="#d2e530">http://www.example.com/repo/courses/{courseId}/participants/{identityKey}</a></li> + <li><a href="#d2e535">http://www.example.com/repo/courses/{courseId}/version</a></li> + <li><a href="#d2e539">http://www.example.com/repo/courses/{courseId}/resource</a></li> + <li><a href="#d2e544">http://www.example.com/repo/courses/{courseId}/publish</a></li> + <li><a href="#d2e553">http://www.example.com/repo/courses/{courseId}/groups</a><ul> + <li><a href="#d2e565">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}</a></li> + <li><a href="#d2e578">http://www.example.com/repo/courses/{courseId}/groups/version</a></li> + <li><a href="#d2e582">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/folder</a><ul> + <li><a href="#d2e615">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/folder/{path:.*}</a></li> + <li><a href="#d2e659">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/folder/metadata/{path:.*}</a></li> + <li><a href="#d2e665">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/folder/version</a></li> + </ul> + </li> + <li><a href="#d2e669">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum</a><ul> + <li><a href="#d2e701">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/threads</a></li> + <li><a href="#d2e810">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{threadKey}</a></li> + <li><a href="#d2e851">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}</a></li> + <li><a href="#d2e963">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}/attachments</a></li> + <li><a href="#d2e1034">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}/attachments/{filename}</a></li> </ul> </li> </ul> </li> - <li><a href="#d2e1119">http://www.example.com/system/monitoring/memory</a><ul> - <li><a href="#d2e1127">http://www.example.com/system/monitoring/memory/pools</a></li> - <li><a href="#d2e1135">http://www.example.com/system/monitoring/memory/samples</a></li> + <li><a href="#d2e1056">http://www.example.com/repo/courses/{courseId}/calendar</a><ul> + <li><a href="#d2e1059">http://www.example.com/repo/courses/{courseId}/calendar/events</a></li> + <li><a href="#d2e1082">http://www.example.com/repo/courses/{courseId}/calendar/events/{eventId}</a></li> + <li><a href="#d2e1088">http://www.example.com/repo/courses/{courseId}/calendar/event</a></li> + </ul> + </li> + <li><a href="#d2e1104">http://www.example.com/repo/courses/{courseId}/vitero/{subIdentifier}</a><ul> + <li><a href="#d2e1162">http://www.example.com/repo/courses/{courseId}/vitero/{subIdentifier}/{bookingId}/members</a></li> + <li><a href="#d2e1201">http://www.example.com/repo/courses/{courseId}/vitero/{subIdentifier}/{bookingId}</a></li> + </ul> + </li> + <li><a href="#d2e1212">http://www.example.com/repo/courses/{courseId}/gotomeeting/{subIdentifier}</a><ul> + <li><a href="#d2e1216">http://www.example.com/repo/courses/{courseId}/gotomeeting/{subIdentifier}/trainings</a></li> + <li><a href="#d2e1271">http://www.example.com/repo/courses/{courseId}/gotomeeting/{subIdentifier}//trainings/{trainingKey}</a></li> </ul> </li> - <li><a href="#d2e1144">http://www.example.com/system/monitoring/threads</a><ul> - <li><a href="#d2e1152">http://www.example.com/system/monitoring/threads/cpu</a></li> + <li><a href="#d2e1282">http://www.example.com/repo/courses/{courseId}/lectureblocks</a><ul> + <li><a href="#d2e1302">http://www.example.com/repo/courses/{courseId}/lectureblocks/configuration</a></li> + <li><a href="#d2e1315">http://www.example.com/repo/courses/{courseId}/lectureblocks/sync/calendar</a></li> + <li><a href="#d2e1319">http://www.example.com/repo/courses/{courseId}/lectureblocks/adaptation</a></li> + <li><a href="#d2e1323">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}</a><ul> + <li><a href="#d2e1332">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/teachers/{identityKey}</a></li> + <li><a href="#d2e1340">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/teachers</a></li> + <li><a href="#d2e1345">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/participants/repositoryentry</a></li> + <li><a href="#d2e1352">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/sync/calendar</a></li> + </ul> + </li> </ul> </li> </ul> </li> - <li><a href="#d2e1157">http://www.example.com/system/indexer</a><ul> - <li><a href="#d2e1162">http://www.example.com/system/indexer/status</a></li> + </ul> + </li> + <li><a href="#d2e1356">http://www.example.com/pwchange</a></li> + <li><a href="#d2e1365">http://www.example.com/vitero</a><ul> + <li><a href="#d2e1368">http://www.example.com/vitero/{resourceName}/{resourceId}/{subIdentifier}</a><ul> + <li><a href="#d2e1428">http://www.example.com/vitero/{resourceName}/{resourceId}/{subIdentifier}/{bookingId}/members</a></li> + <li><a href="#d2e1467">http://www.example.com/vitero/{resourceName}/{resourceId}/{subIdentifier}/{bookingId}</a></li> + </ul> + </li> + </ul> + </li> + <li><a href="#d2e1478">http://www.example.com/groups</a><ul> + <li><a href="#d2e1493">http://www.example.com/groups/{groupKey}</a></li> + <li><a href="#d2e1509">http://www.example.com/groups/{groupKey}/news</a></li> + <li><a href="#d2e1523">http://www.example.com/groups/{groupKey}/configuration</a></li> + <li><a href="#d2e1530">http://www.example.com/groups/{groupKey}/infos</a></li> + <li><a href="#d2e1536">http://www.example.com/groups/{groupKey}/owners</a></li> + <li><a href="#d2e1542">http://www.example.com/groups/{groupKey}/participants</a></li> + <li><a href="#d2e1548">http://www.example.com/groups/{groupKey}/owners/{identityKey}</a></li> + <li><a href="#d2e1557">http://www.example.com/groups/{groupKey}/participants/{identityKey}</a></li> + <li><a href="#d2e1566">http://www.example.com/groups/version</a></li> + <li><a href="#d2e1571">http://www.example.com/groups/{groupKey}/wiki</a></li> + <li><a href="#d2e1581">http://www.example.com/groups/{groupKey}/folder</a><ul> + <li><a href="#d2e1614">http://www.example.com/groups/{groupKey}/folder/{path:.*}</a></li> + <li><a href="#d2e1658">http://www.example.com/groups/{groupKey}/folder/metadata/{path:.*}</a></li> + <li><a href="#d2e1664">http://www.example.com/groups/{groupKey}/folder/version</a></li> </ul> </li> - <li><a href="#d2e1176">http://www.example.com/system/log</a><ul> - <li><a href="#d2e1181">http://www.example.com/system/log/version</a></li> - <li><a href="#d2e1185">http://www.example.com/system/log/{date}</a></li> + <li><a href="#d2e1668">http://www.example.com/groups/{groupKey}/forum</a><ul> + <li><a href="#d2e1700">http://www.example.com/groups/{groupKey}/forum/threads</a></li> + <li><a href="#d2e1809">http://www.example.com/groups/{groupKey}/forum/posts/{threadKey}</a></li> + <li><a href="#d2e1850">http://www.example.com/groups/{groupKey}/forum/posts/{messageKey}</a></li> + <li><a href="#d2e1962">http://www.example.com/groups/{groupKey}/forum/posts/{messageKey}/attachments</a></li> + <li><a href="#d2e2033">http://www.example.com/groups/{groupKey}/forum/posts/{messageKey}/attachments/{filename}</a></li> </ul> </li> </ul> </li> - <li><a href="#d2e1191">http://www.example.com/contacts</a></li> - <li><a href="#d2e1206">http://www.example.com/catalog</a><ul> - <li><a href="#d2e1211">http://www.example.com/catalog/{path:.*}/owners/{identityKey}</a></li> - <li><a href="#d2e1223">http://www.example.com/catalog/version</a></li> - <li><a href="#d2e1227">http://www.example.com/catalog/{path:.*}/children</a></li> - <li><a href="#d2e1236">http://www.example.com/catalog/{path:.*}</a></li> - <li><a href="#d2e1287">http://www.example.com/catalog/{path:.*}/owners</a></li> + <li><a href="#d2e2055">http://www.example.com/repo/courses/{courseId}/db/{category}</a><ul> + <li><a href="#d2e2058">http://www.example.com/repo/courses/{courseId}/db/{category}/values/{name}</a></li> + <li><a href="#d2e2142">http://www.example.com/repo/courses/{courseId}/db/{category}/values</a></li> + <li><a href="#d2e2183">http://www.example.com/repo/courses/{courseId}/db/{category}/values/{name}/delete</a></li> + <li><a href="#d2e2208">http://www.example.com/repo/courses/{courseId}/db/{category}/version</a></li> </ul> </li> - <li><a href="#d2e1293">http://www.example.com/repo/entries</a><ul> - <li><a href="#d2e1313">http://www.example.com/repo/entries/search</a></li> - <li><a href="#d2e1323">http://www.example.com/repo/entries/version</a></li> - <li><a href="#d2e1327">http://www.example.com/repo/entries/{repoEntryKey}</a><ul> - <li><a href="#d2e1348">http://www.example.com/repo/entries/{repoEntryKey}/coaches</a></li> - <li><a href="#d2e1360">http://www.example.com/repo/entries/{repoEntryKey}/coaches/{identityKey}</a></li> - <li><a href="#d2e1369">http://www.example.com/repo/entries/{repoEntryKey}/participants</a></li> - <li><a href="#d2e1381">http://www.example.com/repo/entries/{repoEntryKey}/participants/{identityKey}</a></li> - <li><a href="#d2e1390">http://www.example.com/repo/entries/{repoEntryKey}/owners</a></li> - <li><a href="#d2e1402">http://www.example.com/repo/entries/{repoEntryKey}/owners/{identityKey}</a></li> - <li><a href="#d2e1412">http://www.example.com/repo/entries/{repoEntryKey}/file</a></li> - <li><a href="#d2e1418">http://www.example.com/repo/entries/{repoEntryKey}/status</a></li> - <li><a href="#d2e1427">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks</a><ul> - <li><a href="#d2e1448">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/configuration</a></li> - <li><a href="#d2e1461">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}</a><ul> - <li><a href="#d2e1469">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/teachers/{identityKey}</a></li> - <li><a href="#d2e1477">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/teachers</a></li> - <li><a href="#d2e1481">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/participants/repositoryentry</a></li> - <li><a href="#d2e1488">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/calendar</a></li> - </ul> - </li> - </ul> - </li> + <li><a href="#d2e2223">http://www.example.com/repo/courses/{courseId}/resourcefolders</a><ul> + <li><a href="#d2e2224">http://www.example.com/repo/courses/{courseId}/resourcefolders/version</a></li> + <li><a href="#d2e2228">http://www.example.com/repo/courses/{courseId}/resourcefolders/sharedfolder/{path:.*}</a></li> + <li><a href="#d2e2237">http://www.example.com/repo/courses/{courseId}/resourcefolders/sharedfolder</a></li> + <li><a href="#d2e2242">http://www.example.com/repo/courses/{courseId}/resourcefolders/coursefolder/{path:.*}</a></li> + <li><a href="#d2e2257">http://www.example.com/repo/courses/{courseId}/resourcefolders/coursefolder</a></li> + </ul> + </li> + <li><a href="#d2e2268">http://www.example.com/repo/courses/{courseId}/elements/forum</a><ul> + <li><a href="#d2e2379">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}</a></li> + <li><a href="#d2e2414">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/thread</a></li> + <li><a href="#d2e2462">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/message</a></li> + <li><a href="#d2e2510">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum</a><ul> + <li><a href="#d2e2543">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/threads</a></li> + <li><a href="#d2e2652">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{threadKey}</a></li> + <li><a href="#d2e2693">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}</a></li> + <li><a href="#d2e2805">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}/attachments</a></li> + <li><a href="#d2e2876">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}/attachments/{filename}</a></li> </ul> </li> </ul> </li> - <li><a href="#d2e1492">http://www.example.com/users/{identityKey}/calendars</a><ul> - <li><a href="#d2e1498">http://www.example.com/users/{identityKey}/calendars/events</a></li> - <li><a href="#d2e1508">http://www.example.com/users/{identityKey}/calendars/{calendarId}</a><ul> - <li><a href="#d2e1513">http://www.example.com/users/{identityKey}/calendars/{calendarId}/events/{eventId}</a></li> - <li><a href="#d2e1519">http://www.example.com/users/{identityKey}/calendars/{calendarId}/event</a></li> - <li><a href="#d2e1535">http://www.example.com/users/{identityKey}/calendars/{calendarId}/events</a></li> + <li><a href="#d2e2898">http://www.example.com/users/{identityKey}/forums</a><ul> + <li><a href="#d2e2926">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}</a><ul> + <li><a href="#d2e2959">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/threads</a></li> + <li><a href="#d2e3068">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{threadKey}</a></li> + <li><a href="#d2e3109">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}</a></li> + <li><a href="#d2e3221">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}/attachments</a></li> + <li><a href="#d2e3292">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}/attachments/{filename}</a></li> + </ul> + </li> + <li><a href="#d2e3314">http://www.example.com/users/{identityKey}/forums/group/{groupKey}</a><ul> + <li><a href="#d2e3346">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/threads</a></li> + <li><a href="#d2e3455">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/posts/{threadKey}</a></li> + <li><a href="#d2e3496">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}</a></li> + <li><a href="#d2e3608">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}/attachments</a></li> + <li><a href="#d2e3679">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}/attachments/{filename}</a></li> </ul> </li> </ul> </li> - <li><a href="#d2e1558">http://www.example.com/repo/courses/{courseId}/elements/enrollment</a><ul> - <li><a href="#d2e1677">http://www.example.com/repo/courses/{courseId}/elements/enrollment/{nodeId}/groups</a></li> + <li><a href="#d2e3701">http://www.example.com/repo/courses/{resourceKey}/certificates</a><ul> + <li><a href="#d2e3704">http://www.example.com/repo/courses/{resourceKey}/certificates/{identityKey}</a></li> </ul> </li> - <li><a href="#d2e1708">http://www.example.com/repo/courses/{courseId}/elements/forum</a><ul> - <li><a href="#d2e1819">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}</a></li> - <li><a href="#d2e1854">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/thread</a></li> - <li><a href="#d2e1902">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/message</a></li> - <li><a href="#d2e1950">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum</a><ul> - <li><a href="#d2e1983">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/threads</a></li> - <li><a href="#d2e2092">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{threadKey}</a></li> - <li><a href="#d2e2133">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}</a></li> - <li><a href="#d2e2245">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}/attachments</a></li> - <li><a href="#d2e2316">http://www.example.com/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}/attachments/{filename}</a></li> - </ul> - </li> + <li><a href="#d2e3797">http://www.example.com/ping</a><ul> + <li><a href="#d2e3801">http://www.example.com/ping/version</a></li> + <li><a href="#d2e3805">http://www.example.com/ping/{name}</a></li> </ul> </li> - <li><a href="#d2e2339">http://www.example.com/notifications</a><ul> - <li><a href="#d2e2371">http://www.example.com/notifications/subscribers</a></li> - <li><a href="#d2e2378">http://www.example.com/notifications/subscribers/{subscriberKey}</a></li> - <li><a href="#d2e2383">http://www.example.com/notifications/subscribers/{ressourceName}/{ressourceId}/{subIdentifier}</a></li> + <li><a href="#d2e3810">http://www.example.com/openmeetings</a><ul> + <li><a href="#d2e3813">http://www.example.com/openmeetings/{identityToken}/portrait</a></li> </ul> </li> - <li><a href="#d2e2391">http://www.example.com/repo/sharedfolder</a><ul> - <li><a href="#d2e2392">http://www.example.com/repo/sharedfolder/version</a></li> - <li><a href="#d2e2396">http://www.example.com/repo/sharedfolder/{repoEntryKey}/{path:.*}</a></li> - <li><a href="#d2e2402">http://www.example.com/repo/sharedfolder/{repoEntryKey}</a></li> - <li><a href="#d2e2407">http://www.example.com/repo/sharedfolder/{repoEntryKey}/files</a><ul> - <li><a href="#d2e2440">http://www.example.com/repo/sharedfolder/{repoEntryKey}/files/{path:.*}</a></li> - <li><a href="#d2e2484">http://www.example.com/repo/sharedfolder/{repoEntryKey}/files/version</a></li> - <li><a href="#d2e2488">http://www.example.com/repo/sharedfolder/{repoEntryKey}/files/metadata/{path:.*}</a></li> - </ul> - </li> + <li><a href="#d2e3832">http://www.example.com/repo/courses/{courseId}/assessments</a><ul> + <li><a href="#d2e3838">http://www.example.com/repo/courses/{courseId}/assessments/users/{identityKey}</a></li> + <li><a href="#d2e3845">http://www.example.com/repo/courses/{courseId}/assessments/{nodeId}</a></li> + <li><a href="#d2e3858">http://www.example.com/repo/courses/{courseId}/assessments/version</a></li> + <li><a href="#d2e3862">http://www.example.com/repo/courses/{courseId}/assessments/{nodeId}/users/{identityKey}</a></li> </ul> </li> - <li><a href="#d2e2494">http://www.example.com/users/{username}/auth</a><ul> - <li><a href="#d2e2565">http://www.example.com/users/{username}/auth/{authKey}</a></li> - <li><a href="#d2e2593">http://www.example.com/users/{username}/auth/password</a></li> - <li><a href="#d2e2629">http://www.example.com/users/{username}/auth/version</a></li> + <li><a href="#d2e3870">http://www.example.com/repo/wikis</a><ul> + <li><a href="#d2e3879">http://www.example.com/repo/wikis/{wikiKey}</a></li> </ul> </li> - <li><a href="#d2e2646">http://www.example.com/repo/courses/{courseId}/db/{category}</a><ul> - <li><a href="#d2e2649">http://www.example.com/repo/courses/{courseId}/db/{category}/values/{name}</a></li> - <li><a href="#d2e2733">http://www.example.com/repo/courses/{courseId}/db/{category}/values</a></li> - <li><a href="#d2e2774">http://www.example.com/repo/courses/{courseId}/db/{category}/version</a></li> - <li><a href="#d2e2789">http://www.example.com/repo/courses/{courseId}/db/{category}/values/{name}/delete</a></li> + <li><a href="#d2e3891">http://www.example.com/users/{username}/auth</a><ul> + <li><a href="#d2e3962">http://www.example.com/users/{username}/auth/{authKey}</a></li> + <li><a href="#d2e3990">http://www.example.com/users/{username}/auth/password</a></li> + <li><a href="#d2e4026">http://www.example.com/users/{username}/auth/version</a></li> </ul> </li> - <li><a href="#d2e2814">http://www.example.com/registration</a></li> - <li><a href="#d2e2848">http://www.example.com/repo/courses</a><ul> - <li><a href="#d2e2893">http://www.example.com/repo/courses/version</a></li> - <li><a href="#d2e2897">http://www.example.com/repo/courses/{courseId}</a><ul> - <li><a href="#d2e2907">http://www.example.com/repo/courses/{courseId}/version</a></li> - <li><a href="#d2e2911">http://www.example.com/repo/courses/{courseId}/configuration</a></li> - <li><a href="#d2e2929">http://www.example.com/repo/courses/{courseId}/authors</a></li> - <li><a href="#d2e2940">http://www.example.com/repo/courses/{courseId}/resource</a></li> - <li><a href="#d2e2945">http://www.example.com/repo/courses/{courseId}/publish</a></li> - <li><a href="#d2e2954">http://www.example.com/repo/courses/{courseId}/tutors</a></li> - <li><a href="#d2e2965">http://www.example.com/repo/courses/{courseId}/participants</a></li> - <li><a href="#d2e2976">http://www.example.com/repo/courses/{courseId}/participants/{identityKey}</a></li> - <li><a href="#d2e2982">http://www.example.com/repo/courses/{courseId}/file</a></li> - <li><a href="#d2e2987">http://www.example.com/repo/courses/{courseId}/status</a></li> - <li><a href="#d2e2995">http://www.example.com/repo/courses/{courseId}/runstructure</a></li> - <li><a href="#d2e2999">http://www.example.com/repo/courses/{courseId}/editortreemodel</a></li> - <li><a href="#d2e3003">http://www.example.com/repo/courses/{courseId}/authors/{identityKey}</a></li> - <li><a href="#d2e3016">http://www.example.com/repo/courses/{courseId}/tutors/{identityKey}</a></li> - <li><a href="#d2e3021">http://www.example.com/repo/courses/{courseId}/groups</a><ul> - <li><a href="#d2e3033">http://www.example.com/repo/courses/{courseId}/groups/version</a></li> - <li><a href="#d2e3037">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}</a></li> - <li><a href="#d2e3050">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum</a><ul> - <li><a href="#d2e3082">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/threads</a></li> - <li><a href="#d2e3191">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{threadKey}</a></li> - <li><a href="#d2e3232">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}</a></li> - <li><a href="#d2e3344">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}/attachments</a></li> - <li><a href="#d2e3415">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}/attachments/{filename}</a></li> - </ul> - </li> - <li><a href="#d2e3437">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/folder</a><ul> - <li><a href="#d2e3470">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/folder/{path:.*}</a></li> - <li><a href="#d2e3514">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/folder/version</a></li> - <li><a href="#d2e3518">http://www.example.com/repo/courses/{courseId}/groups/{groupKey}/folder/metadata/{path:.*}</a></li> - </ul> - </li> - </ul> - </li> - <li><a href="#d2e3524">http://www.example.com/repo/courses/{courseId}/calendar</a><ul> - <li><a href="#d2e3527">http://www.example.com/repo/courses/{courseId}/calendar/events/{eventId}</a></li> - <li><a href="#d2e3533">http://www.example.com/repo/courses/{courseId}/calendar/event</a></li> - <li><a href="#d2e3549">http://www.example.com/repo/courses/{courseId}/calendar/events</a></li> - </ul> - </li> - <li><a href="#d2e3572">http://www.example.com/repo/courses/{courseId}/vitero/{subIdentifier}</a><ul> - <li><a href="#d2e3630">http://www.example.com/repo/courses/{courseId}/vitero/{subIdentifier}/{bookingId}/members</a></li> - <li><a href="#d2e3669">http://www.example.com/repo/courses/{courseId}/vitero/{subIdentifier}/{bookingId}</a></li> - </ul> - </li> - <li><a href="#d2e3680">http://www.example.com/repo/courses/{courseId}/gotomeeting/{subIdentifier}</a><ul> - <li><a href="#d2e3684">http://www.example.com/repo/courses/{courseId}/gotomeeting/{subIdentifier}/trainings</a></li> - <li><a href="#d2e3739">http://www.example.com/repo/courses/{courseId}/gotomeeting/{subIdentifier}//trainings/{trainingKey}</a></li> - </ul> - </li> - <li><a href="#d2e3750">http://www.example.com/repo/courses/{courseId}/lectureblocks</a><ul> - <li><a href="#d2e3770">http://www.example.com/repo/courses/{courseId}/lectureblocks/configuration</a></li> - <li><a href="#d2e3783">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}</a><ul> - <li><a href="#d2e3791">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/teachers/{identityKey}</a></li> - <li><a href="#d2e3799">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/teachers</a></li> - <li><a href="#d2e3803">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/participants/repositoryentry</a></li> - <li><a href="#d2e3810">http://www.example.com/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/calendar</a></li> + <li><a href="#d2e4043">http://www.example.com/repo/lifecycle</a></li> + <li><a href="#d2e4048">http://www.example.com/notifications</a><ul> + <li><a href="#d2e4080">http://www.example.com/notifications/subscribers</a></li> + <li><a href="#d2e4087">http://www.example.com/notifications/subscribers/{subscriberKey}</a></li> + <li><a href="#d2e4092">http://www.example.com/notifications/subscribers/{ressourceName}/{ressourceId}/{subIdentifier}</a></li> + </ul> + </li> + <li><a href="#d2e4100">http://www.example.com/i18n</a><ul> + <li><a href="#d2e4101">http://www.example.com/i18n/{package}/{key}</a></li> + <li><a href="#d2e4109">http://www.example.com/i18n/version</a></li> + </ul> + </li> + <li><a href="#d2e4113">http://www.example.com/repo/entries</a><ul> + <li><a href="#d2e4133">http://www.example.com/repo/entries/search</a></li> + <li><a href="#d2e4143">http://www.example.com/repo/entries/version</a></li> + <li><a href="#d2e4147">http://www.example.com/repo/entries/{repoEntryKey}</a><ul> + <li><a href="#d2e4168">http://www.example.com/repo/entries/{repoEntryKey}/coaches/{identityKey}</a></li> + <li><a href="#d2e4177">http://www.example.com/repo/entries/{repoEntryKey}/coaches</a></li> + <li><a href="#d2e4189">http://www.example.com/repo/entries/{repoEntryKey}/file</a></li> + <li><a href="#d2e4195">http://www.example.com/repo/entries/{repoEntryKey}/status</a></li> + <li><a href="#d2e4204">http://www.example.com/repo/entries/{repoEntryKey}/participants</a></li> + <li><a href="#d2e4216">http://www.example.com/repo/entries/{repoEntryKey}/participants/{identityKey}</a></li> + <li><a href="#d2e4226">http://www.example.com/repo/entries/{repoEntryKey}/owners</a></li> + <li><a href="#d2e4238">http://www.example.com/repo/entries/{repoEntryKey}/owners/{identityKey}</a></li> + <li><a href="#d2e4247">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks</a><ul> + <li><a href="#d2e4268">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/configuration</a></li> + <li><a href="#d2e4281">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/sync/calendar</a></li> + <li><a href="#d2e4285">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/adaptation</a></li> + <li><a href="#d2e4289">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}</a><ul> + <li><a href="#d2e4298">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/teachers/{identityKey}</a></li> + <li><a href="#d2e4306">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/teachers</a></li> + <li><a href="#d2e4311">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/participants/repositoryentry</a></li> + <li><a href="#d2e4318">http://www.example.com/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/sync/calendar</a></li> </ul> </li> </ul> @@ -462,1454 +444,1458 @@ </li> </ul> </li> - <li><a href="#d2e3814">http://www.example.com/repo/wikis</a><ul> - <li><a href="#d2e3823">http://www.example.com/repo/wikis/{wikiKey}</a></li> + <li><a href="#d2e4322">http://www.example.com/repo/courses/{courseId}/elements/contact</a></li> + <li><a href="#d2e4447">http://www.example.com/api</a><ul> + <li><a href="#d2e4448">http://www.example.com/api/doc</a></li> + <li><a href="#d2e4452">http://www.example.com/api/doc/{filename}</a></li> + <li><a href="#d2e4457">http://www.example.com/api/{filename}</a></li> + <li><a href="#d2e4462">http://www.example.com/api/copyright</a></li> + <li><a href="#d2e4470">http://www.example.com/api/version</a></li> </ul> </li> - <li><a href="#d2e3835">http://www.example.com/pwchange</a></li> - <li><a href="#d2e3844">http://www.example.com/api</a><ul> - <li><a href="#d2e3845">http://www.example.com/api/version</a></li> - <li><a href="#d2e3849">http://www.example.com/api/doc</a></li> - <li><a href="#d2e3853">http://www.example.com/api/doc/{filename}</a></li> - <li><a href="#d2e3858">http://www.example.com/api/{filename}</a></li> - <li><a href="#d2e3863">http://www.example.com/api/copyright</a></li> + <li><a href="#d2e4475">http://www.example.com/repo/courses/{courseId}/elements/enrollment</a><ul> + <li><a href="#d2e4594">http://www.example.com/repo/courses/{courseId}/elements/enrollment/{nodeId}/groups</a></li> </ul> </li> - <li><a href="#d2e3871">http://www.example.com/repo/lifecycle</a></li> - <li><a href="#d2e3876">http://www.example.com/repo/courses/{resourceKey}/certificates</a><ul> - <li><a href="#d2e3879">http://www.example.com/repo/courses/{resourceKey}/certificates/{identityKey}</a></li> + <li><a href="#d2e4625">http://www.example.com/catalog</a><ul> + <li><a href="#d2e4630">http://www.example.com/catalog/{path:.*}/children</a></li> + <li><a href="#d2e4639">http://www.example.com/catalog/{path:.*}/owners/{identityKey}</a></li> + <li><a href="#d2e4651">http://www.example.com/catalog/{path:.*}</a></li> + <li><a href="#d2e4702">http://www.example.com/catalog/{path:.*}/owners</a></li> + <li><a href="#d2e4708">http://www.example.com/catalog/version</a></li> </ul> </li> - <li><a href="#d2e3972">http://www.example.com/users/{identityKey}/forums</a><ul> - <li><a href="#d2e4000">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}</a><ul> - <li><a href="#d2e4033">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/threads</a></li> - <li><a href="#d2e4142">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{threadKey}</a></li> - <li><a href="#d2e4183">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}</a></li> - <li><a href="#d2e4295">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}/attachments</a></li> - <li><a href="#d2e4366">http://www.example.com/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}/attachments/{filename}</a></li> + <li><a href="#d2e4712">http://www.example.com/system</a><ul> + <li><a href="#d2e4713">http://www.example.com/system/environment</a></li> + <li><a href="#d2e4718">http://www.example.com/system/release</a></li> + <li><a href="#d2e4723">http://www.example.com/system/notifications</a><ul> + <li><a href="#d2e4724">http://www.example.com/system/notifications/status</a></li> </ul> </li> - <li><a href="#d2e4388">http://www.example.com/users/{identityKey}/forums/group/{groupKey}</a><ul> - <li><a href="#d2e4420">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/threads</a></li> - <li><a href="#d2e4529">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/posts/{threadKey}</a></li> - <li><a href="#d2e4570">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}</a></li> - <li><a href="#d2e4682">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}/attachments</a></li> - <li><a href="#d2e4753">http://www.example.com/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}/attachments/{filename}</a></li> - </ul> - </li> - </ul> - </li> - <li><a href="#d2e4775">http://www.example.com/vitero</a><ul> - <li><a href="#d2e4778">http://www.example.com/vitero/{resourceName}/{resourceId}/{subIdentifier}</a><ul> - <li><a href="#d2e4838">http://www.example.com/vitero/{resourceName}/{resourceId}/{subIdentifier}/{bookingId}/members</a></li> - <li><a href="#d2e4877">http://www.example.com/vitero/{resourceName}/{resourceId}/{subIdentifier}/{bookingId}</a></li> + <li><a href="#d2e4738">http://www.example.com/system/log</a><ul> + <li><a href="#d2e4743">http://www.example.com/system/log/{date}</a></li> + <li><a href="#d2e4749">http://www.example.com/system/log/version</a></li> </ul> </li> - </ul> - </li> - <li><a href="#d2e4888">http://www.example.com/users</a><ul> - <li><a href="#d2e4956">http://www.example.com/users/{identityKey}</a></li> - <li><a href="#d2e5057">http://www.example.com/users/{identityKey}/status</a></li> - <li><a href="#d2e5120">http://www.example.com/users/{identityKey}/roles</a></li> - <li><a href="#d2e5183">http://www.example.com/users/version</a></li> - <li><a href="#d2e5200">http://www.example.com/users/{identityKey}/portrait</a></li> - <li><a href="#d2e5270">http://www.example.com/users/managed</a></li> - <li><a href="#d2e5275">http://www.example.com/users/{identityKey}/preferences</a></li> - <li><a href="#d2e5338">http://www.example.com/users/{identityKey}/portrait/{size}</a></li> - <li><a href="#d2e5357">http://www.example.com/users/{identityKey}/folders</a><ul> - <li><a href="#d2e5383">http://www.example.com/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}</a><ul> - <li><a href="#d2e5417">http://www.example.com/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/{path:.*}</a></li> - <li><a href="#d2e5461">http://www.example.com/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/version</a></li> - <li><a href="#d2e5465">http://www.example.com/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/metadata/{path:.*}</a></li> + <li><a href="#d2e4753">http://www.example.com/system/monitoring</a><ul> + <li><a href="#d2e4754">http://www.example.com/system/monitoring/configuration</a></li> + <li><a href="#d2e4759">http://www.example.com/system/monitoring/status</a></li> + <li><a href="#d2e4764">http://www.example.com/system/monitoring/runtime</a><ul> + <li><a href="#d2e4769">http://www.example.com/system/monitoring/runtime/memory</a></li> + <li><a href="#d2e4774">http://www.example.com/system/monitoring/runtime/threads</a></li> + <li><a href="#d2e4779">http://www.example.com/system/monitoring/runtime/classes</a></li> + </ul> + </li> + <li><a href="#d2e4784">http://www.example.com/system/monitoring/database</a></li> + <li><a href="#d2e4789">http://www.example.com/system/monitoring/openolat</a><ul> + <li><a href="#d2e4794">http://www.example.com/system/monitoring/openolat/tasks</a></li> + <li><a href="#d2e4799">http://www.example.com/system/monitoring/openolat/users</a></li> + <li><a href="#d2e4804">http://www.example.com/system/monitoring/openolat/repository</a></li> + <li><a href="#d2e4809">http://www.example.com/system/monitoring/openolat/sessions</a></li> + <li><a href="#d2e4814">http://www.example.com/system/monitoring/openolat/indexer</a><ul> + <li><a href="#d2e4819">http://www.example.com/system/monitoring/openolat/indexer/status</a></li> + </ul> + </li> </ul> </li> - <li><a href="#d2e5471">http://www.example.com/users/{identityKey}/folders/personal</a><ul> - <li><a href="#d2e5503">http://www.example.com/users/{identityKey}/folders/personal/{path:.*}</a></li> - <li><a href="#d2e5547">http://www.example.com/users/{identityKey}/folders/personal/version</a></li> - <li><a href="#d2e5551">http://www.example.com/users/{identityKey}/folders/personal/metadata/{path:.*}</a></li> + <li><a href="#d2e4833">http://www.example.com/system/monitoring/memory</a><ul> + <li><a href="#d2e4841">http://www.example.com/system/monitoring/memory/pools</a></li> + <li><a href="#d2e4849">http://www.example.com/system/monitoring/memory/samples</a></li> </ul> </li> - <li><a href="#d2e5557">http://www.example.com/users/{identityKey}/folders/group/{groupKey}</a><ul> - <li><a href="#d2e5590">http://www.example.com/users/{identityKey}/folders/group/{groupKey}/{path:.*}</a></li> - <li><a href="#d2e5634">http://www.example.com/users/{identityKey}/folders/group/{groupKey}/version</a></li> - <li><a href="#d2e5638">http://www.example.com/users/{identityKey}/folders/group/{groupKey}/metadata/{path:.*}</a></li> + <li><a href="#d2e4858">http://www.example.com/system/monitoring/threads</a><ul> + <li><a href="#d2e4866">http://www.example.com/system/monitoring/threads/cpu</a></li> </ul> </li> </ul> </li> - <li><a href="#d2e5644">http://www.example.com/users/{identityKey}/courses</a><ul> - <li><a href="#d2e5646">http://www.example.com/users/{identityKey}/courses/my</a></li> - <li><a href="#d2e5676">http://www.example.com/users/{identityKey}/courses/teached</a></li> - <li><a href="#d2e5706">http://www.example.com/users/{identityKey}/courses/favorite</a></li> - </ul> - </li> - <li><a href="#d2e5736">http://www.example.com/users/{identityKey}/groups</a><ul> - <li><a href="#d2e5747">http://www.example.com/users/{identityKey}/groups/owner</a></li> - <li><a href="#d2e5757">http://www.example.com/users/{identityKey}/groups/participant</a></li> - <li><a href="#d2e5767">http://www.example.com/users/{identityKey}/groups/infos</a></li> + <li><a href="#d2e4871">http://www.example.com/system/indexer</a><ul> + <li><a href="#d2e4876">http://www.example.com/system/indexer/status</a></li> </ul> </li> </ul> </li> - <li><a href="#d2e5777">http://www.example.com/repo/courses/{courseId}/assessments</a><ul> - <li><a href="#d2e5783">http://www.example.com/repo/courses/{courseId}/assessments/version</a></li> - <li><a href="#d2e5787">http://www.example.com/repo/courses/{courseId}/assessments/users/{identityKey}</a></li> - <li><a href="#d2e5794">http://www.example.com/repo/courses/{courseId}/assessments/{nodeId}</a></li> - <li><a href="#d2e5807">http://www.example.com/repo/courses/{courseId}/assessments/{nodeId}/users/{identityKey}</a></li> - </ul> - </li> - <li><a href="#d2e5815">http://www.example.com/repo/courses/{courseId}/elements/folder</a><ul> - <li><a href="#d2e5956">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}</a></li> - <li><a href="#d2e6039">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}/files</a><ul> - <li><a href="#d2e6073">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}/files/{path:.*}</a></li> - <li><a href="#d2e6117">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}/files/version</a></li> - <li><a href="#d2e6121">http://www.example.com/repo/courses/{courseId}/elements/folder/{nodeId}/files/metadata/{path:.*}</a></li> + <li><a href="#d2e4890">http://www.example.com/registration</a></li> + <li><a href="#d2e4924">http://www.example.com/repo/sharedfolder</a><ul> + <li><a href="#d2e4925">http://www.example.com/repo/sharedfolder/version</a></li> + <li><a href="#d2e4929">http://www.example.com/repo/sharedfolder/{repoEntryKey}/{path:.*}</a></li> + <li><a href="#d2e4935">http://www.example.com/repo/sharedfolder/{repoEntryKey}</a></li> + <li><a href="#d2e4940">http://www.example.com/repo/sharedfolder/{repoEntryKey}/files</a><ul> + <li><a href="#d2e4973">http://www.example.com/repo/sharedfolder/{repoEntryKey}/files/{path:.*}</a></li> + <li><a href="#d2e5017">http://www.example.com/repo/sharedfolder/{repoEntryKey}/files/metadata/{path:.*}</a></li> + <li><a href="#d2e5023">http://www.example.com/repo/sharedfolder/{repoEntryKey}/files/version</a></li> </ul> </li> </ul> </li> - <li><a href="#d2e6127">http://www.example.com/repo/courses/{courseId}/elements/contact</a></li> - <li><a href="#d2e6254">http://www.example.com/repo/courses/{courseId}/elements</a><ul> - <li><a href="#d2e6255">http://www.example.com/repo/courses/{courseId}/elements/version</a></li> - <li><a href="#d2e6259">http://www.example.com/repo/courses/{courseId}/elements/{nodeId}</a></li> - <li><a href="#d2e6266">http://www.example.com/repo/courses/{courseId}/elements/structure/{nodeId}</a></li> - <li><a href="#d2e6273">http://www.example.com/repo/courses/{courseId}/elements/structure</a></li> - <li><a href="#d2e6292">http://www.example.com/repo/courses/{courseId}/elements/singlepage/{nodeId}</a></li> - <li><a href="#d2e6299">http://www.example.com/repo/courses/{courseId}/elements/singlepage</a></li> - <li><a href="#d2e6338">http://www.example.com/repo/courses/{courseId}/elements/task/{nodeId}</a></li> - <li><a href="#d2e6354">http://www.example.com/repo/courses/{courseId}/elements/task</a></li> - <li><a href="#d2e6385">http://www.example.com/repo/courses/{courseId}/elements/test/{nodeId}</a></li> - <li><a href="#d2e6400">http://www.example.com/repo/courses/{courseId}/elements/test</a></li> - <li><a href="#d2e6429">http://www.example.com/repo/courses/{courseId}/elements/assessment/{nodeId}</a></li> - <li><a href="#d2e6444">http://www.example.com/repo/courses/{courseId}/elements/assessment</a></li> - <li><a href="#d2e6471">http://www.example.com/repo/courses/{courseId}/elements/wiki/{nodeId}</a></li> - <li><a href="#d2e6486">http://www.example.com/repo/courses/{courseId}/elements/wiki</a></li> - <li><a href="#d2e6514">http://www.example.com/repo/courses/{courseId}/elements/blog/{nodeId}</a></li> - <li><a href="#d2e6529">http://www.example.com/repo/courses/{courseId}/elements/blog</a></li> - <li><a href="#d2e6557">http://www.example.com/repo/courses/{courseId}/elements/survey/{nodeId}</a></li> - <li><a href="#d2e6572">http://www.example.com/repo/courses/{courseId}/elements/survey</a></li> - <li><a href="#d2e6600">http://www.example.com/repo/courses/{courseId}/elements/externalpage/{nodeId}</a></li> - <li><a href="#d2e6615">http://www.example.com/repo/courses/{courseId}/elements/externalpage</a></li> - <li><a href="#d2e6643">http://www.example.com/repo/courses/{courseId}/elements/task/{nodeId}/file</a></li> - <li><a href="#d2e6654">http://www.example.com/repo/courses/{courseId}/elements/task/{nodeId}/configuration</a></li> - <li><a href="#d2e6726">http://www.example.com/repo/courses/{courseId}/elements/survey/{nodeId}/configuration</a></li> - <li><a href="#d2e6757">http://www.example.com/repo/courses/{courseId}/elements/test/{nodeId}/configuration</a></li> + <li><a href="#d2e5027">http://www.example.com/repo/forums</a><ul> + <li><a href="#d2e5030">http://www.example.com/repo/forums/version</a></li> + <li><a href="#d2e5045">http://www.example.com/repo/forums/{forumKey}</a><ul> + <li><a href="#d2e5079">http://www.example.com/repo/forums/{forumKey}/threads</a></li> + <li><a href="#d2e5188">http://www.example.com/repo/forums/{forumKey}/posts/{threadKey}</a></li> + <li><a href="#d2e5229">http://www.example.com/repo/forums/{forumKey}/posts/{messageKey}</a></li> + <li><a href="#d2e5341">http://www.example.com/repo/forums/{forumKey}/posts/{messageKey}/attachments</a></li> + <li><a href="#d2e5412">http://www.example.com/repo/forums/{forumKey}/posts/{messageKey}/attachments/{filename}</a></li> + </ul> + </li> </ul> </li> - <li><a href="#d2e6810">http://www.example.com/ping</a><ul> - <li><a href="#d2e6814">http://www.example.com/ping/version</a></li> - <li><a href="#d2e6818">http://www.example.com/ping/{name}</a></li> + <li><a href="#d2e5434">http://www.example.com/auth</a><ul> + <li><a href="#d2e5435">http://www.example.com/auth/{username}</a></li> + <li><a href="#d2e5444">http://www.example.com/auth/version</a></li> </ul> </li> - <li><a href="#d2e6823">http://www.example.com/repo/courses/infos</a><ul> - <li><a href="#d2e6831">http://www.example.com/repo/courses/infos/{courseId}</a></li> + <li><a href="#d2e5448">http://www.example.com/users</a><ul> + <li><a href="#d2e5516">http://www.example.com/users/{identityKey}</a></li> + <li><a href="#d2e5617">http://www.example.com/users/{identityKey}/portrait</a></li> + <li><a href="#d2e5687">http://www.example.com/users/{identityKey}/status</a></li> + <li><a href="#d2e5750">http://www.example.com/users/{identityKey}/roles</a></li> + <li><a href="#d2e5813">http://www.example.com/users/managed</a></li> + <li><a href="#d2e5818">http://www.example.com/users/{identityKey}/preferences</a></li> + <li><a href="#d2e5881">http://www.example.com/users/{identityKey}/portrait/{size}</a></li> + <li><a href="#d2e5899">http://www.example.com/users/version</a></li> + <li><a href="#d2e5917">http://www.example.com/users/{identityKey}/folders</a><ul> + <li><a href="#d2e5943">http://www.example.com/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}</a><ul> + <li><a href="#d2e5977">http://www.example.com/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/{path:.*}</a></li> + <li><a href="#d2e6021">http://www.example.com/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/metadata/{path:.*}</a></li> + <li><a href="#d2e6027">http://www.example.com/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/version</a></li> + </ul> + </li> + <li><a href="#d2e6031">http://www.example.com/users/{identityKey}/folders/personal</a><ul> + <li><a href="#d2e6063">http://www.example.com/users/{identityKey}/folders/personal/{path:.*}</a></li> + <li><a href="#d2e6107">http://www.example.com/users/{identityKey}/folders/personal/metadata/{path:.*}</a></li> + <li><a href="#d2e6113">http://www.example.com/users/{identityKey}/folders/personal/version</a></li> + </ul> + </li> + <li><a href="#d2e6117">http://www.example.com/users/{identityKey}/folders/group/{groupKey}</a><ul> + <li><a href="#d2e6150">http://www.example.com/users/{identityKey}/folders/group/{groupKey}/{path:.*}</a></li> + <li><a href="#d2e6194">http://www.example.com/users/{identityKey}/folders/group/{groupKey}/metadata/{path:.*}</a></li> + <li><a href="#d2e6200">http://www.example.com/users/{identityKey}/folders/group/{groupKey}/version</a></li> + </ul> + </li> + </ul> + </li> + <li><a href="#d2e6204">http://www.example.com/users/{identityKey}/courses</a><ul> + <li><a href="#d2e6206">http://www.example.com/users/{identityKey}/courses/my</a></li> + <li><a href="#d2e6236">http://www.example.com/users/{identityKey}/courses/teached</a></li> + <li><a href="#d2e6266">http://www.example.com/users/{identityKey}/courses/favorite</a></li> + </ul> + </li> + <li><a href="#d2e6296">http://www.example.com/users/{identityKey}/groups</a><ul> + <li><a href="#d2e6307">http://www.example.com/users/{identityKey}/groups/owner</a></li> + <li><a href="#d2e6317">http://www.example.com/users/{identityKey}/groups/participant</a></li> + <li><a href="#d2e6327">http://www.example.com/users/{identityKey}/groups/infos</a></li> + </ul> + </li> </ul> </li> - <li><a href="#d2e6837">http://www.example.com/openmeetings</a><ul> - <li><a href="#d2e6840">http://www.example.com/openmeetings/{identityToken}/portrait</a></li> + <li><a href="#d2e6337">http://www.example.com/repo/courses/infos</a><ul> + <li><a href="#d2e6345">http://www.example.com/repo/courses/infos/{courseId}</a></li> </ul> </li> - <li><a href="#d2e6859">http://www.example.com/repo/courses/{courseId}/resourcefolders</a><ul> - <li><a href="#d2e6860">http://www.example.com/repo/courses/{courseId}/resourcefolders/version</a></li> - <li><a href="#d2e6864">http://www.example.com/repo/courses/{courseId}/resourcefolders/sharedfolder/{path:.*}</a></li> - <li><a href="#d2e6873">http://www.example.com/repo/courses/{courseId}/resourcefolders/sharedfolder</a></li> - <li><a href="#d2e6878">http://www.example.com/repo/courses/{courseId}/resourcefolders/coursefolder/{path:.*}</a></li> - <li><a href="#d2e6893">http://www.example.com/repo/courses/{courseId}/resourcefolders/coursefolder</a></li> + <li><a href="#d2e6351">http://www.example.com/contacts</a></li> + <li><a href="#d2e6366">http://www.example.com/repo/courses/{courseId}/elements</a><ul> + <li><a href="#d2e6367">http://www.example.com/repo/courses/{courseId}/elements/{nodeId}</a></li> + <li><a href="#d2e6374">http://www.example.com/repo/courses/{courseId}/elements/version</a></li> + <li><a href="#d2e6378">http://www.example.com/repo/courses/{courseId}/elements/structure/{nodeId}</a></li> + <li><a href="#d2e6385">http://www.example.com/repo/courses/{courseId}/elements/structure</a></li> + <li><a href="#d2e6404">http://www.example.com/repo/courses/{courseId}/elements/singlepage/{nodeId}</a></li> + <li><a href="#d2e6411">http://www.example.com/repo/courses/{courseId}/elements/singlepage</a></li> + <li><a href="#d2e6450">http://www.example.com/repo/courses/{courseId}/elements/task/{nodeId}</a></li> + <li><a href="#d2e6466">http://www.example.com/repo/courses/{courseId}/elements/task</a></li> + <li><a href="#d2e6497">http://www.example.com/repo/courses/{courseId}/elements/test/{nodeId}</a></li> + <li><a href="#d2e6512">http://www.example.com/repo/courses/{courseId}/elements/test</a></li> + <li><a href="#d2e6541">http://www.example.com/repo/courses/{courseId}/elements/assessment/{nodeId}</a></li> + <li><a href="#d2e6556">http://www.example.com/repo/courses/{courseId}/elements/assessment</a></li> + <li><a href="#d2e6583">http://www.example.com/repo/courses/{courseId}/elements/wiki/{nodeId}</a></li> + <li><a href="#d2e6598">http://www.example.com/repo/courses/{courseId}/elements/wiki</a></li> + <li><a href="#d2e6626">http://www.example.com/repo/courses/{courseId}/elements/blog/{nodeId}</a></li> + <li><a href="#d2e6641">http://www.example.com/repo/courses/{courseId}/elements/blog</a></li> + <li><a href="#d2e6669">http://www.example.com/repo/courses/{courseId}/elements/survey/{nodeId}</a></li> + <li><a href="#d2e6684">http://www.example.com/repo/courses/{courseId}/elements/survey</a></li> + <li><a href="#d2e6712">http://www.example.com/repo/courses/{courseId}/elements/externalpage/{nodeId}</a></li> + <li><a href="#d2e6727">http://www.example.com/repo/courses/{courseId}/elements/externalpage</a></li> + <li><a href="#d2e6755">http://www.example.com/repo/courses/{courseId}/elements/task/{nodeId}/file</a></li> + <li><a href="#d2e6766">http://www.example.com/repo/courses/{courseId}/elements/task/{nodeId}/configuration</a></li> + <li><a href="#d2e6838">http://www.example.com/repo/courses/{courseId}/elements/survey/{nodeId}/configuration</a></li> + <li><a href="#d2e6869">http://www.example.com/repo/courses/{courseId}/elements/test/{nodeId}/configuration</a></li> </ul> </li> </ul> </li> <li><a href="#representations">Representations</a><ul> - <li><a href="#d2e10">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e32">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - <li><a href="#d2e45"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e51"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e70">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e83"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e89"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e108">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e121"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e127"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e134">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e141">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e154"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e160"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e182">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e39">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e52"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e58"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e67">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>)</a></li> + <li><a href="#d2e80"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e86"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e93">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e121">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e134"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e140"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e154">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e176">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e189"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e195"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e201"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e212">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e225">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e238"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e244"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e251">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e252">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e256">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e269"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e275"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e294">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e307"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e313"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e326">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e332"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e339">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e345">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e351"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e358">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e359">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e363">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e369"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e378">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e384"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e400">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e406"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e413">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e421">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e422">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e426">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e427">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e429">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e430">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e436">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e437">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e441">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e446">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e447">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e449">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e450">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e453">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e454">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e457">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e462">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e465">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e468">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e471">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e476">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e478">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e483">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e484">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e489">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e490">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e495">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e496">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e204">application/xml, application/json (<abbr title="{http://www.example.com} folderVO">ns3:folderVO</abbr>)</a></li> + <li><a href="#d2e217"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e223"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e231">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e232">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e233">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e234">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e235">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e238">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e239">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e242">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e247">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e248">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e251">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e252">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e255">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e256">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e258">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e259">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e264">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e265">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e266">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e267">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e268">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e271">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e272">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e273">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e276">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e281">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e282">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e283">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e286">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e287">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e288">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e291">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e292">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e294">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e295">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e298">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e299">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e302">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e303">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e308">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e309">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e313">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e318">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e319">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e328">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e329">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e342">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e343">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e346">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e347">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e349">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e350">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e353">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e354">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e356">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e357">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e362">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e363">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e367">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e368">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e370">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e371">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e374">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e375">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e376">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e378">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e379">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e390">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e391">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e412">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e413">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e416">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>)</a></li> + <li><a href="#d2e417">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>)</a></li> + <li><a href="#d2e419">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e420">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e423">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e424">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e428">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e433">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e434">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e437">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e438">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e443">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e444">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e447">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e455">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e456">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e461">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e465">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e466">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e470">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e473">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e478">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e482">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e487">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e488">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e491">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e494">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e495">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e499">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e500">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e502">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e505">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e511">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e505">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e506">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e511">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e512">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e514">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e526">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - <li><a href="#d2e539"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e545"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e564">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e577"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e583"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e602">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e615"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e621"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e628">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e635">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e648"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e654"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e676">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e689"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e695"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e706">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e719">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e732"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e738"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e745">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e746">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e750">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e763"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e769"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e517">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e518">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e522">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e523">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e526">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e527">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e529">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e534">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e538">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e542">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e543">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e551">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e552">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e556">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e557">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e560">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e561">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e563">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e564">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e569">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e572">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e575">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e577">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e581">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e586">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e587">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e588">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e589">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e590">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e593">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e594">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e597">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e602">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e603">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e606">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e607">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e610">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e611">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e613">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e614">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e619">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e620">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e621">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e622">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e623">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e626">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e627">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e628">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e631">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e636">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e637">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e638">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e641">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e642">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e643">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e646">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e647">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e649">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e650">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e653">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e654">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e657">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e658">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e663">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e664">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e668">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e679">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e692"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e698"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e717">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e730"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e736"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e755">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e768"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e774"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e781">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e788">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> <li><a href="#d2e801"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e807"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e820">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e826"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e833">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e839">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e845"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e852">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e853">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e857">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e863"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e872">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e878"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e894">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e900"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e907">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e908">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e909">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e910">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e911">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e914">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e915">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e918">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e923">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e924">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e927">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e928">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e931">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e932">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e934">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e935">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e940">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e941">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e942">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e943">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e944">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e947">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e948">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e949">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e952">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e957">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e958">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e959">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e962">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e963">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e964">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e967">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e968">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e970">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e971">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e974">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e975">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e978">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e979">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e983">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e988">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e989">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e998">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e999">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1004">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1012">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1017">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1018">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1022">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1023">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1028">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1029">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1032">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1035">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1038">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1043">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1044">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1048">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1049">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1053">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1054">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1058">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1059">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1063">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1064">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1068">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1069">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e829">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e842"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e848"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e859">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e872">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e885"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e891"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e898">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e899">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e903">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e916"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e922"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e941">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e954"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e960"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e973">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e979"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e986">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e992">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e998"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1005">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e1006">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e1010">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1016"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1025">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1031"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1047">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1053"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1066">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1067">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1070">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1071">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e1073">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e1074">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1078">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1079">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1083">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1084">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1088">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1089">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1093">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1094">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1098">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1099">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1103">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1104">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1108">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1109">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1112">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1115">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1118">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1122">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1125">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1126">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1130">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1133">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1134">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1142">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1143">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1147">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1150">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1151">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1155">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1156">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1160">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1161">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1165">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1166">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1169">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1172">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1175">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1179">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1180">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1184">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1189">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1190">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1203"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1209">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1210">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1216">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1219">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1222">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1226">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1234">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1235">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1240">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1241">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1244">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> - <li><a href="#d2e1245">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> - <li><a href="#d2e1247">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1248">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1256">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1257">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1260">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1265">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1266">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1270">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> - <li><a href="#d2e1271">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> - <li><a href="#d2e1273">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1274">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1281">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1282">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1285">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1286">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1291">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1292">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1303">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1304">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1307">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1308">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1311">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1312">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1321">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1322">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1326">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1331">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1332">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1335">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>)</a></li> - <li><a href="#d2e1336">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>)</a></li> - <li><a href="#d2e1338">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1339">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1342">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1343">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1346">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1347">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1352">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1353">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1356">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1357">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1359">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1365">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1368">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1373">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1374">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1377">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1378">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1380">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1386">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1389">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1394">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1395">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1397">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1400">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1401">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1407">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1410">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1416">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1417">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1422">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1425">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1426">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1431">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1432">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1435">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e1436">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e1438">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1439">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1442">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1443">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e1444">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e1446">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1447">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1451">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1077">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1078">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1080">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1081">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1086">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1087">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1091">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e1092">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e1094">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1095">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1098">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1099">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e1100">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e1102">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1103">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1114">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1128">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1129">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1133">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1147">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1148">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1152">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1172">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> + <li><a href="#d2e1186">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1187">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1191">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> + <li><a href="#d2e1209"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1223">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> + <li><a href="#d2e1237">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> + <li><a href="#d2e1238">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> + <li><a href="#d2e1242">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> + <li><a href="#d2e1256">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> + <li><a href="#d2e1257">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> + <li><a href="#d2e1261">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> + <li><a href="#d2e1279"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1285">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1286">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1289">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e1290">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e1292">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1293">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1296">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1297">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e1298">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e1300">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1301">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1305">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1306">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1309">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1310">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> + <li><a href="#d2e1311">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> + <li><a href="#d2e1313">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1314">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1318">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1322">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1327">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1330">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1331">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1336">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1339">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1343">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1344">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1348">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1351">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1355">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1363">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1364">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1380">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1394">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1395">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1399">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1413">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1414">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1418">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1438">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> <li><a href="#d2e1452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1455">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1456">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> - <li><a href="#d2e1457">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> - <li><a href="#d2e1459">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1460">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1465">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1468">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1473">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1476">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1480">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1484">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1487">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1491">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1496">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1497">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1506">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1507">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1517">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1518">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1522">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e1523">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e1525">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1526">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1529">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1530">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e1531">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e1533">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1534">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1538">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1539">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1541">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1542">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1549">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1550">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1553">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1554">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1556">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1557">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1598">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - <li><a href="#d2e1611"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1617"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1624">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1655">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - <li><a href="#d2e1668"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1674"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1686">application/xml, application/json (<abbr title="{http://www.example.com} groupVO">ns3:groupVO</abbr>)</a></li> - <li><a href="#d2e1699"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1705"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1729">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - <li><a href="#d2e1742"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1748"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1757">application/xml, application/json (<abbr title="{http://www.example.com} forumVOes">ns3:forumVOes</abbr>)</a></li> - <li><a href="#d2e1770"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1776"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1783">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1797">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - <li><a href="#d2e1810"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1816"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1832">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - <li><a href="#d2e1845"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1851"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1880">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e1893"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1899"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1928">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e1941"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1947"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1961">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - <li><a href="#d2e1974"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1980"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1999">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e2012"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2018"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2037">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e2050"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2056"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2063">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2070">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1453">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1457">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> + <li><a href="#d2e1475"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1484">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1485">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1488">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e1489">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e1491">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1492">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1497">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1498">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1501">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e1502">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e1504">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1505">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1508">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1513">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1516">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1519">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1522">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1527">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e1529">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1534">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1535">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1540">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1541">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1546">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1547">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1553">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1556">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1562">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1565">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1569">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1579">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1580">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1585">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1586">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1587">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1588">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1589">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1592">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1593">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1596">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1601">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1602">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1605">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1606">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1609">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e1610">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e1612">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1613">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1618">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1619">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1620">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1621">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1622">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1625">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1626">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1627">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1630">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1635">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1636">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1637">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1640">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1641">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1642">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1645">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e1646">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e1648">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1649">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1652">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1653">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1656">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1657">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1662">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1663">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1667">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1678">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e1691"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1697"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1716">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e1729"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1735"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1754">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1767"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1773"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1780">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1787">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1800"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1806"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1828">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e1841"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1847"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1858">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1871">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1884"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1890"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1897">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e1898">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e1902">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1915"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1921"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1940">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1953"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1959"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1972">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1978"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1985">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1991">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1997"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2004">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e2005">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e2009">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2015"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2024">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2030"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2046">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2052"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2072">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> <li><a href="#d2e2083"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2089"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2111">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e2090">text/plain, text/html (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> + <li><a href="#d2e2101"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2108">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2113"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2120"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e2124"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2130"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2141">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2154">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e2167"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2173"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2180">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e2181">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e2185">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e2198"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2204"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2223">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e2236"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2242"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2255">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2261"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2268">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2274">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2280"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2287">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e2288">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e2292">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2298"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2307">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2313"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2329">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2335"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2355">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2368"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2374">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>)</a></li> - <li><a href="#d2e2375">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>)</a></li> - <li><a href="#d2e2377">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2382">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2389">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2390">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2395">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2401">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2406">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2411">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2412">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2413">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2414">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2415">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2418">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2419">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2422">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2427">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2428">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2431">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2432">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2435">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e2436">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e2438">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2439">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2444">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2445">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2446">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2447">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2448">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2451">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2453">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2456">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2461">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2462">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2463">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2466">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2467">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2468">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2471">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e2472">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e2474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2475">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2478">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2479">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2482">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2483">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2487">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2492">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2493">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2504">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>)</a></li> - <li><a href="#d2e2505">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>)</a></li> - <li><a href="#d2e2509">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>)</a></li> - <li><a href="#d2e2522"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2528"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2128"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2139"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2153">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> + <li><a href="#d2e2167">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> + <li><a href="#d2e2168">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> + <li><a href="#d2e2170"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2177">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> + <li><a href="#d2e2178">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> + <li><a href="#d2e2180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2197"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2201"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2205"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2213">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2227">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2233">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2234">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2235">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2236">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2241">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2247">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2248">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2249">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2250">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2253">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2256">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2261">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2264">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2267">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2278">application/xml, application/json (<abbr title="{http://www.example.com} forumVOes">ns3:forumVOes</abbr>)</a></li> + <li><a href="#d2e2291"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2297"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2304">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2318">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e2331"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2337"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2357">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e2370"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2376"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2392">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e2405"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2411"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2440">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e2453"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2459"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2488">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e2501"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2507"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2521">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> <li><a href="#d2e2534"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e2540"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2547">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>)</a></li> - <li><a href="#d2e2558"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2562"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2559">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e2572"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e2578"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2584"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2590"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2601">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2608"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2614"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2620"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2626"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2636">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2663">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> - <li><a href="#d2e2674"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2685"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2692">text/plain, text/html (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> - <li><a href="#d2e2703"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2710">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2715"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2722"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2726"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2730"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2744">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> - <li><a href="#d2e2745">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> - <li><a href="#d2e2747"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2754">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> - <li><a href="#d2e2768">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> - <li><a href="#d2e2769">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> - <li><a href="#d2e2771"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2779">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2803"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2807"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2811"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2825"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2829"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2836">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2841"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2845"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2858">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2859">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2862">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>)</a></li> - <li><a href="#d2e2863">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>)</a></li> - <li><a href="#d2e2865">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2866">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2887">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2888">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2891">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2892">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2896">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2901">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2902">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2905">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2906">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2910">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2915">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2916">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2919">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2927">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2928">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2932">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2933">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2936">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2937">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2939">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2943">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2944">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2952">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2953">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2957">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2958">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2961">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2962">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2964">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2968">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2969">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2972">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2973">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2975">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2980">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2985">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2986">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2990">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2993">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2994">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2998">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3002">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3007">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3008">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3011">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3014">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3015">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3020">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3024">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e3025">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e3027">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3028">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3031">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3032">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3036">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3041">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3044">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e3046">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3049">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3060">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - <li><a href="#d2e3073"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3079"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3098">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e3111"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3117"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3136">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e2597">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e2610"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2616"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2623">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2630">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e2643"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2649"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2671">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e2684"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2690"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2701">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2714">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e2727"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2733"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2740">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e2741">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e2745">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e2758"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2764"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2783">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e2796"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2802"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2815">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2821"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2828">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2834">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2840"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2847">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e2848">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e2852">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2858"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2867">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2873"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2889">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2895"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2910">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e2923"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2937">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e2950"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2956"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2975">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e2988"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2994"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3013">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3026"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3032"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3039">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3046">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3059"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3065"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3087">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e3100"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3106"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3117">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3130">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3143"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e3149"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3155"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3162">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3169">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e3182"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3188"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3210">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e3223"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3229"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3240">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3253">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e3266"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3272"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3279">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e3280">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e3284">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e3297"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3303"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3322">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e3335"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3341"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3354">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3360"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3367">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3373">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3379"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3386">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e3387">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e3391">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3397"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3406">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3412"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3428">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3434"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3441">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3442">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3443">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3444">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3445">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3448">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3449">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3452">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3457">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3458">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3461">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3462">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3465">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e3466">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e3468">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3469">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3475">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3476">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3477">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3478">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3481">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3482">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3483">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3486">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3491">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3492">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3493">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3496">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3497">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3498">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3501">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e3502">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e3504">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3505">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3508">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3509">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3512">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3513">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3517">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3522">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3523">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3531">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3532">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3536">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e3537">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e3539">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3540">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3543">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3544">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e3545">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e3547">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3548">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3552">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3553">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3555">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3556">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3563">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3564">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3567">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3568">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3570">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3571">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3582">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e3596">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e3597">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e3601">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e3615">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e3616">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e3620">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e3640">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> - <li><a href="#d2e3654">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3655">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3659">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> - <li><a href="#d2e3677"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3691">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> - <li><a href="#d2e3705">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> - <li><a href="#d2e3706">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> - <li><a href="#d2e3710">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> - <li><a href="#d2e3724">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> - <li><a href="#d2e3725">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> - <li><a href="#d2e3729">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> - <li><a href="#d2e3747"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3753">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3754">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3757">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e3758">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e3760">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3761">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3764">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3765">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e3766">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e3768">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3769">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3773">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3774">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3777">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3778">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> - <li><a href="#d2e3779">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> - <li><a href="#d2e3781">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3782">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3787">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3790">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3795">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3798">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3802">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3806">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3809">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3813">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3821">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3822">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3833">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3834">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3842">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3843">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3848">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3852">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3857">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3862">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3866">application/xhtml+xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3867">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3870">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3874">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3875">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3888">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3895">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3901"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3907"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3912">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3929"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3935"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3941"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3947"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3956"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3962"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3968"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3984">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - <li><a href="#d2e3997"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4011">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - <li><a href="#d2e4024"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4030"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4049">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e4062"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4068"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4087">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4100"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4106"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4113">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4120">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4133"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4139"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4161">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e4174"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4191">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4204">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4217"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4223"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4230">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e4231">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e4235">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4248"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4254"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4273">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4286"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4292"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4305">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4311"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4318">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4324">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4330"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4337">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e4338">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e4342">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4348"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4357">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4363"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4379">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4385"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4398">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - <li><a href="#d2e4411"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4417"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4436">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e4449"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4455"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4474">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4487"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4493"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4500">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4507">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4520"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4526"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4548">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - <li><a href="#d2e4561"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4567"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4578">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4591">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4604"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4610"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4617">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e4618">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e4622">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4635"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4641"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4660">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - <li><a href="#d2e4673"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4679"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4692">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4698"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4705">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4711">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4717"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4724">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e4725">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e4729">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4735"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4744">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4750"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4766">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4772"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4790">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e4804">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e4805">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e4809">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e4823">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e4824">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e4828">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e4848">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> - <li><a href="#d2e4862">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4863">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4867">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> - <li><a href="#d2e4885"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4895">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> - <li><a href="#d2e4896">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> - <li><a href="#d2e4900">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4913"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4919">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4940">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>)</a></li> - <li><a href="#d2e4953"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4964">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> - <li><a href="#d2e4965">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> - <li><a href="#d2e4969">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>)</a></li> - <li><a href="#d2e4982"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4988"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4994">application/xml, application/json (<abbr title="{http://www.example.com} errorVO">ns3:errorVO</abbr>)</a></li> - <li><a href="#d2e5010"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5016"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5022"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5035">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5048"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5054"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5067">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5080"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5086"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5093">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>)</a></li> - <li><a href="#d2e5094">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>)</a></li> - <li><a href="#d2e5098">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5111"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5117"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5130">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5143"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5149"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5156">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>)</a></li> - <li><a href="#d2e5157">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>)</a></li> - <li><a href="#d2e5161">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5174"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5190">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5210">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5216"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5225">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5231"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5240">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5246"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5252"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5261"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5267"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5273">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5274">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5285">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5298"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5304"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5311">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>)</a></li> - <li><a href="#d2e5312">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>)</a></li> - <li><a href="#d2e5316">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5329"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5335"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5347">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5353"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5367">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>)</a></li> - <li><a href="#d2e5380"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5388">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5389">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5390">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5391">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5392">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5395">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5396">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5399">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5404">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5405">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5408">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5409">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5412">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5413">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5415">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5416">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5421">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5422">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5423">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5424">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5425">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5428">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5429">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5430">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5433">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5438">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5439">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5440">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5443">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5444">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5445">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5448">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5449">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5451">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5455">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5456">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5459">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5460">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5464">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5469">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5470">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5475">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5476">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5477">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5478">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5481">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5482">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5485">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5490">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5491">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5494">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5495">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5498">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5499">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5501">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5502">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5507">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5508">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5509">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5510">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5511">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5514">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5515">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5516">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5519">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5524">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5525">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5526">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5529">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5530">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5531">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5534">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5535">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5537">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5538">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5541">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5542">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5545">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5546">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5550">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5555">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5556">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5561">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5562">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5563">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5564">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5565">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5568">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5569">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5572">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5577">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5578">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5581">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5582">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5585">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5586">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5588">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5589">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5594">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5595">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5596">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5597">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5598">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5601">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5602">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5603">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5606">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5611">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5612">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5613">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5616">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5617">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5618">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5621">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5622">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5624">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5625">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5628">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5629">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5632">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5633">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5637">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5642">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5643">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5660">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> - <li><a href="#d2e5673"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5690">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> - <li><a href="#d2e5703"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5720">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> - <li><a href="#d2e5733"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5745">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5746">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5755">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5756">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5765">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5766">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5775">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5776">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5781">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5782">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5786">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5792">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5793">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5799">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5800">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5803">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>)</a></li> - <li><a href="#d2e5804">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>)</a></li> - <li><a href="#d2e5806">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5813">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5814">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5827">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>)</a></li> - <li><a href="#d2e5840"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5846"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5880">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - <li><a href="#d2e5893"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5899"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5906">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5934">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - <li><a href="#d2e5947"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5953"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5967">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5989">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - <li><a href="#d2e6002"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6008"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6017">application/xml, application/json (<abbr title="{http://www.example.com} folderVO">ns3:folderVO</abbr>)</a></li> - <li><a href="#d2e6030"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6036"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6044">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6045">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6046">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6047">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6048">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6051">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6052">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6055">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6060">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6061">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6064">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6065">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6068">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e6069">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e6071">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6072">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6077">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6078">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6079">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6080">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6081">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3156">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e3157">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e3161">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3174"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3199">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3212"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3218"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3231">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3237"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3244">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3250">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3256"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3263">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e3264">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e3268">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3274"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3283">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3289"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3305">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3311"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3324">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e3337"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3343"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3362">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e3375"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3381"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3400">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3413"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3419"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3426">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3433">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3446"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3452"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3474">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e3487"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3493"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3504">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3517">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3530"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3536"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3543">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e3544">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e3548">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3561"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3567"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3586">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3599"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3605"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3618">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3624"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3631">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3637">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3643"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3650">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e3651">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e3655">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3661"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3670">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3676"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3692">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3698"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3713">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3720">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3726"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3732"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3737">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3754"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3760"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3766"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3772"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3781"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3787"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3793"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3800">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3804">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3809">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3823">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3829"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3836">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3837">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3843">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3844">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3850">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3851">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3854">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>)</a></li> + <li><a href="#d2e3855">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>)</a></li> + <li><a href="#d2e3857">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3861">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3868">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3869">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3877">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3878">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3889">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3890">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3901">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>)</a></li> + <li><a href="#d2e3902">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>)</a></li> + <li><a href="#d2e3906">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>)</a></li> + <li><a href="#d2e3919"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3925"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3931"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3937"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3944">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>)</a></li> + <li><a href="#d2e3955"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3959"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3975"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3981"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3987"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3998">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4005"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4011"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4017"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4023"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4033">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4046">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4047">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4064">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4077"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4083">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>)</a></li> + <li><a href="#d2e4084">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>)</a></li> + <li><a href="#d2e4086">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4091">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4098">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4099">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4108">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4112">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4123">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4124">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4127">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4128">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4131">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4132">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4141">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4142">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4146">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4151">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4152">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4155">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4156">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4159">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>)</a></li> + <li><a href="#d2e4160">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>)</a></li> + <li><a href="#d2e4162">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4163">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4166">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4167">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4173">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4176">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4181">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4182">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4184">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4187">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4188">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4193">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4194">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4199">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4202">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4203">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4208">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4209">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4212">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4213">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4215">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4221">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4224">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4230">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4231">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4233">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4236">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4237">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4243">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4246">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4251">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4252">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4255">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e4256">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e4258">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4259">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4262">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4263">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e4264">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e4266">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4267">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4271">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4272">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4275">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4276">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> + <li><a href="#d2e4277">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> + <li><a href="#d2e4279">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4280">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4284">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4288">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4293">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4296">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4297">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4302">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4305">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4309">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4310">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4314">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4317">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4321">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4376">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e4389"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4395"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4402">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4425">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e4438"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4444"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4451">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4456">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4461">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4465">application/xhtml+xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4466">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4469">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4473">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4515">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e4528"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4534"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4541">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4572">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e4585"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4591"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4603">application/xml, application/json (<abbr title="{http://www.example.com} groupVO">ns3:groupVO</abbr>)</a></li> + <li><a href="#d2e4616"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4622"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4628">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4629">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4637">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4638">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4644">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4647">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4650">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4655">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4656">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4659">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> + <li><a href="#d2e4660">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> + <li><a href="#d2e4662">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4663">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4671">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4672">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4675">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4680">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4681">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4685">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> + <li><a href="#d2e4686">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> + <li><a href="#d2e4688">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4689">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4696">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4697">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4700">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4701">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4706">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4707">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4711">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4716">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4717">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4721">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4722">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4727">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4728">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4731">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4734">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4737">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4741">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4742">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4747">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4748">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4752">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4757">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4758">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4762">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4763">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4767">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4768">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4772">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4773">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4777">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4778">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4782">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4783">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4787">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4788">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4792">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4793">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4797">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4798">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4802">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4803">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4807">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4808">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4812">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4813">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4817">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4818">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4822">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4823">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4826">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4829">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4832">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4836">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4839">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4840">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4844">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4847">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4848">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4856">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4857">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4861">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4864">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4865">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4869">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4870">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4874">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4875">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4879">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4880">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4883">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4886">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4889">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4901"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4905"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4912">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4917"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4921"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4928">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4934">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4939">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4944">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4945">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4946">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4947">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4948">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4951">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4952">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4955">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4960">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4961">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4964">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4965">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4968">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e4969">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e4971">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4972">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4977">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4978">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4979">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4980">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4981">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4984">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4985">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4986">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4989">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4994">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4995">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4996">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4999">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5000">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5001">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5004">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5005">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5007">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5008">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5011">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5012">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5015">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5016">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5021">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5022">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5026">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5035">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5057">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e5070"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5076"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5095">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e5108"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5114"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5133">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e5146"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5152"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5159">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5166">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e5179"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5185"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5207">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e5220"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5226"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5237">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5250">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e5263"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5269"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5276">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e5277">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e5281">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e5294"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5300"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5319">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e5332"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5338"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5351">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5357"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5364">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5370">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5376"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5383">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5384">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5388">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5394"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5403">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5409"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5425">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5431"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5442">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5443">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5447">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5455">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> + <li><a href="#d2e5456">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> + <li><a href="#d2e5460">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5473"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5479">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5500">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>)</a></li> + <li><a href="#d2e5513"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5524">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> + <li><a href="#d2e5525">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> + <li><a href="#d2e5529">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>)</a></li> + <li><a href="#d2e5542"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5548"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5554">application/xml, application/json (<abbr title="{http://www.example.com} errorVO">ns3:errorVO</abbr>)</a></li> + <li><a href="#d2e5570"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5576"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5582"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5595">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5608"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5614"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5627">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5633"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5642">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5648"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5657">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5663"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5669"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5678"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5684"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5697">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5710"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5716"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5723">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>)</a></li> + <li><a href="#d2e5724">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>)</a></li> + <li><a href="#d2e5728">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5741"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5747"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5760">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5773"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5779"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5786">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>)</a></li> + <li><a href="#d2e5787">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>)</a></li> + <li><a href="#d2e5791">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5804"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5810"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5816">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5817">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5828">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5841"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5847"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5854">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>)</a></li> + <li><a href="#d2e5855">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>)</a></li> + <li><a href="#d2e5859">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5872"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5878"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5890">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5896"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5906">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5927">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>)</a></li> + <li><a href="#d2e5940"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5948">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5949">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5950">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5951">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5952">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5955">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5956">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5959">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5964">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5965">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5968">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5969">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5972">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5973">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5975">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5976">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5981">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5982">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5983">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5984">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5985">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5988">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5989">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5990">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5993">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5998">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5999">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6000">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6003">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6004">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6005">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6008">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6009">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6011">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6012">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6015">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6016">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6019">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6020">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6025">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6026">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6030">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6034">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6035">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6036">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6037">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6038">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6041">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6042">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6045">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6050">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6051">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6054">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6055">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6058">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6059">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6061">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6062">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6067">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6068">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6069">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6070">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6071">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6074">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6075">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6076">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6079">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e6084">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e6085">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e6086">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6089">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6094">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6095">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6096">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6099">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6100">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6101">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6104">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e6105">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e6107">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6108">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6089">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6090">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6091">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6094">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6095">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6097">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6098">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6101">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6102">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6105">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6106">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e6111">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e6112">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6115">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6116">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6120">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6125">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6126">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6137">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6160">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - <li><a href="#d2e6173"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6179"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6232">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - <li><a href="#d2e6245"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6251"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6258">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6264">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6265">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6271">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6272">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6277">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6278">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6290">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6291">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6297">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6298">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6303">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6314">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6315">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6318">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6319">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6322">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6323">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6336">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6337">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6343">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6352">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6353">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6358">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6369">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6370">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6116">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6121">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6122">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6123">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6124">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6125">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6128">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6129">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6132">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6137">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6138">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6141">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6142">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6145">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6146">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6148">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6149">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6154">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6155">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6156">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6157">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6158">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6161">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6162">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6163">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6166">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6171">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6172">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6173">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6176">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6177">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6178">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6181">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6182">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6184">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6185">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6188">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6189">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6192">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6193">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6198">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6199">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6203">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6220">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> + <li><a href="#d2e6233"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6250">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> + <li><a href="#d2e6263"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6280">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> + <li><a href="#d2e6293"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6305">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6306">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6315">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6316">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6325">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6326">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6335">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6336">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6343">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6344">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6349">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6350">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6363"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6372">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6373">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6377">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e6383">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e6384">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6390">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6398">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6399">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6404">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6414">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6415">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6427">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6428">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6434">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6441">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6442">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6448">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6457">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6458">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6469">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6470">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6476">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6484">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6485">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6499">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6500">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6512">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6513">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6519">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6527">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6528">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6542">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6543">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6555">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6556">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6562">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6570">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6571">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6585">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6586">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6598">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6599">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6605">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6613">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6614">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6628">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6629">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6641">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6642">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6648">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6649">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6652">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6653">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6687">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6688">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6719">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6720">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6723">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6724">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6739">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6740">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6751">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6752">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6755">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6756">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6781">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6782">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6804">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6805">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6808">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6809">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6813">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6817">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6822">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6829">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6830">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6389">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6390">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6402">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6403">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6409">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6410">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6415">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6426">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6427">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6430">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6431">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6434">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6435">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6448">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6449">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6455">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6464">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6465">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6470">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6481">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6482">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6495">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6496">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6502">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6510">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6511">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6516">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6526">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6527">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6539">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6540">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6546">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6553">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6554">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6560">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6569">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6570">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6581">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6582">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6588">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6596">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6597">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6611">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6612">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6624">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6625">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6631">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6639">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6640">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6654">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6655">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6667">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6668">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6674">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6682">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6683">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6697">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6698">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6710">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6711">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6717">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6725">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6726">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6740">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6741">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6753">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6754">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6760">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6761">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6764">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6765">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6799">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6800">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6831">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6832">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e6835">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> <li><a href="#d2e6836">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6850">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6856"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6863">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6869">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6870">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6871">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6872">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6877">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6883">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6884">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6885">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6886">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6889">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6892">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6897">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6900">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6903">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6851">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6852">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6863">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6864">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6867">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6868">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6893">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6894">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6916">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6917">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6920">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6921">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </li> </ul> <h2 id="resources">Resources</h2> <div class="resource"> - <h3 id="d2e2">/repo/forums</h3> - <p>Description:<br> - Web service to manage forums. - - <P> - Initial Date: 26 aug. 2010 <br> - </p> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e5">/repo/forums/version</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p>The version of the Forum Web Service</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e10">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e20">/repo/forums/{forumKey}</h3> + <h3 id="d2e2">/repo/courses/{courseId}/elements/folder<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&downloadExpertRules</span><span class="optional">&uploadExpertRules</span></h3> <p>Description:<br> - Web service to manage a forum. <P> - Initial Date: 20 apr. 2010 <br> + Initial Date: 6 févr. 2012 <br> </p> <h6>resource-wide template parameters</h6> <table> @@ -1920,62 +1906,23 @@ </tr> <tr> <td> - <p><strong>forumKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The key of the forum</p> - </td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getForum">GET</h4> - <p>Retrieves the forum.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e32">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e45"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e51"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e54">/repo/forums/{forumKey}/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>forumKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p>The key of the forum</p> + <p>The course resourceable's id</p> </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getThreads">GET</h4> - <p>Retrieves the threads in the forum</p> + <h4 id="http://www.example.com#attachFolder">PUT</h4> + <p>This attaches a Folder Element onto a given course. The element will be + inserted underneath the supplied parentNodeId. + </p> <h6>request query parameters</h6> <table> <tr> @@ -1985,143 +1932,151 @@ </tr> <tr> <td> - <p><strong>start</strong></p> + <p><strong>parentNodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The node's id which will be the parent of this folder</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>limit</strong></p> + <p><strong>position</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> </td> - <td></td> + <td> + <p>The node's position relative to its sibling nodes (optional)</p> + </td> </tr> <tr> <td> - <p><strong>orderBy</strong></p> + <p><strong>shortTitle</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>creationDate</tt></p> + <p>Default: <tt>undefined</tt></p> </td> <td> - <p>(value name,creationDate)</p> + <p>The node short title</p> </td> </tr> <tr> <td> - <p><strong>asc</strong></p> + <p><strong>longTitle</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>true</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> </td> <td> - <p>(value true/false)</p> + <p>The node long title</p> </td> </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e70">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e83"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e89"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#newThreadToForum">PUT</h4> - <p>Creates a new thread in the forum of the course node</p> - <h6>request query parameters</h6> - <table> <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p><strong>objectives</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td> + <p>The node learning objectives</p> + </td> </tr> <tr> <td> - <p><strong>title</strong></p> + <p><strong>visibilityExpertRules</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The title for the first post in the thread</p> + <p>The rules to view the node (optional)</p> </td> </tr> <tr> <td> - <p><strong>body</strong></p> + <p><strong>downloadExpertRules</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The body for the first post in the thread</p> + <p>The rules to download files (optional)</p> </td> </tr> <tr> <td> - <p><strong>authorKey</strong></p> + <p><strong>uploadExpertRules</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The author user key (optional)</p> + <p>The rules to upload files (optional)</p> </td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e108">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e39">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e121"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e52"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e127"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e58"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#newThreadToForumPost">POST</h4> - <p>Creates a new thread in the forum of the course node</p> + <h4 id="http://www.example.com#getFolders">GET</h4> + <p>Retrieves metadata of the course node</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e67">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e80"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e86"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachFolderPost">POST</h4> + <p>This attaches a Folder Element onto a given course. The element will be + inserted underneath the supplied parentNodeId. + </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e134">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e93">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e141">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e121">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e154"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e134"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e160"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e140"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e163">/repo/forums/{forumKey}/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> + <h3 id="d2e143">/repo/courses/{courseId}/elements/folder/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -2131,101 +2086,80 @@ </tr> <tr> <td> - <p><strong>forumKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p>The key of the forum</p> + <p>The course resourceable's id</p> </td> </tr> <tr> <td> - <p><strong>threadKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p>The key of the thread</p> + <p>The course resourceable's id</p> </td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getMessages">GET</h4> - <p>Retrieves the messages in the thread</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>orderBy</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>creationDate</tt></p> - </td> - <td> - <p>(value name, creationDate)</p> - </td> - </tr> - <tr> - <td> - <p><strong>asc</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>true</tt></p> - </td> - <td> - <p>(value true/false)</p> - </td> - </tr> - </table> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The node's id</p> + </td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#updateFolder">POST</h4> + <p>This updates a Folder Element onto a given course.</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e154">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e176">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e182">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e189"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> <li><a href="#d2e195"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getFolder">GET</h4> + <p>Retrieves metadata of the course node</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e204">application/xml, application/json (<abbr title="{http://www.example.com} folderVO">ns3:folderVO</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e201"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e217"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e223"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e204">/repo/forums/{forumKey}/posts/{messageKey}</h3> + <h3 id="d2e226">/repo/courses/{courseId}/elements/folder/{nodeId}/files</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -2235,131 +2169,92 @@ </tr> <tr> <td> - <p><strong>forumKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p>The key of the forum</p> + <p>The course resourceable's id</p> </td> </tr> <tr> <td> - <p><strong>messageKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> <td> - <p>The id of the reply message</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#replyToPostPost">POST</h4> - <p>Creates a new reply in the forum of the course node</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e212">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e225">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e238"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e231">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e232">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e233">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e234">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e235">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFileToRoot">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e244"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e238">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e239">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#replyToPost">PUT</h4> - <p>Creates a new reply in the forum of the course node</p> + <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e251">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e252">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e256">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e242">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e269"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e275"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e247">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e248">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#replyToPost">PUT</h4> - <p>Creates a new reply in the forum of the course node</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>title</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The title for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>body</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The body for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>authorKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The author user key (optional)</p> - </td> - </tr> - </table> + <h4 id="http://www.example.com#putFileToRoot">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e294">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e251">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e252">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - <p><em>available response representations:</em></p> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e307"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e255">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e256">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e313"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e258">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e259">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e316">/repo/forums/{forumKey}/posts/{messageKey}/attachments</h3> + <h3 id="d2e260">/repo/courses/{courseId}/elements/folder/{nodeId}/files/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -2369,99 +2264,120 @@ </tr> <tr> <td> - <p><strong>forumKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p>The key of the forum</p> + <p>The course resourceable's id</p> </td> </tr> <tr> <td> - <p><strong>messageKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>The key of the message</p> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>path</strong></p> </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAttachments">GET</h4> - <p>Retrieves the attachments of the message</p> + <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e326">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e264">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e265">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e266">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e267">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e268">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFileToFolder">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e332"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e271">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e272">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e273">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> + <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e339">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e276">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e345">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e281">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e282">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e283">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e351"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e286">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e287">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e288">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">PUT</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> + <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e358">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e359">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e363">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e291">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e292">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e369"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e294">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e295">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> + <h4 id="http://www.example.com#putFolders">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e378">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e298">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e299">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e384"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e302">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e303">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e387">/repo/forums/{forumKey}/posts/{messageKey}/attachments/{filename}</h3> + <h3 id="d2e304">/repo/courses/{courseId}/elements/folder/{nodeId}/files/metadata/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -2471,74 +2387,107 @@ </tr> <tr> <td> - <p><strong>forumKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p>The key of the forum</p> + <p>The course resourceable's id</p> </td> </tr> <tr> <td> - <p><strong>messageKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The identity key of the user being searched</p> - </td> + <td></td> </tr> <tr> <td> - <p><strong>filename</strong></p> + <p><strong>nodeId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>path</strong></p> + </td> <td> - <p>The name of the attachment</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAttachment">GET</h4> - <p>Retrieves the attachment of the message</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e400">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getFileMetadata">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e406"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e308">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e309">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e409">/auth</h3> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e410">/auth/version</h3> + <h3 id="d2e310">/repo/courses/{courseId}/elements/folder/{nodeId}/files/version</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The course resourceable's id</p> + </td> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e413">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e313">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e414">/auth/{username}<span class="optional">?password</span><span class="optional">&x-olat-token</span></h3> + <h3 id="d2e314">/users/{identityKey}/calendars</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -2548,10 +2497,10 @@ </tr> <tr> <td> - <p><strong>username</strong></p> + <p><strong>identityKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -2559,60 +2508,47 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#login">GET</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>password</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>x-olat-token</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - </table> + <h4 id="http://www.example.com#getCalendars">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e421">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e422">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e318">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e319">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e423">/groups</h3> + <h3 id="d2e320">/users/{identityKey}/calendars/events<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&onlyFuture</span></h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#createGroup">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e426">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e427">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e429">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e430">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getGroupList">GET</h4> + <h4 id="http://www.example.com#getEvents">GET</h4> <h6>request query parameters</h6> <table> <tr> @@ -2622,46 +2558,46 @@ </tr> <tr> <td> - <p><strong>externalId</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>managed</strong></p> + <p><strong>limit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>onlyFuture</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>false</tt></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e436">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e437">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e328">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e329">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e438">/groups/version</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e441">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e442">/groups/{groupKey}</h3> + <h3 id="d2e330">/users/{identityKey}/calendars/{calendarId}</h3> + <p>Initial date: 23.12.2015<br></p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -2671,7 +2607,25 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>calendarId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -2680,39 +2634,10 @@ </tr> </table> <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#postGroup">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e446">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e447">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e449">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e450">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#findById">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e453">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e454">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#deleteGroup">DELETE</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e457">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> + <div class="methods"></div> </div> <div class="resource"> - <h3 id="d2e458">/groups/{groupKey}/news</h3> + <h3 id="d2e335">/users/{identityKey}/calendars/{calendarId}/events<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&onlyFuture</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -2722,7 +2647,25 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>calendarId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -2733,34 +2676,81 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getNews">GET</h4> + <h4 id="http://www.example.com#getEventsByCalendar">GET</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>start</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>limit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>onlyFuture</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>false</tt></p> + </td> + <td></td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e462">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e342">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e343">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postNews">POST</h4> + <h4 id="http://www.example.com#putEventsByCalendar">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e465">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e346">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e347">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e468">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e349">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e350">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#deleteNews">DELETE</h4> + <h4 id="http://www.example.com#postEventsByCalendar">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e353">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e354">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e471">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e356">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e357">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e472">/groups/{groupKey}/configuration</h3> + <h3 id="d2e358">/users/{identityKey}/calendars/{calendarId}/events/{eventId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -2770,106 +2760,37 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#postGroupConfiguration">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e476">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e478">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e479">/groups/{groupKey}/infos</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>calendarId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getInformations">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e483">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e484">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e485">/groups/{groupKey}/owners</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getTutors">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e489">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e490">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e491">/groups/{groupKey}/participants</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>eventId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> @@ -2877,17 +2798,17 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getParticipants">GET</h4> + <h4 id="http://www.example.com#deleteEventByCalendar">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e495">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e496">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e362">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e363">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e497">/groups/{groupKey}/owners/{identityKey}</h3> + <h3 id="d2e364">/users/{identityKey}/calendars/{calendarId}/event</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -2906,41 +2827,13 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>calendarId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#addTutor">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e502">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#removeTutor">DELETE</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e505">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e506">/groups/{groupKey}/participants/{identityKey}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> <tr> <td> <p><strong>identityKey</strong></p> @@ -2950,103 +2843,44 @@ </td> <td></td> </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#addParticipant">PUT</h4> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#putEventByCalendar">PUT</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e511">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e367">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e368">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#removeParticipant">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e514">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e370">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e371">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e516">/groups/{groupKey}/forum</h3> - <p>Description:<br> - Web service to manage a forum. - - <P> - Initial Date: 20 apr. 2010 <br> - </p> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getForum">GET</h4> - <p>Retrieves the forum.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e526">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#postEventByCalendar">POST</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e539"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e374">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e375">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e376">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e545"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e378">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e379">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e548">/groups/{groupKey}/forum/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> + <h3 id="d2e380">/repo/courses<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&managed</span><span class="optional">&externalId</span><span class="optional">&externalRef</span><span class="optional">&repositoryEntryKey</span></h3> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getThreads">GET</h4> - <p>Retrieves the threads in the forum</p> + <h4 id="http://www.example.com#getCourseList">GET</h4> <h6>request query parameters</h6> <table> <tr> @@ -3076,45 +2910,49 @@ </tr> <tr> <td> - <p><strong>orderBy</strong></p> + <p><strong>managed</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>creationDate</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>externalId</strong></p> </td> <td> - <p>(value name,creationDate)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>asc</strong></p> + <p><strong>externalRef</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>true</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>repositoryEntryKey</strong></p> </td> <td> - <p>(value true/false)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e564">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e577"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e583"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e390">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e391">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#newThreadToForum">PUT</h4> - <p>Creates a new thread in the forum of the course node</p> + <h4 id="http://www.example.com#createEmptyCourse">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -3122,6 +2960,15 @@ <th>value</th> <th>description</th> </tr> + <tr> + <td> + <p><strong>shortTitle</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> <tr> <td> <p><strong>title</strong></p> @@ -3129,172 +2976,180 @@ <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>The title for the first post in the thread</p> + <p><strong>displayName</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>body</strong></p> + <p><strong>description</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>softKey</strong></p> + </td> <td> - <p>The body for the first post in the thread</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>authorKey</strong></p> + <p><strong>access</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>The author user key (optional)</p> + <p><strong>membersOnly</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> </td> + <td></td> </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e602">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e615"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e621"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#newThreadToForumPost">POST</h4> - <p>Creates a new thread in the forum of the course node</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e628">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e635">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e648"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e654"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e657">/groups/{groupKey}/forum/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>threadKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The key of the thread</p> - </td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getMessages">GET</h4> - <p>Retrieves the messages in the thread</p> - <h6>request query parameters</h6> - <table> <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p><strong>externalId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> </tr> <tr> <td> - <p><strong>start</strong></p> + <p><strong>externalRef</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>limit</strong></p> + <p><strong>authors</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>orderBy</strong></p> + <p><strong>location</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>creationDate</tt></p> </td> + <td></td> + </tr> + <tr> <td> - <p>(value name, creationDate)</p> + <p><strong>managedFlags</strong></p> </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> </tr> <tr> <td> - <p><strong>asc</strong></p> + <p><strong>sharedFolderSoftKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>true</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>copyFrom</strong></p> </td> <td> - <p>(value true/false)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>initialAuthor</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>setAuthor</strong></p> </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>true</tt></p> + </td> + <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e676">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e412">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e413">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#createEmptyCourse">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e416">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>)</a></li> + <li><a href="#d2e417">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e419">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e420">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#importCourse">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e689"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e423">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e424">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e425">/repo/courses/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e695"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e428">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e698">/groups/{groupKey}/forum/posts/{messageKey}</h3> + <h3 id="d2e429">/repo/courses/{courseId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -3304,129 +3159,36 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>messageKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The id of the reply message</p> - </td> - </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#replyToPostPost">POST</h4> - <p>Creates a new reply in the forum of the course node</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e706">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e719">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e732"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e738"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPost">PUT</h4> - <p>Creates a new reply in the forum of the course node</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e745">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e746">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e750">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e763"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#deleteCourse">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e769"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e433">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e434">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#replyToPost">PUT</h4> - <p>Creates a new reply in the forum of the course node</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>title</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The title for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>body</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The body for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>authorKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The author user key (optional)</p> - </td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e788">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e801"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#findById">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e807"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e437">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e438">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e810">/groups/{groupKey}/forum/posts/{messageKey}/attachments</h3> + <h3 id="d2e439">/repo/courses/{courseId}/configuration</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -3436,7 +3198,7 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -3445,88 +3207,40 @@ </tr> <tr> <td> - <p><strong>messageKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The key of the message</p> - </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAttachments">GET</h4> - <p>Retrieves the attachments of the message</p> + <h4 id="http://www.example.com#getConfiguration">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e820">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e443">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e444">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#updateConfiguration">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e447">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e826"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e833">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e839">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e845"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">PUT</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e852">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e853">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e857">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e863"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e872">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e878"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e455">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e456">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e881">/groups/{groupKey}/forum/posts/{messageKey}/attachments/{filename}</h3> + <h3 id="d2e457">/repo/courses/{courseId}/tutors/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -3536,7 +3250,7 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -3545,45 +3259,58 @@ </tr> <tr> <td> - <p><strong>messageKey</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The identity key of the user being searched</p> - </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#addCoach">PUT</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e461">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e462">/repo/courses/{courseId}/file</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>filename</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><strong>courseId</strong></p> </td> <td> - <p>The name of the attachment</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAttachment">GET</h4> - <p>Retrieves the attachment of the message</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e894">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getRepoFileById">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e900"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e465">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e466">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e903">/groups/{groupKey}/folder</h3> + <h3 id="d2e467">/repo/courses/{courseId}/status</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -3593,7 +3320,7 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -3604,61 +3331,81 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e907">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e908">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e909">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e910">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e911">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFileToRoot">POST</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e914">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e915">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> + <h4 id="http://www.example.com#deleteCoursePermanently">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e918">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e470">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e923">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e924">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e473">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e475">/repo/courses/{courseId}/runstructure</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putFileToRoot">PUT</h4> + <h4 id="http://www.example.com#findRunStructureById">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e927">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e928">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e478">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e479">/repo/courses/{courseId}/editortreemodel</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e931">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e932">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#findEditorTreeModelById">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e934">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e935">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e482">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e936">/groups/{groupKey}/folder/{path:.*}</h3> + <h3 id="d2e483">/repo/courses/{courseId}/authors/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -3668,7 +3415,7 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -3677,10 +3424,10 @@ </tr> <tr> <td> - <p><strong>path</strong></p> + <p><strong>identityKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -3688,80 +3435,118 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> + <h4 id="http://www.example.com#getAuthor">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e940">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e941">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e942">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e943">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e944">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e487">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e488">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFileToFolder">POST</h4> + <h4 id="http://www.example.com#addAuthor">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e947">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e948">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e949">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e491">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> + <h4 id="http://www.example.com#removeAuthor">DELETE</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e494">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e495">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e496">/repo/courses/{courseId}/authors</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#addAuthors">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e952">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e499">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e500">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e957">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e958">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e959">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e502">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#putFileToFolder">PUT</h4> + <h4 id="http://www.example.com#getAuthors">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e962">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e963">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e964">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e505">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e506">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e508">/repo/courses/{courseId}/tutors</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> + <h4 id="http://www.example.com#addCoaches">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e967">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e968">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e511">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e512">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e970">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e971">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFolders">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e974">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e975">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e514">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#deleteItem">DELETE</h4> + <h4 id="http://www.example.com#getTutors">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e978">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e979">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e517">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e518">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e980">/groups/{groupKey}/folder/version</h3> + <h3 id="d2e519">/repo/courses/{courseId}/participants</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -3771,7 +3556,7 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -3782,16 +3567,29 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#getParticipants">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e522">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e523">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#addParticipants">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e526">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e527">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e983">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e529">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e984">/groups/{groupKey}/folder/metadata/{path:.*}</h3> + <h3 id="d2e530">/repo/courses/{courseId}/participants/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -3801,7 +3599,7 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -3810,10 +3608,10 @@ </tr> <tr> <td> - <p><strong>path</strong></p> + <p><strong>identityKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -3821,20 +3619,16 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getFileMetadata">GET</h4> + <h4 id="http://www.example.com#addParticipant">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e988">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e989">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e534">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e990">/groups/{groupKey}/wiki</h3> - <p>The Group Wiki Webservice<br /> - allows the export of group wikis - </p> + <h3 id="d2e535">/repo/courses/{courseId}/version</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -3844,7 +3638,7 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -3855,38 +3649,47 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#exportWiki">GET</h4> - <p>will export the wiki from the current group to a CP and serve as - zip-file.<br /> - </p> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e998">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e999">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e538">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1000">/i18n</h3> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e1001">/i18n/version</h3> + <h3 id="d2e539">/repo/courses/{courseId}/resource</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#getOlatResource">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1004">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e542">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e543">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1005">/i18n/{package}/{key}<span class="optional">?locale</span></h3> + <h3 id="d2e544">/repo/courses/{courseId}/publish<span class="optional">?locale</span><span class="optional">&access</span><span class="optional">&membersOnly</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -3896,19 +3699,10 @@ </tr> <tr> <td> - <p><strong>package</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>key</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -3916,7 +3710,7 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getTranslation">GET</h4> + <h4 id="http://www.example.com#publishCourse">POST</h4> <h6>request query parameters</h6> <table> <tr> @@ -3933,351 +3727,535 @@ </td> <td></td> </tr> + <tr> + <td> + <p><strong>access</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>membersOnly</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td></td> + </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1012">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e551">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e552">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1013">/system</h3> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e1014">/system/environment</h3> + <h3 id="d2e553">/repo/courses/{courseId}/groups</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getEnvironnementXml">GET</h4> + <h4 id="http://www.example.com#getGroupList">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1017">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1018">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e556">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e557">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1019">/system/release</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getReleaseInfos">GET</h4> + <h4 id="http://www.example.com#putNewGroup">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e560">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e561">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1022">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1023">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e563">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e564">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1024">/system/notifications</h3> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e1025">/system/notifications/status</h3> + <h3 id="d2e565">/repo/courses/{courseId}/groups/{groupKey}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getStatus">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1028">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1029">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#setStatus">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e1032">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getGroup">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1035">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e569">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#getPlainTextStatus">GET</h4> + <h4 id="http://www.example.com#deleteGroup">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1038">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e572">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1039">/system/monitoring</h3> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e1040">/system/monitoring/configuration</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getImplementedProbes">GET</h4> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#updateGroup">POST</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1043">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1044">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e575">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1045">/system/monitoring/status</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getSystemSummaryVO">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1048">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1049">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e577">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1050">/system/monitoring/runtime</h3> + <h3 id="d2e578">/repo/courses/{courseId}/groups/version</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getSystemSummaryVO">GET</h4> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1053">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1054">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e581">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1055">/system/monitoring/runtime/classes</h3> + <h3 id="d2e582">/repo/courses/{courseId}/groups/{groupKey}/folder</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getCompilationXml">GET</h4> + <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1058">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1059">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e586">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e587">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e588">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e589">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e590">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1060">/system/monitoring/runtime/memory</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getMemoryStatistics">GET</h4> + <h4 id="http://www.example.com#postFileToRoot">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1063">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1064">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e593">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e594">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1065">/system/monitoring/runtime/threads</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getThreadStatistics">GET</h4> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1068">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1069">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e597">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1070">/system/monitoring/database</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getDatabaseStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1073">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1074">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e602">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e603">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1075">/system/monitoring/openolat</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getStatistics">GET</h4> + <h4 id="http://www.example.com#putFileToRoot">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1078">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1079">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e606">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e607">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1080">/system/monitoring/openolat/tasks</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getTasks">GET</h4> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1083">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1084">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e610">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e611">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1085">/system/monitoring/openolat/users</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getUserStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1088">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1089">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e613">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e614">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1090">/system/monitoring/openolat/repository</h3> - <h6>Methods</h6> - <div class="methods"> + <h3 id="d2e615">/repo/courses/{courseId}/groups/{groupKey}/folder/{path:.*}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>path</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getRepositoryStatistics">GET</h4> + <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1093">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1094">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e619">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e620">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e621">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e622">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e623">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1095">/system/monitoring/openolat/sessions</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getSessions">GET</h4> + <h4 id="http://www.example.com#postFileToFolder">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1098">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1099">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e626">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e627">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e628">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1100">/system/monitoring/openolat/indexer</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getStatistics">GET</h4> + <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e631">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1103">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1104">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e636">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e637">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e638">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1105">/system/monitoring/openolat/indexer/status</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getStatus">GET</h4> + <h4 id="http://www.example.com#putFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1108">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1109">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e641">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e642">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e643">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#setStatus">POST</h4> + <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1112">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e646">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e647">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1115">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e649">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e650">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#getPlainTextStatus">GET</h4> + <h4 id="http://www.example.com#putFolders">PUT</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e653">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e654">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1118">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e657">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e658">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1119">/system/monitoring/memory</h3> + <h3 id="d2e659">/repo/courses/{courseId}/groups/{groupKey}/folder/metadata/{path:.*}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>path</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getMemory">GET</h4> + <h4 id="http://www.example.com#getFileMetadata">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1122">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e663">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e664">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e665">/repo/courses/{courseId}/groups/{groupKey}/folder/version</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getMemoryXml">GET</h4> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1125">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1126">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e668">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1127">/system/monitoring/memory/pools</h3> + <h3 id="d2e669">/repo/courses/{courseId}/groups/{groupKey}/forum</h3> + <p>Description:<br> + Web service to manage a forum. + + <P> + Initial Date: 20 apr. 2010 <br> + </p> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getMemoryPools">GET</h4> + <h4 id="http://www.example.com#getForum">GET</h4> + <p>Retrieves the forum.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1130">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e679">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e692"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getMemoryPoolsXml">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1133">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1134">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e698"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1135">/system/monitoring/memory/samples<span class="optional">?from</span><span class="optional">&to</span><span class="optional">&lastSamples</span></h3> + <h3 id="d2e701">/repo/courses/{courseId}/groups/{groupKey}/forum/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getSamplesXml">GET</h4> + <h4 id="http://www.example.com#getThreads">GET</h4> + <p>Retrieves the threads in the forum</p> <h6>request query parameters</h6> <table> <tr> @@ -4287,150 +4265,143 @@ </tr> <tr> <td> - <p><strong>from</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>to</strong></p> + <p><strong>limit</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>lastSamples</strong></p> + <p><strong>orderBy</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>creationDate</tt></p> + </td> + <td> + <p>(value name,creationDate)</p> + </td> + </tr> + <tr> + <td> + <p><strong>asc</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>true</tt></p> + </td> + <td> + <p>(value true/false)</p> </td> - <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1142">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1143">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e717">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1144">/system/monitoring/threads</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getThreads">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1147">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e730"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getThreadsXml">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1150">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1151">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e736"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1152">/system/monitoring/threads/cpu</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getThreadsCpu">GET</h4> + <h4 id="http://www.example.com#newThreadToForum">PUT</h4> + <p>Creates a new thread in the forum of the course node</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>title</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The title for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>body</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The body for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>authorKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The author user key (optional)</p> + </td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1155">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1156">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e755">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1157">/system/indexer</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1160">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1161">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e768"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1162">/system/indexer/status</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getStatus">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1165">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1166">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e774"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#setStatus">POST</h4> + <h4 id="http://www.example.com#newThreadToForumPost">POST</h4> + <p>Creates a new thread in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1169">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1172">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e781">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getPlainTextStatus">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1175">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e788">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1176">/system/log</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getCurrentLogFile">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1179">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1180">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e801"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1181">/system/log/version</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1184">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e807"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1185">/system/log/{date}</h3> + <h3 id="d2e810">/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -4440,38 +4411,39 @@ </tr> <tr> <td> - <p><strong>date</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>threadKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The key of the thread</p> + </td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getLogFileByDate">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1189">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1190">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1191">/contacts<span class="optional">?start</span><span class="optional">&limit</span></h3> - <p>Description:<br> - - <P> - Initial Date: 21 oct. 2011 <br> - </p> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getMyContacts">GET</h4> - <p>Retrieve the contacts of the logged in identity.</p> + <h4 id="http://www.example.com#getMessages">GET</h4> + <p>Retrieves the messages in the thread</p> <h6>request query parameters</h6> <table> <tr> @@ -4499,30 +4471,48 @@ </td> <td></td> </tr> + <tr> + <td> + <p><strong>orderBy</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>creationDate</tt></p> + </td> + <td> + <p>(value name, creationDate)</p> + </td> + </tr> + <tr> + <td> + <p><strong>asc</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>true</tt></p> + </td> + <td> + <p>(value true/false)</p> + </td> + </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1203"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e829">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1206">/catalog</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getRoots">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1209">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1210">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e842"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e848"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1211">/catalog/{path:.*}/owners/{identityKey}</h3> + <h3 id="d2e851">/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -4532,84 +4522,80 @@ </tr> <tr> <td> - <p><strong>path</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> + <tr> + <td> + <p><strong>messageKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The id of the reply message</p> + </td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getOwner">GET</h4> + <h4 id="http://www.example.com#replyToPostPost">POST</h4> + <p>Creates a new reply in the forum of the course node</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e859">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1216">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e872">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#addOwner">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1219">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e885"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#removeOwner">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1222">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e891"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1223">/catalog/version</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#replyToPost">PUT</h4> + <p>Creates a new reply in the forum of the course node</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e898">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e899">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e903">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e916"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1226">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e922"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1227">/catalog/{path:.*}/children<span class="optional">?start</span><span class="optional">&limit</span></h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getChildren">GET</h4> + <h4 id="http://www.example.com#replyToPost">PUT</h4> + <p>Creates a new reply in the forum of the course node</p> <h6>request query parameters</h6> <table> <tr> @@ -4619,35 +4605,55 @@ </tr> <tr> <td> - <p><strong>start</strong></p> + <p><strong>title</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The title for the first post in the thread</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>limit</strong></p> + <p><strong>body</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The body for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>authorKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The author user key (optional)</p> </td> - <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1234">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1235">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e941">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e954"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e960"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1236">/catalog/{path:.*}</h3> + <h3 id="d2e963">/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}/attachments</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -4657,186 +4663,106 @@ </tr> <tr> <td> - <p><strong>path</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> + <tr> + <td> + <p><strong>messageKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The key of the message</p> + </td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getCatalogEntry">GET</h4> + <h4 id="http://www.example.com#getAttachments">GET</h4> + <p>Retrieves the attachments of the message</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1240">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1241">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e973">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e979"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#addCatalogEntry">PUT</h4> + <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1244">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> - <li><a href="#d2e1245">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> + <li><a href="#d2e986">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1247">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1248">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e992">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#addCatalogEntry">PUT</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>name</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>description</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>type</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1256">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1257">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e998"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#updatePostCatalogEntry">POST</h4> + <h4 id="http://www.example.com#replyToPostAttachment">PUT</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1260">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1005">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e1006">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1265">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1266">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#updateCatalogEntry">POST</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>newParentKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e1270">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> - <li><a href="#d2e1271">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> + <li><a href="#d2e1010">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1273">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1274">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1016"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#updateCatalogEntry">POST</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>name</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>description</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>newParentKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> + <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1281">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1282">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1025">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#deleteCatalogEntry">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1285">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1286">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1031"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1287">/catalog/{path:.*}/owners</h3> + <h3 id="d2e1034">/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}/attachments/{filename}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -4846,126 +4772,107 @@ </tr> <tr> <td> - <p><strong>path</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> + <tr> + <td> + <p><strong>messageKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The identity key of the user being searched</p> + </td> + </tr> + <tr> + <td> + <p><strong>filename</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The name of the attachment</p> + </td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getOwners">GET</h4> + <h4 id="http://www.example.com#getAttachment">GET</h4> + <p>Retrieves the attachment of the message</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1047">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1291">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1292">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1053"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1293">/repo/entries<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&managed</span><span class="optional">&externalId</span><span class="optional">&externalRef</span><span class="optional">&resourceType</span></h3> + <h3 id="d2e1056">/repo/courses/{courseId}/calendar</h3> + <p>Initial date: 23.12.2015<br></p> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getEntries">GET</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>managed</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>externalId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>externalRef</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>resourceType</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1303">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1304">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getEntriesText">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1307">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1308">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putResource">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1311">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1312">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> + <div class="methods"></div> </div> <div class="resource"> - <h3 id="d2e1313">/repo/entries/search<span class="optional">?type</span><span class="optional">&author</span><span class="optional">&name</span><span class="optional">&myentries</span></h3> + <h3 id="d2e1059">/repo/courses/{courseId}/calendar/events<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&onlyFuture</span></h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#searchEntries">GET</h4> + <h4 id="http://www.example.com#getEventsByCalendar">GET</h4> <h6>request query parameters</h6> <table> <tr> @@ -4975,36 +4882,27 @@ </tr> <tr> <td> - <p><strong>type</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>author</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>*</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>name</strong></p> + <p><strong>limit</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>*</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>myentries</strong></p> + <p><strong>onlyFuture</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> @@ -5015,27 +4913,40 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1321">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1322">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1066">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1067">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1323">/repo/entries/version</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#putEventsByCalendar">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1070">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1071">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1073">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1074">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postEventsByCalendar">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1077">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1078">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1326">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1080">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1081">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1327">/repo/entries/{repoEntryKey}</h3> + <h3 id="d2e1082">/repo/courses/{courseId}/calendar/events/{eventId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5045,7 +4956,16 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>eventId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -5056,46 +4976,68 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getById">GET</h4> + <h4 id="http://www.example.com#deleteEventByCalendar">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1331">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1332">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1086">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1087">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1088">/repo/courses/{courseId}/calendar/event</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateEntry">POST</h4> + <h4 id="http://www.example.com#putEventByCalendar">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1335">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>)</a></li> - <li><a href="#d2e1336">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>)</a></li> + <li><a href="#d2e1091">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e1092">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1338">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1339">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1094">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1095">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#replaceResource">POST</h4> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#postEventByCalendar">POST</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1342">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1343">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1098">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1099">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e1100">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#deleteCourse">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1346">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1347">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1102">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1103">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1348">/repo/entries/{repoEntryKey}/coaches</h3> + <h3 id="d2e1104">/repo/courses/{courseId}/vitero/{subIdentifier}</h3> + <p>Initial date: 14.07.2015<br></p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5105,16 +5047,16 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -5125,29 +5067,43 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getCoaches">GET</h4> + <h4 id="http://www.example.com#getRooms">GET</h4> + <p>returns the list of booking of the resource.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1352">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1353">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1114">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#addCoach">PUT</h4> + <h4 id="http://www.example.com#createRoom">PUT</h4> + <p>Return the created or updated booking</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1128">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1129">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1133">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#updateRoom">POST</h4> + <p>Return the created or updated booking</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1356">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1357">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1147">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1148">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1359">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1152">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1360">/repo/entries/{repoEntryKey}/coaches/{identityKey}</h3> + <h3 id="d2e1162">/repo/courses/{courseId}/vitero/{subIdentifier}/{bookingId}/members</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5157,52 +5113,63 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>bookingId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + </td> + <td> + <p>The id of the booking</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#removeCoach">DELETE</h4> + <h4 id="http://www.example.com#getMembers">GET</h4> + <p>Returns the list of members of the booking.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1365">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1172">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#addCoach">PUT</h4> + <h4 id="http://www.example.com#addMembers">POST</h4> + <p>Update the list of members of the booking, it add and mutates the + members and delete the missing members. + </p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1186">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1187">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1368">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1191">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1369">/repo/entries/{repoEntryKey}/participants</h3> + <h3 id="d2e1201">/repo/courses/{courseId}/vitero/{subIdentifier}/{bookingId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5212,49 +5179,47 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> + <tr> + <td> + <p><strong>bookingId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + </td> + <td></td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getParticipants">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1373">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1374">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#addParticipants">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e1377">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1378">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#deleteRoom">DELETE</h4> + <p>Delete the booking</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1380">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1209"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1381">/repo/entries/{repoEntryKey}/participants/{identityKey}</h3> + <h3 id="d2e1212">/repo/courses/{courseId}/gotomeeting/{subIdentifier}</h3> + <p>Initial date: 24.03.2016<br></p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5264,25 +5229,16 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -5291,25 +5247,10 @@ </tr> </table> <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#addParticipant">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1386">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#removeParticipant">DELETE</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1389">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> + <div class="methods"></div> </div> <div class="resource"> - <h3 id="d2e1390">/repo/entries/{repoEntryKey}/owners</h3> + <h3 id="d2e1216">/repo/courses/{courseId}/gotomeeting/{subIdentifier}/trainings</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5319,16 +5260,16 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -5339,29 +5280,43 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#addOwners">PUT</h4> + <h4 id="http://www.example.com#getTrainings">GET</h4> + <p>returns the list of booking of the resource.</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1223">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#createTraining">PUT</h4> + <p>Return the created or updated training</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1394">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1395">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1237">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> + <li><a href="#d2e1238">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1397">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1242">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#getOwners">GET</h4> + <h4 id="http://www.example.com#updateTraining">POST</h4> + <p>Return the created or updated training</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1256">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> + <li><a href="#d2e1257">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1400">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1401">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1261">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1402">/repo/entries/{repoEntryKey}/owners/{identityKey}</h3> + <h3 id="d2e1271">/repo/courses/{courseId}/gotomeeting/{subIdentifier}//trainings/{trainingKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5371,28 +5326,28 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>trainingKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5400,23 +5355,17 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#addOwner">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1407">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#removeOwner">DELETE</h4> + <h4 id="http://www.example.com#deleteTraining">DELETE</h4> + <p>Delete the training</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1410">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1279"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1412">/repo/entries/{repoEntryKey}/file</h3> + <h3 id="d2e1282">/repo/courses/{courseId}/lectureblocks</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5426,19 +5375,10 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5446,17 +5386,44 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getRepoFileById">GET</h4> + <h4 id="http://www.example.com#getLectureBlocks">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1285">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1286">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putLectureBlocks">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1289">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e1290">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1292">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1293">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postLectureBlocks">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1296">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1297">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e1298">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1416">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1417">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1300">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1301">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1418">/repo/entries/{repoEntryKey}/status</h3> + <h3 id="d2e1302">/repo/courses/{courseId}/lectureblocks/configuration</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5466,19 +5433,10 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5486,21 +5444,31 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deleteCoursePermanently">POST</h4> + <h4 id="http://www.example.com#getConfiguration">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1305">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1306">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#updateConfiguration">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1422">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1309">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1310">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> + <li><a href="#d2e1311">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1425">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1426">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1313">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1314">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1427">/repo/entries/{repoEntryKey}/lectureblocks</h3> + <h3 id="d2e1315">/repo/courses/{courseId}/lectureblocks/sync/calendar</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5510,19 +5478,10 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5530,44 +5489,16 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getLectureBlocks">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1431">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1432">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putLectureBlocks">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e1435">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e1436">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1438">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1439">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postLectureBlocks">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e1442">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1443">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e1444">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#syncCalendar">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1446">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1447">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1318">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1448">/repo/entries/{repoEntryKey}/lectureblocks/configuration</h3> + <h3 id="d2e1319">/repo/courses/{courseId}/lectureblocks/adaptation</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5577,19 +5508,10 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5597,31 +5519,16 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getConfiguration">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1451">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#updateConfiguration">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e1455">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1456">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> - <li><a href="#d2e1457">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#adapatation">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1459">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1460">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1322">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1461">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}</h3> + <h3 id="d2e1323">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5631,19 +5538,10 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5660,23 +5558,24 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getLectureBlock">GET</h4> + <h4 id="http://www.example.com#deleteLectureBlock">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1465">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1327">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#deleteLectureBlock">DELETE</h4> + <h4 id="http://www.example.com#getLectureBlock">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1468">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1330">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1331">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1469">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/teachers/{identityKey}</h3> + <h3 id="d2e1332">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/teachers/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5686,19 +5585,10 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5727,20 +5617,20 @@ <h4 id="http://www.example.com#addTeacher">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1473">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1336">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#removeTeacher">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1476">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1339">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1477">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/teachers</h3> + <h3 id="d2e1340">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/teachers</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5750,19 +5640,10 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5782,13 +5663,14 @@ <h4 id="http://www.example.com#getTeacher">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1480">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1343">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1344">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1481">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/participants/repositoryentry</h3> + <h3 id="d2e1345">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/participants/repositoryentry</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5798,19 +5680,10 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5830,20 +5703,20 @@ <h4 id="http://www.example.com#addRepositoryEntryParticipantGroup">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1484">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1348">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#deleteRepositoryEntryParticipantGroup">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1487">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1351">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1488">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/calendar</h3> + <h3 id="d2e1352">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/sync/calendar</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -5853,19 +5726,10 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -5885,74 +5749,21 @@ <h4 id="http://www.example.com#syncCalendar">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1491">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1355">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1492">/users/{identityKey}/calendars</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getCalendars">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1496">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1497">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e1498">/users/{identityKey}/calendars/events<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&onlyFuture</span></h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> + <h3 id="d2e1356">/pwchange<span class="optional">?identityKey</span></h3> + <p>Webservice to create a temporary key to change the password + + Initial date: 15.10.2013<br> + </p> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getEvents">GET</h4> + <h4 id="http://www.example.com#register">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -5962,86 +5773,31 @@ </tr> <tr> <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>onlyFuture</strong></p> + <p><strong>identityKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>false</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1506">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1507">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1363">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1364">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1508">/users/{identityKey}/calendars/{calendarId}</h3> - <p>Initial date: 23.12.2015<br></p> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>calendarId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> + <h3 id="d2e1365">/vitero</h3> + <p>Initial date: 06.07.2015<br></p> <h6>Methods</h6> <div class="methods"></div> </div> <div class="resource"> - <h3 id="d2e1513">/users/{identityKey}/calendars/{calendarId}/events/{eventId}</h3> + <h3 id="d2e1368">/vitero/{resourceName}/{resourceId}/{subIdentifier}</h3> + <p>Initial date: 14.07.2015<br></p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -6051,16 +5807,7 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>calendarId</strong></p> + <p><strong>resourceName</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -6069,7 +5816,7 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>resourceId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -6078,7 +5825,7 @@ </tr> <tr> <td> - <p><strong>eventId</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -6089,17 +5836,43 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deleteEventByCalendar">DELETE</h4> + <h4 id="http://www.example.com#getRooms">GET</h4> + <p>returns the list of booking of the resource.</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1380">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#createRoom">PUT</h4> + <p>Return the created or updated booking</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1394">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1395">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1399">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#updateRoom">POST</h4> + <p>Return the created or updated booking</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1413">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e1414">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1517">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1518">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1418">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1519">/users/{identityKey}/calendars/{calendarId}/event</h3> + <h3 id="d2e1428">/vitero/{resourceName}/{resourceId}/{subIdentifier}/{bookingId}/members</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -6109,7 +5882,16 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>resourceName</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>resourceId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -6118,7 +5900,7 @@ </tr> <tr> <td> - <p><strong>calendarId</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -6127,47 +5909,45 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>bookingId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + </td> + <td> + <p>The id of the booking</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putEventByCalendar">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e1522">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e1523">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getMembers">GET</h4> + <p>Returns the list of members of the booking.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1525">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1526">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1438">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postEventByCalendar">POST</h4> + <h4 id="http://www.example.com#addMembers">POST</h4> + <p>Update the list of members of the booking, it add and mutates the + members and delete the missing members. + </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1529">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1530">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e1531">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> + <li><a href="#d2e1452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1453">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1533">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1534">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1457">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1535">/users/{identityKey}/calendars/{calendarId}/events</h3> + <h3 id="d2e1467">/vitero/{resourceName}/{resourceId}/{subIdentifier}/{bookingId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -6177,7 +5957,16 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>resourceName</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>resourceId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -6186,7 +5975,7 @@ </tr> <tr> <td> - <p><strong>calendarId</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -6195,10 +5984,10 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>bookingId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> </td> <td></td> </tr> @@ -6206,20 +5995,21 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putEventsByCalendar">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e1538">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1539">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#deleteRoom">DELETE</h4> + <p>Delete the booking</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1541">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1542">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1475"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1478">/groups<span class="optional">?externalId</span><span class="optional">&managed</span></h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getEventsByCalendar">GET</h4> + <h4 id="http://www.example.com#getGroupList">GET</h4> <h6>request query parameters</h6> <table> <tr> @@ -6229,64 +6019,46 @@ </tr> <tr> <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> + <p><strong>externalId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>onlyFuture</strong></p> + <p><strong>managed</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>false</tt></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1549">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1550">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1484">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1485">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postEventsByCalendar">POST</h4> + <h4 id="http://www.example.com#createGroup">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1553">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1554">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1488">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e1489">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1556">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e1557">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1491">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1492">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1558">/repo/courses/{courseId}/elements/enrollment<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&groups</span><span class="optional">&cancelEnabled</span></h3> - <p>Description:<br> - This handles the enrollment building block. - - <P> - Initial Date: 10 mai 2010 <br> - </p> + <h3 id="d2e1493">/groups/{groupKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -6296,173 +6068,96 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The course resourceable's id</p> - </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachEnrolmment">PUT</h4> - <p>This attaches an enrollment element onto a given course, the element will be - inserted underneath the supplied parentNodeId - </p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>parentNodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The node's id which will be the parent of this structure</p> - </td> - </tr> - <tr> - <td> - <p><strong>position</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - </td> - <td> - <p>The node's position relative to its sibling nodes (optional)</p> - </td> - </tr> - <tr> - <td> - <p><strong>shortTitle</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td> - <p>The node short title</p> - </td> - </tr> - <tr> - <td> - <p><strong>longTitle</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td> - <p>The node long title</p> - </td> - </tr> - <tr> - <td> - <p><strong>objectives</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td> - <p>The node learning objectives</p> - </td> - </tr> - <tr> - <td> - <p><strong>visibilityExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The rules to view the node (optional)</p> - </td> - </tr> - <tr> - <td> - <p><strong>accessExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The rules to access the node (optional)</p> - </td> - </tr> - <tr> - <td> - <p><strong>groups</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>A list of learning groups (list of keys)</p> - </td> - </tr> - <tr> - <td> - <p><strong>cancelEnabled</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>false</tt></p> - </td> - <td> - <p>cancel enrollment enabled or not</p> - </td> - </tr> - </table> + <h4 id="http://www.example.com#findById">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1598">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e1497">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1498">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - <p><em>available response representations:</em></p> + </div> + <div class="method"> + <h4 id="http://www.example.com#postGroup">POST</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e1611"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1501">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + <li><a href="#d2e1502">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1617"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1504">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1505">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#attachEnrollmenetPost">POST</h4> - <p>This attaches an enrollment element onto a given course, the element will be - inserted underneath the supplied parentNodeId - </p> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#deleteGroup">DELETE</h4> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1624">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1508">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1509">/groups/{groupKey}/news</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getNews">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1655">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e1513">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postNews">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1516">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1668"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1519">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deleteNews">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1674"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1522">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1677">/repo/courses/{courseId}/elements/enrollment/{nodeId}/groups</h3> + <h3 id="d2e1523">/groups/{groupKey}/configuration</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -6472,30 +6167,75 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The course resourceable's id</p> - </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#postGroupConfiguration">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1527">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1529">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1530">/groups/{groupKey}/infos</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getInformations">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1534">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1535">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1536">/groups/{groupKey}/owners</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> <tr> <td> - <p><strong>nodeId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -6503,31 +6243,48 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getGroups">GET</h4> - <p>Retrieves the groups where the enrollment happens</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1686">application/xml, application/json (<abbr title="{http://www.example.com} groupVO">ns3:groupVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getTutors">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1699"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1540">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1541">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1542">/groups/{groupKey}/participants</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getParticipants">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1705"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1546">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1547">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1708">/repo/courses/{courseId}/elements/forum<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&moderatorExpertRules</span><span class="optional">&posterExpertRules</span><span class="optional">&readerExpertRules</span></h3> - <p>Description:<br> - REST API implementation for forum course node - - <P> - Initial Date: 20.12.2010 <br> - </p> + <h3 id="d2e1548">/groups/{groupKey}/owners/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -6537,7 +6294,16 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -6548,166 +6314,85 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachForum">PUT</h4> - <p>This attaches a Forum Element onto a given course. The element will be - inserted underneath the supplied parentNodeId. - </p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>parentNodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>position</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>shortTitle</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>longTitle</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>objectives</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>visibilityExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>accessExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>moderatorExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>posterExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>readerExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1729">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1742"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#addTutor">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1748"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1553">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#getForums">GET</h4> - <p>Retrieves metadata of the published course node</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1757">application/xml, application/json (<abbr title="{http://www.example.com} forumVOes">ns3:forumVOes</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1770"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#removeTutor">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1776"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1556">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1557">/groups/{groupKey}/participants/{identityKey}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>groupKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachForumPost">POST</h4> - <p>This attaches a Forum Element onto a given course. The element will be - inserted underneath the supplied parentNodeId. - </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e1783">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#addParticipant">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1797">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e1562">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#removeParticipant">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1810"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1565">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1566">/groups/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1816"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1569">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1819">/repo/courses/{courseId}/elements/forum/{nodeId}</h3> + <h3 id="d2e1571">/groups/{groupKey}/wiki</h3> + <p>The Group Wiki Webservice<br /> + allows the export of group wikis + </p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -6717,58 +6402,106 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#exportWiki">GET</h4> + <p>will export the wiki from the current group to a CP and serve as + zip-file.<br /> + </p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1579">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1580">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1581">/groups/{groupKey}/folder</h3> + <h6>resource-wide template parameters</h6> + <table> <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The course resourceable's id</p> - </td> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><strong>groupKey</strong></p> </td> <td> - <p>The node's id</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getForum">GET</h4> - <p>Retrieves metadata of the published course node</p> + <h4 id="http://www.example.com#listFiles">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1585">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1586">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1587">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1588">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1589">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFileToRoot">POST</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1592">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1593">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1596">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1832">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e1601">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1602">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFileToRoot">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1845"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1605">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1606">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1609">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e1610">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1851"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1612">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1613">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1854">/repo/courses/{courseId}/elements/forum/{nodeId}/thread<span class="optional">?title</span><span class="optional">&body</span><span class="optional">&identityName</span><span class="optional">&sticky</span></h3> + <h3 id="d2e1614">/groups/{groupKey}/folder/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -6778,7 +6511,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -6787,101 +6520,91 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The id of the course.</p> - </td> - </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td> - <p>The id of the course node.</p> - </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#newThreadToForum">PUT</h4> - <p>Creates a new thread in the forum of the course node</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>title</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The title for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>body</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The body for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>identityName</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The author identity name (optional)</p> - </td> - </tr> - <tr> - <td> - <p><strong>sticky</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - </td> - <td> - <p>Creates sticky thread.</p> - </td> - </tr> - </table> + <h4 id="http://www.example.com#listFiles">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1618">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1619">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1620">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1621">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1622">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFileToFolder">POST</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1625">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1626">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1627">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1630">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1635">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1636">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1637">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFileToFolder">PUT</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1640">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1641">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1642">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e1645">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e1646">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1880">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1648">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1649">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFolders">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1893"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1652">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1653">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1899"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1656">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1657">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1902">/repo/courses/{courseId}/elements/forum/{nodeId}/message<span class="optional">?parentMessageId</span><span class="optional">&title</span><span class="optional">&body</span><span class="optional">&identityName</span></h3> + <h3 id="d2e1658">/groups/{groupKey}/folder/metadata/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -6891,7 +6614,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -6900,101 +6623,58 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>path</strong></p> </td> <td> - <p>The id of the course.</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getFileMetadata">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e1662">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1663">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e1664">/groups/{groupKey}/folder/version</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><strong>groupKey</strong></p> </td> <td> - <p>The id of the course node.</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#newMessageToForum">PUT</h4> - <p>Creates a new forum message in the forum of the course node</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>parentMessageId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The id of the parent message.</p> - </td> - </tr> - <tr> - <td> - <p><strong>title</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The title for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>body</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The body for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>identityName</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The author identity name (optional)</p> - </td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1928">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e1941"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1947"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1667">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1950">/repo/courses/{courseId}/elements/forum/{nodeId}/forum</h3> + <h3 id="d2e1668">/groups/{groupKey}/forum</h3> <p>Description:<br> Web service to manage a forum. @@ -7010,31 +6690,13 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> @@ -7043,21 +6705,21 @@ <p>Retrieves the forum.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1961">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e1678">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1974"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1691"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1980"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1697"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e1983">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> + <h3 id="d2e1700">/groups/{groupKey}/forum/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7067,31 +6729,13 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> @@ -7152,15 +6796,15 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e1999">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e1716">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2012"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1729"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2018"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1735"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -7209,15 +6853,15 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2037">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1754">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2050"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1767"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2056"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1773"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -7225,25 +6869,25 @@ <p>Creates a new thread in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2063">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1780">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2070">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1787">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2083"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1800"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2089"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1806"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2092">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> + <h3 id="d2e1809">/groups/{groupKey}/forum/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7253,31 +6897,13 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> <tr> <td> <p><strong>threadKey</strong></p> @@ -7349,21 +6975,21 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2111">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e1828">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2124"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1841"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2130"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1847"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2133">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}</h3> + <h3 id="d2e1850">/groups/{groupKey}/forum/posts/{messageKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7373,7 +6999,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -7382,25 +7008,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>messageKey</strong></p> + <p><strong>messageKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -7417,19 +7025,19 @@ <p>Creates a new reply in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2141">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1858">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2154">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1871">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2167"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1884"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2173"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1890"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -7437,20 +7045,20 @@ <p>Creates a new reply in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2180">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e2181">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e1897">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e1898">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2185">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1902">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2198"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1915"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2204"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1921"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -7499,21 +7107,21 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2223">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e1940">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2236"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1953"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2242"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1959"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2245">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}/attachments</h3> + <h3 id="d2e1962">/groups/{groupKey}/forum/posts/{messageKey}/attachments</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7523,31 +7131,13 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> <tr> <td> <p><strong>messageKey</strong></p> @@ -7567,11 +7157,11 @@ <p>Retrieves the attachments of the message</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2255">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1972">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2261"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1978"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -7582,15 +7172,15 @@ </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2268">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1985">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2274">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1991">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2280"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e1997"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -7601,16 +7191,16 @@ </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2287">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e2288">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e2004">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e2005">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2292">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2009">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2298"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2015"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -7621,17 +7211,17 @@ </p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2307">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2024">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2313"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2030"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2316">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}/attachments/{filename}</h3> + <h3 id="d2e2033">/groups/{groupKey}/forum/posts/{messageKey}/attachments/{filename}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7641,7 +7231,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -7650,73 +7240,154 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>messageKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The identity key of the user being searched</p> + </td> </tr> <tr> <td> - <p><strong>nodeId</strong></p> + <p><strong>filename</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td></td> + <td> + <p>The name of the attachment</p> + </td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getAttachment">GET</h4> + <p>Retrieves the attachment of the message</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2046">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2052"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e2055">/repo/courses/{courseId}/db/{category}</h3> + <p>Description:<br> + Access the custom dbs of a course + + <P> + Initial Date: *7 apr. 2010 <br> + </p> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e2058">/repo/courses/{courseId}/db/{category}/values/{name}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>messageKey</strong></p> + <p><strong>name</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The identity key of the user being searched</p> + <p>The name of the key value pair</p> </td> </tr> <tr> <td> - <p><strong>filename</strong></p> + <p><strong>category</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The name of the attachment</p> + <p>The name of the database</p> + </td> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The course resourceable's id</p> </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAttachment">GET</h4> - <p>Retrieves the attachment of the message</p> + <h4 id="http://www.example.com#getValue">GET</h4> + <p>Retrieve a value of an authenticated user.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2329">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2072">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2335"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2083"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2339">/notifications<span class="optional">?date</span><span class="optional">&type</span></h3> - <p><h3>Description:</h3> - REST API for notifications - <p> - Initial Date: 25 aug 2010 <br> - </p> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getNotifications">GET</h4> - <p>Retrieves the notification of the logged in user.</p> + <h4 id="http://www.example.com#getValuePlain">GET</h4> + <p>Retrieve a value of an authenticated user.</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2090">text/plain, text/html (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2101"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#formValue">POST</h4> + <p>Update a value for an authenticated user.</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e2108">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2113"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deleteValue">DELETE</h4> + <p>Delete a value for an authenticated user.</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2120"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2124"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2128"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putValue">PUT</h4> + <p>Put a new value for an authenticated user.</p> <h6>request query parameters</h6> <table> <tr> @@ -7726,58 +7397,25 @@ </tr> <tr> <td> - <p><strong>date</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The date (optional)</p> - </td> - </tr> - <tr> - <td> - <p><strong>type</strong></p> + <p><strong>value</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The type of notifications (User, Forum...) (optional)</p> + <p>The value of the key value pair</p> </td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2355">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2368"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2371">/notifications/subscribers</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#subscribe">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2374">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>)</a></li> - <li><a href="#d2e2375">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2377">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2139"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2378">/notifications/subscribers/{subscriberKey}</h3> + <h3 id="d2e2142">/repo/courses/{courseId}/db/{category}/values</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7787,27 +7425,67 @@ </tr> <tr> <td> - <p><strong>subscriberKey</strong></p> + <p><strong>category</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The name of the database</p> + </td> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The course resourceable's id</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#unsubscribe">DELETE</h4> + <h4 id="http://www.example.com#getValues">GET</h4> + <p>Retrieve all values of the authenticated user</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2153">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putValues">PUT</h4> + <p>Put a new value for an authenticated user.</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e2167">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> + <li><a href="#d2e2168">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2170"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postValues">POST</h4> + <p>Update a value for an authenticated user.</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e2177">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> + <li><a href="#d2e2178">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2382">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2383">/notifications/subscribers/{ressourceName}/{ressourceId}/{subIdentifier}</h3> + <h3 id="d2e2183">/repo/courses/{courseId}/db/{category}/values/{name}/delete</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7817,64 +7495,92 @@ </tr> <tr> <td> - <p><strong>ressourceId</strong></p> + <p><strong>name</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The name of the key value pair</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>subIdentifier</strong></p> + <p><strong>category</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td></td> + <td> + <p>The name of the database</p> + </td> </tr> <tr> <td> - <p><strong>ressourceName</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The course resourceable's id</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getSubscriber">GET</h4> + <h4 id="http://www.example.com#deleteValuePost">POST</h4> + <p>Fallbakc method for the browsers</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2389">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2390">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2197"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2201"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2205"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e2208">/repo/courses/{courseId}/db/{category}/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> + <p>Retrieves the version of the Course DB Web Service.</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2213">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2391">/repo/sharedfolder</h3> + <h3 id="d2e2223">/repo/courses/{courseId}/resourcefolders</h3> <h6>Methods</h6> <div class="methods"></div> </div> <div class="resource"> - <h3 id="d2e2392">/repo/sharedfolder/version</h3> + <h3 id="d2e2224">/repo/courses/{courseId}/resourcefolders/version</h3> <h6>Methods</h6> <div class="methods"> <div class="method"> <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2395">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2227">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2396">/repo/sharedfolder/{repoEntryKey}/{path:.*}</h3> + <h3 id="d2e2228">/repo/courses/{courseId}/resourcefolders/sharedfolder/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7893,7 +7599,7 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -7907,13 +7613,16 @@ <h4 id="http://www.example.com#getSharedFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2401">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2233">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2234">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2235">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2236">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2402">/repo/sharedfolder/{repoEntryKey}</h3> + <h3 id="d2e2237">/repo/courses/{courseId}/resourcefolders/sharedfolder</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7923,7 +7632,7 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -7937,13 +7646,13 @@ <h4 id="http://www.example.com#getSharedFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2406">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2241">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2407">/repo/sharedfolder/{repoEntryKey}/files</h3> + <h3 id="d2e2242">/repo/courses/{courseId}/resourcefolders/coursefolder/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -7953,7 +7662,16 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>path</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -7964,61 +7682,83 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> + <h4 id="http://www.example.com#getCourseFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2411">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2412">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2413">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2414">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2415">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2247">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2248">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2249">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2250">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFileToRoot">POST</h4> + <h4 id="http://www.example.com#attachFileToFolderPost">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2418">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2419">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2253">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2422">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#attachFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2427">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2428">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2256">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e2257">/repo/courses/{courseId}/resourcefolders/coursefolder</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putFileToRoot">PUT</h4> + <h4 id="http://www.example.com#getCourseFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2431">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2432">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2261">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#attachFileToFolderPost">POST</h4> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2435">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e2436">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e2264">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2438">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2439">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2267">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2440">/repo/sharedfolder/{repoEntryKey}/files/{path:.*}</h3> + <h3 id="d2e2268">/repo/courses/{courseId}/elements/forum</h3> + <p>Description:<br> + REST API implementation for forum course node + + <P> + Initial Date: 20.12.2010 <br> + </p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -8028,100 +7768,177 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> + <h4 id="http://www.example.com#getForums">GET</h4> + <p>Retrieves metadata of the published course node</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2444">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2445">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2446">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2447">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2448">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2278">application/xml, application/json (<abbr title="{http://www.example.com} forumVOes">ns3:forumVOes</abbr>)</a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFileToFolder">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2451">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2453">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2291"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2297"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> + <h4 id="http://www.example.com#attachForumPost">POST</h4> + <p>This attaches a Forum Element onto a given course. The element will be + inserted underneath the supplied parentNodeId. + </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2456">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2304">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2461">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2462">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2463">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2318">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2466">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2467">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2468">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2471">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e2472">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e2331"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2475">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2337"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#putFolders">PUT</h4> + <h4 id="http://www.example.com#attachForum">PUT</h4> + <p>This attaches a Forum Element onto a given course. The element will be + inserted underneath the supplied parentNodeId. + </p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>parentNodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>position</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>shortTitle</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>longTitle</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>objectives</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>visibilityExpertRules</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>accessExpertRules</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>moderatorExpertRules</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>posterExpertRules</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>readerExpertRules</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2478">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2479">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2357">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2370"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2482">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2483">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2376"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2484">/repo/sharedfolder/{repoEntryKey}/files/version</h3> + <h3 id="d2e2379">/repo/courses/{courseId}/elements/forum/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -8131,68 +7948,58 @@ </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2487">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2488">/repo/sharedfolder/{repoEntryKey}/files/metadata/{path:.*}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> <tr> <td> - <p><strong>repoEntryKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The course resourceable's id</p> + </td> </tr> <tr> <td> - <p><strong>path</strong></p> + <p><strong>nodeId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td></td> - </tr> + <td> + <p>The node's id</p> + </td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getFileMetadata">GET</h4> + <h4 id="http://www.example.com#getForum">GET</h4> + <p>Retrieves metadata of the published course node</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2392">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2405"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2492">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2493">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2411"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2494">/users/{username}/auth</h3> - <p>This web service handles functionalities related to authentication credentials of users.</p> + <h3 id="d2e2414">/repo/courses/{courseId}/elements/forum/{nodeId}/thread<span class="optional">?title</span><span class="optional">&body</span><span class="optional">&identityName</span><span class="optional">&sticky</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -8202,67 +8009,110 @@ </tr> <tr> <td> - <p><strong>username</strong></p> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The id of the course.</p> + </td> + </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The username of the user to retrieve authentication</p> + <p>The id of the course node.</p> </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#create">PUT</h4> - <p>Creates and persists an authentication</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2504">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>)</a></li> - <li><a href="#d2e2505">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2509">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2522"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2528"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2534"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2540"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getAuthenticationTokenList">GET</h4> - <p>Returns all user authentications</p> + <h4 id="http://www.example.com#newThreadToForum">PUT</h4> + <p>Creates a new thread in the forum of the course node</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>title</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The title for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>body</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The body for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>identityName</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The author identity name (optional)</p> + </td> + </tr> + <tr> + <td> + <p><strong>sticky</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td> + <p>Creates sticky thread.</p> + </td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2547">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>)</a></li> + <li><a href="#d2e2440">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2558"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2453"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2562"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2459"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2565">/users/{username}/auth/{authKey}</h3> + <h3 id="d2e2462">/repo/courses/{courseId}/elements/forum/{nodeId}/message<span class="optional">?parentMessageId</span><span class="optional">&title</span><span class="optional">&body</span><span class="optional">&identityName</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -8272,60 +8122,116 @@ </tr> <tr> <td> - <p><strong>username</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><strong>courseId</strong></p> </td> <td> - <p>The username of the user to retrieve authentication</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>authKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p>The authentication key identifier</p> + <p>The id of the course.</p> </td> </tr> <tr> <td> - <p><strong>username</strong></p> + <p><strong>nodeId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The username of the user</p> + <p>The id of the course node.</p> </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#delete">DELETE</h4> - <p>Deletes an authentication from the system</p> + <h4 id="http://www.example.com#newMessageToForum">PUT</h4> + <p>Creates a new forum message in the forum of the course node</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>parentMessageId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The id of the parent message.</p> + </td> + </tr> + <tr> + <td> + <p><strong>title</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The title for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>body</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The body for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>identityName</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The author identity name (optional)</p> + </td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2578"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2488">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2584"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2501"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2590"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2507"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2593">/users/{username}/auth/password</h3> + <h3 id="d2e2510">/repo/courses/{courseId}/elements/forum/{nodeId}/forum</h3> + <p>Description:<br> + Web service to manage a forum. + + <P> + Initial Date: 20 apr. 2010 <br> + </p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -8335,57 +8241,54 @@ </tr> <tr> <td> - <p><strong>username</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> </td> <td> - <p>The username of the user to retrieve authentication</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>username</strong></p> + <p><strong>nodeId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td> - <p>The username of the user to change the password</p> - </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#changePassword">POST</h4> - <p>Change the password of a user.</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2601">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2608"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getForum">GET</h4> + <p>Retrieves the forum.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2614"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2521">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2620"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2534"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2626"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2540"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2629">/users/{username}/auth/version</h3> + <h3 id="d2e2543">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -8395,99 +8298,105 @@ </tr> <tr> <td> - <p><strong>username</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>The username of the user to retrieve authentication</p> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p>The version of the User Authentication Web Service</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2636">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2646">/repo/courses/{courseId}/db/{category}</h3> - <p>Description:<br> - Access the custom dbs of a course - - <P> - Initial Date: *7 apr. 2010 <br> - </p> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e2649">/repo/courses/{courseId}/db/{category}/values/{name}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>name</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The name of the key value pair</p> - </td> - </tr> - <tr> - <td> - <p><strong>category</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The name of the database</p> - </td> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The course resourceable's id</p> - </td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getValue">GET</h4> - <p>Retrieve a value of an authenticated user.</p> + <h4 id="http://www.example.com#getThreads">GET</h4> + <p>Retrieves the threads in the forum</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>start</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>limit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>orderBy</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>creationDate</tt></p> + </td> + <td> + <p>(value name,creationDate)</p> + </td> + </tr> + <tr> + <td> + <p><strong>asc</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>true</tt></p> + </td> + <td> + <p>(value true/false)</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2559">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2663">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> + <li><a href="#d2e2572"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2674"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2578"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#putValue">PUT</h4> - <p>Put a new value for an authenticated user.</p> + <h4 id="http://www.example.com#newThreadToForum">PUT</h4> + <p>Creates a new thread in the forum of the course node</p> <h6>request query parameters</h6> <table> <tr> @@ -8497,65 +8406,75 @@ </tr> <tr> <td> - <p><strong>value</strong></p> + <p><strong>title</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The value of the key value pair</p> + <p>The title for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>body</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The body for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>authorKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The author user key (optional)</p> </td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2685"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2597">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getValuePlain">GET</h4> - <p>Retrieve a value of an authenticated user.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2692">text/plain, text/html (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> + <li><a href="#d2e2610"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2703"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2616"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#formValue">POST</h4> - <p>Update a value for an authenticated user.</p> + <h4 id="http://www.example.com#newThreadToForumPost">POST</h4> + <p>Creates a new thread in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2710">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2715"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2623">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#deleteValue">DELETE</h4> - <p>Delete a value for an authenticated user.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2722"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2630">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2726"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2643"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2730"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2649"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2733">/repo/courses/{courseId}/db/{category}/values</h3> + <h3 id="d2e2652">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -8563,17 +8482,6 @@ <th>value</th> <th>description</th> </tr> - <tr> - <td> - <p><strong>category</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The name of the database</p> - </td> - </tr> <tr> <td> <p><strong>courseId</strong></p> @@ -8581,191 +8489,43 @@ <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The course resourceable's id</p> - </td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#putValues">PUT</h4> - <p>Put a new value for an authenticated user.</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2744">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> - <li><a href="#d2e2745">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2747"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getValues">GET</h4> - <p>Retrieve all values of the authenticated user</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2754">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>)</a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postValues">POST</h4> - <p>Update a value for an authenticated user.</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2768">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> - <li><a href="#d2e2769">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2771"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2774">/repo/courses/{courseId}/db/{category}/version</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p>Retrieves the version of the Course DB Web Service.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2779">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2789">/repo/courses/{courseId}/db/{category}/values/{name}/delete</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td></td> </tr> <tr> <td> - <p><strong>name</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><strong>courseId</strong></p> </td> <td> - <p>The name of the key value pair</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>category</strong></p> + <p><strong>nodeId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td> - <p>The name of the database</p> - </td> + <td></td> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>threadKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p>The course resourceable's id</p> + <p>The key of the thread</p> </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deleteValuePost">POST</h4> - <p>Fallbakc method for the browsers</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2803"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2807"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2811"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2814">/registration<span class="optional">?email</span></h3> - <p>Description:<br> - Web service to trigger the registration process - - <P> - Initial Date: 14 juil. 2011 <br> - </p> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#register">PUT</h4> - <p>Register with the specified email</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>email</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The email address</p> - </td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2825"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2829"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#registerPost">POST</h4> - <p>Register with the specified email</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2836">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2841"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2845"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2848">/repo/courses<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&managed</span><span class="optional">&externalId</span><span class="optional">&externalRef</span><span class="optional">&repositoryEntryKey</span></h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getCourseList">GET</h4> + <h4 id="http://www.example.com#getMessages">GET</h4> + <p>Retrieves the messages in the thread</p> <h6>request query parameters</h6> <table> <tr> @@ -8795,62 +8555,138 @@ </tr> <tr> <td> - <p><strong>managed</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p><strong>orderBy</strong></p> </td> - <td></td> - </tr> - <tr> <td> - <p><strong>externalId</strong></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>creationDate</tt></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>(value name, creationDate)</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>externalRef</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><strong>asc</strong></p> </td> - <td></td> - </tr> - <tr> <td> - <p><strong>repositoryEntryKey</strong></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>true</tt></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>(value true/false)</p> </td> - <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2858">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2859">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2671">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2684"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2690"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e2693">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>messageKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The id of the reply message</p> + </td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#replyToPostPost">POST</h4> + <p>Creates a new reply in the forum of the course node</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e2701">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2714">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2727"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2733"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#createEmptyCourse">PUT</h4> + <h4 id="http://www.example.com#replyToPost">PUT</h4> + <p>Creates a new reply in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2862">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>)</a></li> - <li><a href="#d2e2863">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>)</a></li> + <li><a href="#d2e2740">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e2741">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2745">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2865">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2866">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2758"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2764"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#createEmptyCourse">PUT</h4> + <h4 id="http://www.example.com#replyToPost">PUT</h4> + <p>Creates a new reply in the forum of the course node</p> <h6>request query parameters</h6> <table> <tr> @@ -8858,15 +8694,6 @@ <th>value</th> <th>description</th> </tr> - <tr> - <td> - <p><strong>shortTitle</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> <tr> <td> <p><strong>title</strong></p> @@ -8874,167 +8701,50 @@ <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>displayName</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>description</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>softKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>access</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>membersOnly</strong></p> - </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>The title for the first post in the thread</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>externalId</strong></p> + <p><strong>body</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>externalRef</strong></p> - </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>The body for the first post in the thread</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>authors</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><strong>authorKey</strong></p> </td> - <td></td> - </tr> - <tr> <td> - <p><strong>location</strong></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>The author user key (optional)</p> </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>managedFlags</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>sharedFolderSoftKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>copyFrom</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>initialAuthor</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>setAuthor</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>true</tt></p> - </td> - <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2887">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2888">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2783">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#importCourse">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2891">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2892">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2796"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2893">/repo/courses/version</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2896">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2802"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2897">/repo/courses/{courseId}</h3> + <h3 id="d2e2805">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}/attachments</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9051,29 +8761,108 @@ </td> <td></td> </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>messageKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The key of the message</p> + </td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#findById">GET</h4> + <h4 id="http://www.example.com#getAttachments">GET</h4> + <p>Retrieves the attachments of the message</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2815">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2901">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2902">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2821"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#deleteCourse">DELETE</h4> + <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e2828">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2834">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2840"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#replyToPostAttachment">PUT</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e2847">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e2848">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2852">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2858"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2867">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2905">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2906">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2873"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2907">/repo/courses/{courseId}/version</h3> + <h3 id="d2e2876">/repo/courses/{courseId}/elements/forum/{nodeId}/forum/posts/{messageKey}/attachments/{filename}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9090,27 +8879,6 @@ </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2910">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2911">/repo/courses/{courseId}/configuration</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> <tr> <td> <p><strong>courseId</strong></p> @@ -9122,40 +8890,59 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>nodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> + <tr> + <td> + <p><strong>messageKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The identity key of the user being searched</p> + </td> + </tr> + <tr> + <td> + <p><strong>filename</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The name of the attachment</p> + </td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getConfiguration">GET</h4> + <h4 id="http://www.example.com#getAttachment">GET</h4> + <p>Retrieves the attachment of the message</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2915">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2916">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#updateConfiguration">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2919">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2889">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2927">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2928">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2895"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2929">/repo/courses/{courseId}/authors</h3> + <h3 id="d2e2898">/users/{identityKey}/forums</h3> + <p>Description:<br> + + <P> + Initial Date: 6 déc. 2011 <br> + </p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9165,40 +8952,43 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAuthors">GET</h4> + <h4 id="http://www.example.com#getForums">GET</h4> + <p>Retrieves a list of forums on a user base. All forums of groups + where the user is participant/tutor + all forums in course where + the user is a participant (owner, tutor or participant) + </p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2932">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2933">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#addAuthors">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e2936">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2937">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2910">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2939">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2923"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2940">/repo/courses/{courseId}/resource</h3> + <h3 id="d2e2926">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}</h3> + <p>Description:<br> + Web service to manage a forum. + + <P> + Initial Date: 20 apr. 2010 <br> + </p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9208,28 +8998,56 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> + </tr> + <tr> + <td> + <p><strong>courseKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> + <tr> + <td> + <p><strong>courseNodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getOlatResource">GET</h4> + <h4 id="http://www.example.com#getForum">GET</h4> + <p>Retrieves the forum.</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2937">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2943">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2944">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2950"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2956"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2945">/repo/courses/{courseId}/publish<span class="optional">?locale</span><span class="optional">&access</span><span class="optional">&membersOnly</span></h3> + <h3 id="d2e2959">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9239,18 +9057,39 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> + <tr> + <td> + <p><strong>courseKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>courseNodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#publishCourse">POST</h4> + <h4 id="http://www.example.com#getThreads">GET</h4> + <p>Retrieves the threads in the forum</p> <h6>request query parameters</h6> <table> <tr> @@ -9260,128 +9099,143 @@ </tr> <tr> <td> - <p><strong>locale</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>access</strong></p> + <p><strong>limit</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>membersOnly</strong></p> + <p><strong>orderBy</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>creationDate</tt></p> + </td> + <td> + <p>(value name,creationDate)</p> + </td> + </tr> + <tr> + <td> + <p><strong>asc</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>true</tt></p> + </td> + <td> + <p>(value true/false)</p> </td> - <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2952">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2953">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2975">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2954">/repo/courses/{courseId}/tutors</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getTutors">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2957">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2958">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e2988"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e2994"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#addCoaches">PUT</h4> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#newThreadToForum">PUT</h4> + <p>Creates a new thread in the forum of the course node</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>title</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The title for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>body</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The body for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>authorKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The author user key (optional)</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2961">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2962">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3013">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2964">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3026"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2965">/repo/courses/{courseId}/participants</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getParticipants">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2968">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2969">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3032"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#addParticipants">PUT</h4> + <h4 id="http://www.example.com#newThreadToForumPost">POST</h4> + <p>Creates a new thread in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2972">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2973">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3039">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3046">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2975">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3059"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3065"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2976">/repo/courses/{courseId}/participants/{identityKey}</h3> + <h3 id="d2e3068">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9391,36 +9245,119 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>courseKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> + <tr> + <td> + <p><strong>courseNodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>threadKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The key of the thread</p> + </td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#addParticipant">PUT</h4> + <h4 id="http://www.example.com#getMessages">GET</h4> + <p>Retrieves the messages in the thread</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>start</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>limit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>orderBy</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>creationDate</tt></p> + </td> + <td> + <p>(value name, creationDate)</p> + </td> + </tr> + <tr> + <td> + <p><strong>asc</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>true</tt></p> + </td> + <td> + <p>(value true/false)</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3087">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3100"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2980">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3106"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2982">/repo/courses/{courseId}/file</h3> + <h3 id="d2e3109">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9430,63 +9367,149 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getRepoFileById">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2985">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2986">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2987">/repo/courses/{courseId}/status</h3> - <h6>resource-wide template parameters</h6> - <table> <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p><strong>courseKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>courseNodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> + <tr> + <td> + <p><strong>messageKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The id of the reply message</p> + </td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deleteCoursePermanently">POST</h4> + <h4 id="http://www.example.com#replyToPostPost">POST</h4> + <p>Creates a new reply in the forum of the course node</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e3117">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3130">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3143"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3149"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#replyToPost">PUT</h4> + <p>Creates a new reply in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e2990">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3156">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e3157">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3161">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3174"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#replyToPost">PUT</h4> + <p>Creates a new reply in the forum of the course node</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>title</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The title for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>body</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The body for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>authorKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The author user key (optional)</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3199">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3212"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e2993">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e2994">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3218"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e2995">/repo/courses/{courseId}/runstructure</h3> + <h3 id="d2e3221">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}/attachments</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9496,112 +9519,117 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#findRunStructureById">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e2998">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e2999">/repo/courses/{courseId}/editortreemodel</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>courseKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#findEditorTreeModelById">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3002">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e3003">/repo/courses/{courseId}/authors/{identityKey}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>courseNodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>messageKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the message</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAuthor">GET</h4> + <h4 id="http://www.example.com#getAttachments">GET</h4> + <p>Retrieves the attachments of the message</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3007">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3008">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3231">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3237"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#addAuthor">PUT</h4> + <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e3244">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3011">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3250">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3256"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#removeAuthor">DELETE</h4> + <h4 id="http://www.example.com#replyToPostAttachment">PUT</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e3263">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e3264">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3268">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3274"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3283">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3014">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3015">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3289"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3016">/repo/courses/{courseId}/tutors/{identityKey}</h3> + <h3 id="d2e3292">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}/attachments/{filename}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9611,167 +9639,74 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>courseKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#addCoach">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3020">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e3021">/repo/courses/{courseId}/groups</h3> - <h6>resource-wide template parameters</h6> - <table> <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p><strong>courseNodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>messageKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#putNewGroup">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3024">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - <li><a href="#d2e3025">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3027">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3028">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getGroupList">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3031">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3032">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e3033">/repo/courses/{courseId}/groups/version</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3036">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e3037">/repo/courses/{courseId}/groups/{groupKey}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p>The identity key of the user being searched</p> + </td> </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>filename</strong></p> </td> - <td></td> - </tr> - <tr> <td> - <p><strong>groupKey</strong></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p>The name of the attachment</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getGroup">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3041">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#updateGroup">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3044">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getAttachment">GET</h4> + <p>Retrieves the attachment of the message</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3046">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3305">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#deleteGroup">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3049">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3311"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3050">/repo/courses/{courseId}/groups/{groupKey}/forum</h3> + <h3 id="d2e3314">/users/{identityKey}/forums/group/{groupKey}</h3> <p>Description:<br> Web service to manage a forum. @@ -9787,12 +9722,14 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> <tr> <td> @@ -9811,21 +9748,21 @@ <p>Retrieves the forum.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3060">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e3324">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3073"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3337"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3079"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3343"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3082">/repo/courses/{courseId}/groups/{groupKey}/forum/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> + <h3 id="d2e3346">/users/{identityKey}/forums/group/{groupKey}/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -9835,12 +9772,14 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> <tr> <td> @@ -9911,15 +9850,15 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3098">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e3362">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3111"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3375"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3117"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3381"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -9968,15 +9907,15 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3136">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3400">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3149"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3413"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3155"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3419"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -9984,25 +9923,25 @@ <p>Creates a new thread in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e3162">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3426">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3169">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3433">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3182"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3446"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3188"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3452"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3191">/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> + <h3 id="d2e3455">/users/{identityKey}/forums/group/{groupKey}/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10012,12 +9951,14 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> <tr> <td> @@ -10099,21 +10040,21 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3210">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e3474">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3223"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3487"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3229"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3493"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3232">/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}</h3> + <h3 id="d2e3496">/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10123,12 +10064,14 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> <tr> <td> @@ -10158,19 +10101,19 @@ <p>Creates a new reply in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e3240">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3504">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3253">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3517">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3266"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3530"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3272"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3536"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -10178,20 +10121,20 @@ <p>Creates a new reply in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e3279">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e3280">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e3543">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e3544">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3284">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3548">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3297"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3561"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3303"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3567"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -10240,21 +10183,21 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3322">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e3586">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3335"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3599"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3341"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3605"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3344">/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}/attachments</h3> + <h3 id="d2e3608">/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}/attachments</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10264,12 +10207,14 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> <tr> <td> @@ -10299,11 +10244,11 @@ <p>Retrieves the attachments of the message</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3354">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3618">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3360"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3624"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -10314,15 +10259,15 @@ </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e3367">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3631">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3373">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3637">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3379"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3643"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -10333,16 +10278,16 @@ </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e3386">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e3387">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e3650">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e3651">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3391">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3655">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3397"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3661"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -10353,17 +10298,17 @@ </p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3406">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3670">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3412"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3676"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3415">/repo/courses/{courseId}/groups/{groupKey}/forum/posts/{messageKey}/attachments/{filename}</h3> + <h3 id="d2e3679">/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}/attachments/{filename}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10373,12 +10318,14 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the user (IdentityImpl)</p> + </td> </tr> <tr> <td> @@ -10419,17 +10366,23 @@ <p>Retrieves the attachment of the message</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3428">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3692">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3434"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3698"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3437">/repo/courses/{courseId}/groups/{groupKey}/folder</h3> + <h3 id="d2e3701">/repo/courses/{resourceKey}/certificates</h3> + <p>Initial date: 17.11.2014<br></p> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e3704">/repo/courses/{resourceKey}/certificates/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10439,81 +10392,166 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>resourceKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The primary key of the resource of the repository entry of the course.</p> + </td> </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The owner of the certificate</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> + <h4 id="http://www.example.com#getCertificateInfo">HEAD</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3441">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3442">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3443">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3444">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3445">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3713">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFileToRoot">POST</h4> + <h4 id="http://www.example.com#getCertificate">GET</h4> + <p>Return the certificate as PDF file.</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3720">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3448">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3449">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3726"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3732"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#deleteCertificateInfo">DELETE</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3737">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putCertificate">PUT</h4> + <p>Generate a new certificate.</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>score</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#float">float</a></em></p> + </td> + <td> + <p>The score which appears in the certificate</p> + </td> + </tr> + <tr> + <td> + <p><strong>passed</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td> + <p>The passed/failed which appears in the certificate (true/false)</p> + </td> + </tr> + <tr> + <td> + <p><strong>creationDate</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The date of the certification</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3754"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3760"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3452">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3766"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3457">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3458">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3772"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#putFileToRoot">PUT</h4> + <h4 id="http://www.example.com#postCertificate">POST</h4> + <p>Upload a new certificate.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3461">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3462">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3781"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3787"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3793"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e3797">/ping</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#ping">GET</h4> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3465">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e3466">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e3800">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e3801">/ping/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3468">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3469">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3804">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3470">/repo/courses/{courseId}/groups/{groupKey}/folder/{path:.*}</h3> + <h3 id="d2e3805">/ping/{name}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10523,25 +10561,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>path</strong></p> + <p><strong>name</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -10552,80 +10572,59 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> + <h4 id="http://www.example.com#ping">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3475">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3476">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3477">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3478">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFileToFolder">POST</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3481">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3482">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3483">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3486">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3491">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3492">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3493">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFileToFolder">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3496">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3497">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3498">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3501">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e3502">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3504">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3505">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3809">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e3810">/openmeetings</h3> + <p>Initial date: 13.11.2012<br></p> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e3813">/openmeetings/{identityToken}/portrait</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>identityToken</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The identity key of the user being searched</p> + </td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putFolders">PUT</h4> + <h4 id="http://www.example.com#getPortrait">GET</h4> + <p>Retrieves the portrait of an user</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3508">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3509">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3823">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3512">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3513">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3829"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3514">/repo/courses/{courseId}/groups/{groupKey}/folder/version</h3> + <h3 id="d2e3832">/repo/courses/{courseId}/assessments</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10642,29 +10641,21 @@ </td> <td></td> </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#getCourseResults">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3517">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3836">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3837">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3518">/repo/courses/{courseId}/groups/{groupKey}/folder/metadata/{path:.*}</h3> + <h3 id="d2e3838">/repo/courses/{courseId}/assessments/users/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10683,7 +10674,7 @@ </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -10692,10 +10683,10 @@ </tr> <tr> <td> - <p><strong>path</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -10703,18 +10694,17 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getFileMetadata">GET</h4> + <h4 id="http://www.example.com#getCourseResultsOf">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3522">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3523">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3843">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3844">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3524">/repo/courses/{courseId}/calendar</h3> - <p>Initial date: 23.12.2015<br></p> + <h3 id="d2e3845">/repo/courses/{courseId}/assessments/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10731,19 +10721,6 @@ </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e3527">/repo/courses/{courseId}/calendar/events/{eventId}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> <tr> <td> <p><strong>courseId</strong></p> @@ -10755,7 +10732,7 @@ </tr> <tr> <td> - <p><strong>eventId</strong></p> + <p><strong>nodeId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -10766,17 +10743,29 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deleteEventByCalendar">DELETE</h4> + <h4 id="http://www.example.com#getAssessableResults">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3850">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3851">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postAssessableResults">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e3854">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>)</a></li> + <li><a href="#d2e3855">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3531">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3532">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3857">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3533">/repo/courses/{courseId}/calendar/event</h3> + <h3 id="d2e3858">/repo/courses/{courseId}/assessments/version</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10797,36 +10786,16 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putEventByCalendar">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3536">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e3537">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3539">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3540">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postEventByCalendar">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3543">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3544">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - <li><a href="#d2e3545">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3547">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3548">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3861">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3549">/repo/courses/{courseId}/calendar/events</h3> + <h3 id="d2e3862">/repo/courses/{courseId}/assessments/{nodeId}/users/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10843,92 +10812,14 @@ </td> <td></td> </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#putEventsByCalendar">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3552">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3553">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3555">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3556">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getEventsByCalendar">GET</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>onlyFuture</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>false</tt></p> - </td> - <td></td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3563">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3564">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postEventsByCalendar">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3567">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3568">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3570">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3571">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e3572">/repo/courses/{courseId}/vitero/{subIdentifier}</h3> - <p>Initial date: 14.07.2015<br></p> - <h6>resource-wide template parameters</h6> - <table> <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> </tr> <tr> <td> @@ -10941,10 +10832,10 @@ </tr> <tr> <td> - <p><strong>subIdentifier</strong></p> + <p><strong>nodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -10952,43 +10843,38 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getRooms">GET</h4> - <p>returns the list of booking of the resource.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3582">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#createRoom">PUT</h4> - <p>Return the created or updated booking</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3596">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e3597">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getCourseNodeResultsForNode">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3601">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e3868">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3869">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e3870">/repo/wikis</h3> + <p>The Wikis Webservice.<br /> + OO-112 + </p> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateRoom">POST</h4> - <p>Return the created or updated booking</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3615">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e3616">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getWikis">GET</h4> + <p>get list of repo-entry wikis. Group-Wikis are not listed!</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3620">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e3877">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3878">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3630">/repo/courses/{courseId}/vitero/{subIdentifier}/{bookingId}/members</h3> + <h3 id="d2e3879">/repo/wikis/{wikiKey}</h3> + <p>The Wiki Webservice<br /> + allows the export of "normal" wikis ( in contrast to group-wikis) OO-112 + </p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -10998,63 +10884,36 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>subIdentifier</strong></p> + <p><strong>wikiKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td></td> - </tr> - <tr> <td> - <p><strong>bookingId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - </td> - <td> - <p>The id of the booking</p> + <p>part of the REST path, the resourceable-id / repo-entry-key / + softkey of the wiki resource. + </p> </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getMembers">GET</h4> - <p>Returns the list of members of the booking.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3640">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#addMembers">POST</h4> - <p>Update the list of members of the booking, it add and mutates the - members and delete the missing members. + <h4 id="http://www.example.com#exportWiki">GET</h4> + <p>will export the specified wiki (which must be a repo-entry-wiki) to a CP + and serve as zip-file.<br /> </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3654">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3655">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3659">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> + <li><a href="#d2e3889">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3890">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3669">/repo/courses/{courseId}/vitero/{subIdentifier}/{bookingId}</h3> + <h3 id="d2e3891">/users/{username}/auth</h3> + <p>This web service handles functionalities related to authentication credentials of users.</p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11064,47 +10923,67 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>subIdentifier</strong></p> + <p><strong>username</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>bookingId</strong></p> - </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>The username of the user to retrieve authentication</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deleteRoom">DELETE</h4> - <p>Delete the booking</p> + <h4 id="http://www.example.com#create">PUT</h4> + <p>Creates and persists an authentication</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e3901">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>)</a></li> + <li><a href="#d2e3902">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3906">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3919"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3925"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3931"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3937"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getAuthenticationTokenList">GET</h4> + <p>Returns all user authentications</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3944">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e3955"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3677"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e3959"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3680">/repo/courses/{courseId}/gotomeeting/{subIdentifier}</h3> - <p>Initial date: 24.03.2016<br></p> + <h3 id="d2e3962">/users/{username}/auth/{authKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11114,94 +10993,60 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>username</strong></p> </td> - <td></td> - </tr> - <tr> <td> - <p><strong>subIdentifier</strong></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>The username of the user to retrieve authentication</p> </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e3684">/repo/courses/{courseId}/gotomeeting/{subIdentifier}/trainings</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>authKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The authentication key identifier</p> + </td> </tr> <tr> <td> - <p><strong>subIdentifier</strong></p> + <p><strong>username</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td></td> + <td> + <p>The username of the user</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getTrainings">GET</h4> - <p>returns the list of booking of the resource.</p> + <h4 id="http://www.example.com#delete">DELETE</h4> + <p>Deletes an authentication from the system</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3691">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#createTraining">PUT</h4> - <p>Return the created or updated training</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3705">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> - <li><a href="#d2e3706">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> + <li><a href="#d2e3975"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3710">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#updateTraining">POST</h4> - <p>Return the created or updated training</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3724">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> - <li><a href="#d2e3725">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>)</a></li> + <li><a href="#d2e3981"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3729">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>)</a></li> + <li><a href="#d2e3987"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3739">/repo/courses/{courseId}/gotomeeting/{subIdentifier}//trainings/{trainingKey}</h3> + <h3 id="d2e3990">/users/{username}/auth/password</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11211,46 +11056,57 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>username</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The username of the user to retrieve authentication</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>subIdentifier</strong></p> + <p><strong>username</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>trainingKey</strong></p> - </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p>The username of the user to change the password</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deleteTraining">DELETE</h4> - <p>Delete the training</p> + <h4 id="http://www.example.com#changePassword">POST</h4> + <p>Change the password of a user.</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e3998">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4005"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4011"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4017"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3747"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4023"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3750">/repo/courses/{courseId}/lectureblocks</h3> + <h3 id="d2e4026">/users/{username}/auth/version</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11260,55 +11116,115 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>username</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The username of the user to retrieve authentication</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getLectureBlocks">GET</h4> + <h4 id="http://www.example.com#getVersion">GET</h4> + <p>The version of the User Authentication Web Service</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3753">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3754">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4033">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4043">/repo/lifecycle</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#putLectureBlocks">PUT</h4> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#getPublicLifeCycles">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4046">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4047">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4048">/notifications<span class="optional">?date</span><span class="optional">&type</span></h3> + <p><h3>Description:</h3> + REST API for notifications + <p> + Initial Date: 25 aug 2010 <br> + </p> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getNotifications">GET</h4> + <p>Retrieves the notification of the logged in user.</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>date</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The date (optional)</p> + </td> + </tr> + <tr> + <td> + <p><strong>type</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The type of notifications (User, Forum...) (optional)</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3757">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e3758">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e4064">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3760">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3761">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4077"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4080">/notifications/subscribers</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#postLectureBlocks">POST</h4> + <h4 id="http://www.example.com#subscribe">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e3764">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3765">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> - <li><a href="#d2e3766">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e4083">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>)</a></li> + <li><a href="#d2e4084">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3768">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3769">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4086">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3770">/repo/courses/{courseId}/lectureblocks/configuration</h3> + <h3 id="d2e4087">/notifications/subscribers/{subscriberKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11318,7 +11234,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>subscriberKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -11329,31 +11245,16 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getConfiguration">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3773">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3774">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#updateConfiguration">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e3777">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3778">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> - <li><a href="#d2e3779">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#unsubscribe">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3781">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3782">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4091">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3783">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}</h3> + <h3 id="d2e4092">/notifications/subscribers/{ressourceName}/{ressourceId}/{subIdentifier}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11363,7 +11264,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>ressourceId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -11372,10 +11273,19 @@ </tr> <tr> <td> - <p><strong>lectureBlockKey</strong></p> + <p><strong>subIdentifier</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>ressourceName</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> @@ -11383,23 +11293,22 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getLectureBlock">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3787">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#deleteLectureBlock">DELETE</h4> + <h4 id="http://www.example.com#getSubscriber">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3790">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4098">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4099">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3791">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/teachers/{identityKey}</h3> + <h3 id="d2e4100">/i18n</h3> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e4101">/i18n/{package}/{key}<span class="optional">?locale</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11409,28 +11318,19 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>lectureBlockKey</strong></p> + <p><strong>package</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>key</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> @@ -11438,108 +11338,214 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#addTeacher">PUT</h4> + <h4 id="http://www.example.com#getTranslation">GET</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>locale</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3795">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4108">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4109">/i18n/version</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#removeTeacher">DELETE</h4> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3798">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4112">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3799">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/teachers</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>lectureBlockKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> + <h3 id="d2e4113">/repo/entries<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&managed</span><span class="optional">&externalId</span><span class="optional">&externalRef</span><span class="optional">&resourceType</span></h3> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getTeacher">GET</h4> + <h4 id="http://www.example.com#getEntries">GET</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>start</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>limit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>managed</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>externalId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>externalRef</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>resourceType</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4123">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4124">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getEntriesText">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4127">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4128">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putResource">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3802">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4131">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4132">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3803">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/participants/repositoryentry</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>lectureBlockKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> + <h3 id="d2e4133">/repo/entries/search<span class="optional">?type</span><span class="optional">&author</span><span class="optional">&name</span><span class="optional">&myentries</span></h3> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#addRepositoryEntryParticipantGroup">PUT</h4> + <h4 id="http://www.example.com#searchEntries">GET</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>type</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>author</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>*</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>name</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>*</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>myentries</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>false</tt></p> + </td> + <td></td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3806">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4141">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4142">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4143">/repo/entries/version</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deleteRepositoryEntryParticipantGroup">DELETE</h4> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3809">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4146">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3810">/repo/courses/{courseId}/lectureblocks/{lectureBlockKey}/calendar</h3> + <h3 id="d2e4147">/repo/entries/{repoEntryKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11549,19 +11555,10 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>lectureBlockKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> @@ -11569,37 +11566,46 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#syncCalendar">POST</h4> + <h4 id="http://www.example.com#deleteCourse">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3813">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4151">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4152">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e3814">/repo/wikis</h3> - <p>The Wikis Webservice.<br /> - OO-112 - </p> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getWikis">GET</h4> - <p>get list of repo-entry wikis. Group-Wikis are not listed!</p> + <h4 id="http://www.example.com#getById">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4155">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4156">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#updateEntry">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e4159">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>)</a></li> + <li><a href="#d2e4160">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4162">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4163">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#replaceResource">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3821">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3822">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4166">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4167">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3823">/repo/wikis/{wikiKey}</h3> - <p>The Wiki Webservice<br /> - allows the export of "normal" wikis ( in contrast to group-wikis) OO-112 - </p> + <h3 id="d2e4168">/repo/entries/{repoEntryKey}/coaches/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11609,101 +11615,104 @@ </tr> <tr> <td> - <p><strong>wikiKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>part of the REST path, the resourceable-id / repo-entry-key / - softkey of the wiki resource. - </p> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#exportWiki">GET</h4> - <p>will export the specified wiki (which must be a repo-entry-wiki) to a CP - and serve as zip-file.<br /> - </p> + <h4 id="http://www.example.com#addCoach">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3833">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3834">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4173">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e3835">/pwchange<span class="optional">?identityKey</span></h3> - <p>Webservice to create a temporary key to change the password - - Initial date: 15.10.2013<br> - </p> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#register">PUT</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> + <h4 id="http://www.example.com#removeCoach">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3842">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3843">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4176">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3844">/api</h3> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e3845">/api/version</h3> + <h3 id="d2e4177">/repo/entries/{repoEntryKey}/coaches</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#addCoach">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e4181">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4182">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3848">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4184">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e3849">/api/doc</h3> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getHtmlDoc">GET</h4> + <h4 id="http://www.example.com#getCoaches">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3852">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4187">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4188">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3853">/api/doc/{filename}</h3> + <h3 id="d2e4189">/repo/entries/{repoEntryKey}/file</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11713,7 +11722,16 @@ </tr> <tr> <td> - <p><strong>filename</strong></p> + <p><strong>repoEntryKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -11724,16 +11742,17 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getImage1">GET</h4> + <h4 id="http://www.example.com#getRepoFileById">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3857">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4193">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4194">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3858">/api/{filename}</h3> + <h3 id="d2e4195">/repo/entries/{repoEntryKey}/status</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11743,7 +11762,16 @@ </tr> <tr> <td> - <p><strong>filename</strong></p> + <p><strong>repoEntryKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -11754,57 +11782,73 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getImage2">GET</h4> + <h4 id="http://www.example.com#deleteCoursePermanently">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e4199">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3862">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4202">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4203">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3863">/api/copyright</h3> + <h3 id="d2e4204">/repo/entries/{repoEntryKey}/participants</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getCopyrightXhtml">GET</h4> + <h4 id="http://www.example.com#getParticipants">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3866">application/xhtml+xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3867">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4208">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4209">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#getCopyrightPlainText">GET</h4> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#addParticipants">PUT</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e3870">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4212">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4213">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e3871">/repo/lifecycle</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getPublicLifeCycles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3874">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e3875">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4215">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3876">/repo/courses/{resourceKey}/certificates</h3> - <p>Initial date: 17.11.2014<br></p> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e3879">/repo/courses/{resourceKey}/certificates/{identityKey}</h3> + <h3 id="d2e4216">/repo/entries/{repoEntryKey}/participants/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11814,14 +11858,12 @@ </tr> <tr> <td> - <p><strong>resourceKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p>The primary key of the resource of the repository entry of the course.</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> @@ -11830,129 +11872,38 @@ <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>The owner of the certificate</p> + <p><strong>repoEntryKey</strong></p> </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getCertificateInfo">HEAD</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3888">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#getCertificate">GET</h4> - <p>Return the certificate as PDF file.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3895">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3901"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#addParticipant">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3907"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4221">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#deleteCertificateInfo">DELETE</h4> + <h4 id="http://www.example.com#removeParticipant">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3912">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putCertificate">PUT</h4> - <p>Generate a new certificate.</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>score</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#float">float</a></em></p> - </td> - <td> - <p>The score which appears in the certificate</p> - </td> - </tr> - <tr> - <td> - <p><strong>passed</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - </td> - <td> - <p>The passed/failed which appears in the certificate (true/false)</p> - </td> - </tr> - <tr> - <td> - <p><strong>creationDate</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The date of the certification</p> - </td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3929"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3935"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3941"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3947"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postCertificate">POST</h4> - <p>Upload a new certificate.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3956"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3962"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e3968"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4224">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e3972">/users/{identityKey}/forums</h3> - <p>Description:<br> - - <P> - Initial Date: 6 déc. 2011 <br> - </p> + <h3 id="d2e4226">/repo/entries/{repoEntryKey}/owners</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -11962,43 +11913,49 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>The key of the user (IdentityImpl)</p> + <p><strong>repoEntryKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getForums">GET</h4> - <p>Retrieves a list of forums on a user base. All forums of groups - where the user is participant/tutor + all forums in course where - the user is a participant (owner, tutor or participant) - </p> + <h4 id="http://www.example.com#addOwners">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e4230">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4231">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3984">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> + <li><a href="#d2e4233">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getOwners">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e3997"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4236">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4237">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4000">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}</h3> - <p>Description:<br> - Web service to manage a forum. - - <P> - Initial Date: 20 apr. 2010 <br> - </p> + <h3 id="d2e4238">/repo/entries/{repoEntryKey}/owners/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -12008,18 +11965,16 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p>The key of the user (IdentityImpl)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>courseKey</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -12028,7 +11983,7 @@ </tr> <tr> <td> - <p><strong>courseNodeId</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -12039,25 +11994,23 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getForum">GET</h4> - <p>Retrieves the forum.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4011">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#addOwner">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4024"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4243">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#removeOwner">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4030"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4246">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4033">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> + <h3 id="d2e4247">/repo/entries/{repoEntryKey}/lectureblocks</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -12067,27 +12020,16 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The key of the user (IdentityImpl)</p> - </td> - </tr> - <tr> - <td> - <p><strong>courseKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>courseNodeId</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -12098,154 +12040,44 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getThreads">GET</h4> - <p>Retrieves the threads in the forum</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>orderBy</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>creationDate</tt></p> - </td> - <td> - <p>(value name,creationDate)</p> - </td> - </tr> - <tr> - <td> - <p><strong>asc</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>true</tt></p> - </td> - <td> - <p>(value true/false)</p> - </td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4049">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4062"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getLectureBlocks">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4068"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4251">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4252">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#newThreadToForum">PUT</h4> - <p>Creates a new thread in the forum of the course node</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>title</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The title for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>body</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The body for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>authorKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The author user key (optional)</p> - </td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4087">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#putLectureBlocks">PUT</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e4100"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4255">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e4256">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4106"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4258">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4259">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#newThreadToForumPost">POST</h4> - <p>Creates a new thread in the forum of the course node</p> + <h4 id="http://www.example.com#postLectureBlocks">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e4113">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4120">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4133"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4262">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4263">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> + <li><a href="#d2e4264">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4139"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4266">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4267">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4142">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> + <h3 id="d2e4268">/repo/entries/{repoEntryKey}/lectureblocks/configuration</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -12255,27 +12087,61 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The key of the user (IdentityImpl)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>courseKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getConfiguration">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4271">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4272">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#updateConfiguration">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e4275">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4276">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> + <li><a href="#d2e4277">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4279">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4280">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4281">/repo/entries/{repoEntryKey}/lectureblocks/sync/calendar</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> <tr> <td> - <p><strong>courseNodeId</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -12284,90 +12150,27 @@ </tr> <tr> <td> - <p><strong>threadKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p>The key of the thread</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getMessages">GET</h4> - <p>Retrieves the messages in the thread</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>orderBy</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>creationDate</tt></p> - </td> - <td> - <p>(value name, creationDate)</p> - </td> - </tr> - <tr> - <td> - <p><strong>asc</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>true</tt></p> - </td> - <td> - <p>(value true/false)</p> - </td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4161">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4174"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#syncCalendar">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4284">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4183">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}</h3> + <h3 id="d2e4285">/repo/entries/{repoEntryKey}/lectureblocks/adaptation</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -12377,27 +12180,55 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p>The key of the user (IdentityImpl)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#adapatation">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4288">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4289">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>courseKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>courseNodeId</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -12406,120 +12237,35 @@ </tr> <tr> <td> - <p><strong>messageKey</strong></p> + <p><strong>lectureBlockKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The id of the reply message</p> - </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#replyToPostPost">POST</h4> - <p>Creates a new reply in the forum of the course node</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4191">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4204">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4217"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4223"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPost">PUT</h4> - <p>Creates a new reply in the forum of the course node</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4230">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e4231">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4235">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4248"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#deleteLectureBlock">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4254"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4293">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#replyToPost">PUT</h4> - <p>Creates a new reply in the forum of the course node</p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>title</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The title for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>body</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The body for the first post in the thread</p> - </td> - </tr> - <tr> - <td> - <p><strong>authorKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The author user key (optional)</p> - </td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4273">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4286"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getLectureBlock">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4292"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4296">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4297">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4295">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}/attachments</h3> + <h3 id="d2e4298">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/teachers/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -12529,117 +12275,61 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p>The key of the user (IdentityImpl)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>courseKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>courseNodeId</strong></p> + <p><strong>lectureBlockKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>messageKey</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The key of the message</p> - </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAttachments">GET</h4> - <p>Retrieves the attachments of the message</p> + <h4 id="http://www.example.com#addTeacher">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4305">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4302">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#removeTeacher">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4311"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4318">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4324">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4330"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">PUT</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4337">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e4338">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4342">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4348"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4357">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4363"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4305">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4366">/users/{identityKey}/forums/course/{courseKey}/{courseNodeId}/posts/{messageKey}/attachments/{filename}</h3> + <h3 id="d2e4306">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/teachers</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -12649,27 +12339,56 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p>The key of the user (IdentityImpl)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>courseKey</strong></p> + <p><strong>lectureBlockKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getTeacher">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4309">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4310">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4311">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/participants/repositoryentry</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> <tr> <td> - <p><strong>courseNodeId</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -12678,51 +12397,43 @@ </tr> <tr> <td> - <p><strong>messageKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p>The identity key of the user being searched</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>filename</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><strong>lectureBlockKey</strong></p> </td> <td> - <p>The name of the attachment</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAttachment">GET</h4> - <p>Retrieves the attachment of the message</p> + <h4 id="http://www.example.com#addRepositoryEntryParticipantGroup">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4379">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4314">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deleteRepositoryEntryParticipantGroup">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4385"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4317">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4388">/users/{identityKey}/forums/group/{groupKey}</h3> - <p>Description:<br> - Web service to manage a forum. - - <P> - Initial Date: 20 apr. 2010 <br> - </p> + <h3 id="d2e4318">/repo/entries/{repoEntryKey}/lectureblocks/{lectureBlockKey}/sync/calendar</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -12732,18 +12443,25 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p>The key of the user (IdentityImpl)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>lectureBlockKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -12754,25 +12472,22 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getForum">GET</h4> - <p>Retrieves the forum.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4398">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4411"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#syncCalendar">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4417"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4321">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4420">/users/{identityKey}/forums/group/{groupKey}/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> + <h3 id="d2e4322">/repo/courses/{courseId}/elements/contact<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&coaches</span><span class="optional">&participants</span><span class="optional">&groups</span><span class="optional">&areas</span><span class="optional">&to</span><span class="optional">&defaultSubject</span><span class="optional">&defaultBody</span></h3> + <p>Description:<br> + This handles the contact building block. + + <P> + Initial Date: 10 mai 2010 <br> + </p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -12782,18 +12497,7 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The key of the user (IdentityImpl)</p> - </td> - </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -12804,8 +12508,10 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getThreads">GET</h4> - <p>Retrieves the threads in the forum</p> + <h4 id="http://www.example.com#attachContact">PUT</h4> + <p>This attaches a contact element onto a given course, the element will be + inserted underneath the supplied parentNodeId + </p> <h6>request query parameters</h6> <table> <tr> @@ -12815,256 +12521,221 @@ </tr> <tr> <td> - <p><strong>start</strong></p> + <p><strong>parentNodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The node's id which will be the parent of this structure</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>limit</strong></p> + <p><strong>position</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> </td> - <td></td> + <td> + <p>The node's position relative to its sibling nodes (optional)</p> + </td> </tr> <tr> <td> - <p><strong>orderBy</strong></p> + <p><strong>shortTitle</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>creationDate</tt></p> + <p>Default: <tt>undefined</tt></p> </td> <td> - <p>(value name,creationDate)</p> + <p>The node short title</p> </td> </tr> <tr> <td> - <p><strong>asc</strong></p> + <p><strong>longTitle</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>true</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> </td> <td> - <p>(value true/false)</p> + <p>The node long title</p> </td> </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4436">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4449"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4455"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#newThreadToForum">PUT</h4> - <p>Creates a new thread in the forum of the course node</p> - <h6>request query parameters</h6> - <table> <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p><strong>objectives</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td> + <p>The node learning objectives</p> + </td> </tr> <tr> <td> - <p><strong>title</strong></p> + <p><strong>visibilityExpertRules</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The title for the first post in the thread</p> + <p>The rules to view the node (optional)</p> </td> </tr> <tr> <td> - <p><strong>body</strong></p> + <p><strong>accessExpertRules</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The body for the first post in the thread</p> + <p>The rules to access the node (optional)</p> </td> </tr> <tr> <td> - <p><strong>authorKey</strong></p> + <p><strong>coaches</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>false</tt></p> </td> <td> - <p>The author user key (optional)</p> + <p>Send to coaches (true/false)</p> </td> </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4474">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4487"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4493"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#newThreadToForumPost">POST</h4> - <p>Creates a new thread in the forum of the course node</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4500">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4507">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4520"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4526"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e4529">/users/{identityKey}/forums/group/{groupKey}/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The key of the user (IdentityImpl)</p> - </td> - </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>threadKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The key of the thread</p> - </td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getMessages">GET</h4> - <p>Retrieves the messages in the thread</p> - <h6>request query parameters</h6> - <table> <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p><strong>participants</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>false</tt></p> + </td> + <td> + <p>Send to participants (true/false)</p> + </td> </tr> <tr> <td> - <p><strong>start</strong></p> + <p><strong>groups</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>A list of learning groups (list of keys)</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>limit</strong></p> + <p><strong>areas</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>A list of learning areas (list of keys)</p> </td> - <td></td> </tr> <tr> <td> - <p><strong>orderBy</strong></p> + <p><strong>to</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>creationDate</tt></p> </td> <td> - <p>(value name, creationDate)</p> + <p>The list of e-mail address</p> </td> </tr> <tr> <td> - <p><strong>asc</strong></p> + <p><strong>defaultSubject</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>true</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>(value true/false)</p> + <p>The default subject</p> + </td> + </tr> + <tr> + <td> + <p><strong>defaultBody</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The default body text</p> </td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4548">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + <li><a href="#d2e4376">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4389"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4395"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachContactPost">POST</h4> + <p>This attaches a contact element onto a given course, the element will be + inserted underneath the supplied parentNodeId + </p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e4402">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4425">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4561"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4438"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4567"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4444"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4447">/api</h3> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e4448">/api/doc</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getHtmlDoc">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4451">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4570">/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}</h3> + <h3 id="d2e4452">/api/doc/{filename}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -13074,82 +12745,123 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>filename</strong></p> </td> <td> - <p>The key of the user (IdentityImpl)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getImage1">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4456">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4457">/api/{filename}</h3> + <h6>resource-wide template parameters</h6> + <table> <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>messageKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>filename</strong></p> </td> <td> - <p>The id of the reply message</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#replyToPostPost">POST</h4> - <p>Creates a new reply in the forum of the course node</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4578">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4591">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4604"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getImage2">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4610"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4461">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4462">/api/copyright</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#replyToPost">PUT</h4> - <p>Creates a new reply in the forum of the course node</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4617">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - <li><a href="#d2e4618">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getCopyrightXhtml">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4622">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e4465">application/xhtml+xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4466">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getCopyrightPlainText">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4635"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4469">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4470">/api/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4641"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4473">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4475">/repo/courses/{courseId}/elements/enrollment<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&groups</span><span class="optional">&cancelEnabled</span></h3> + <p>Description:<br> + This handles the enrollment building block. + + <P> + Initial Date: 10 mai 2010 <br> + </p> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The course resourceable's id</p> + </td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#replyToPost">PUT</h4> - <p>Creates a new reply in the forum of the course node</p> + <h4 id="http://www.example.com#attachEnrolmment">PUT</h4> + <p>This attaches an enrollment element onto a given course, the element will be + inserted underneath the supplied parentNodeId + </p> <h6>request query parameters</h6> <table> <tr> @@ -13159,55 +12871,147 @@ </tr> <tr> <td> - <p><strong>title</strong></p> + <p><strong>parentNodeId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td> - <p>The title for the first post in the thread</p> + <p>The node's id which will be the parent of this structure</p> </td> </tr> <tr> <td> - <p><strong>body</strong></p> + <p><strong>position</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> </td> <td> - <p>The body for the first post in the thread</p> + <p>The node's position relative to its sibling nodes (optional)</p> </td> </tr> <tr> <td> - <p><strong>authorKey</strong></p> + <p><strong>shortTitle</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> </td> <td> - <p>The author user key (optional)</p> + <p>The node short title</p> + </td> + </tr> + <tr> + <td> + <p><strong>longTitle</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td> + <p>The node long title</p> + </td> + </tr> + <tr> + <td> + <p><strong>objectives</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td> + <p>The node learning objectives</p> + </td> + </tr> + <tr> + <td> + <p><strong>visibilityExpertRules</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The rules to view the node (optional)</p> + </td> + </tr> + <tr> + <td> + <p><strong>accessExpertRules</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The rules to access the node (optional)</p> + </td> + </tr> + <tr> + <td> + <p><strong>groups</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>A list of learning groups (list of keys)</p> + </td> + </tr> + <tr> + <td> + <p><strong>cancelEnabled</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>false</tt></p> + </td> + <td> + <p>cancel enrollment enabled or not</p> </td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4660">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + <li><a href="#d2e4515">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4528"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4534"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachEnrollmenetPost">POST</h4> + <p>This attaches an enrollment element onto a given course, the element will be + inserted underneath the supplied parentNodeId + </p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e4541">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4572">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4673"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4585"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4679"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4591"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4682">/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}/attachments</h3> + <h3 id="d2e4594">/repo/courses/{courseId}/elements/enrollment/{nodeId}/groups</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -13217,18 +13021,18 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td> - <p>The key of the user (IdentityImpl)</p> + <p>The course resourceable's id</p> </td> </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>courseId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -13237,88 +13041,50 @@ </tr> <tr> <td> - <p><strong>messageKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>nodeId</strong></p> </td> <td> - <p>The key of the message</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAttachments">GET</h4> - <p>Retrieves the attachments of the message</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4692">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4698"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4705">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4711">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getGroups">GET</h4> + <p>Retrieves the groups where the enrollment happens</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4717"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">PUT</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4724">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e4725">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e4603">application/xml, application/json (<abbr title="{http://www.example.com} groupVO">ns3:groupVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4729">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4616"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4735"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4622"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4625">/catalog</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> - <p>Upload the attachment of a message, as parameter:<br> - filename The name of the attachment<br> - file The attachment. - </p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4744">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getRoots">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4750"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4628">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4629">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4753">/users/{identityKey}/forums/group/{groupKey}/posts/{messageKey}/attachments/{filename}</h3> + <h3 id="d2e4630">/catalog/{path:.*}/children<span class="optional">?start</span><span class="optional">&limit</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -13328,72 +13094,56 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The key of the user (IdentityImpl)</p> - </td> - </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>messageKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The identity key of the user being searched</p> - </td> - </tr> - <tr> - <td> - <p><strong>filename</strong></p> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td> - <p>The name of the attachment</p> - </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAttachment">GET</h4> - <p>Retrieves the attachment of the message</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4766">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getChildren">GET</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>start</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>limit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> + </td> + <td></td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4772"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4637">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4638">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4775">/vitero</h3> - <p>Initial date: 06.07.2015<br></p> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e4778">/vitero/{resourceName}/{resourceId}/{subIdentifier}</h3> - <p>Initial date: 14.07.2015<br></p> + <h3 id="d2e4639">/catalog/{path:.*}/owners/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -13403,7 +13153,7 @@ </tr> <tr> <td> - <p><strong>resourceName</strong></p> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -13412,138 +13162,41 @@ </tr> <tr> <td> - <p><strong>resourceId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>subIdentifier</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getRooms">GET</h4> - <p>returns the list of booking of the resource.</p> + <h4 id="http://www.example.com#addOwner">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4790">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> + <li><a href="#d2e4644">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#createRoom">PUT</h4> - <p>Return the created or updated booking</p> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#removeOwner">DELETE</h4> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4804">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e4805">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4809">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#updateRoom">POST</h4> - <p>Return the created or updated booking</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4823">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - <li><a href="#d2e4824">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4828">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>)</a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e4838">/vitero/{resourceName}/{resourceId}/{subIdentifier}/{bookingId}/members</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>resourceName</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>resourceId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>subIdentifier</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>bookingId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - </td> - <td> - <p>The id of the booking</p> - </td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getMembers">GET</h4> - <p>Returns the list of members of the booking.</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4848">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> + <li><a href="#d2e4647">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#addMembers">POST</h4> - <p>Update the list of members of the booking, it add and mutates the - members and delete the missing members. - </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e4862">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e4863">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getOwner">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4867">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>)</a></li> + <li><a href="#d2e4650">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e4877">/vitero/{resourceName}/{resourceId}/{subIdentifier}/{bookingId}</h3> + <h3 id="d2e4651">/catalog/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -13553,92 +13206,39 @@ </tr> <tr> <td> - <p><strong>resourceName</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>resourceId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>subIdentifier</strong></p> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>bookingId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deleteRoom">DELETE</h4> - <p>Delete the booking</p> + <h4 id="http://www.example.com#getCatalogEntry">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4885"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4655">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4656">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e4888">/users</h3> - <p>This web service handles functionalities related to <code>User</code>.</p> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#create">PUT</h4> - <p>Creates and persists a new user entity</p> + <h4 id="http://www.example.com#addCatalogEntry">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e4895">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> - <li><a href="#d2e4896">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> + <li><a href="#d2e4659">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> + <li><a href="#d2e4660">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4900">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4913"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4919">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4662">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4663">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#getUserListQuery">GET</h4> - <p>Search users and return them in a simple form (without user properties). User properties - can be added two the query parameters. If the authUsername and the authProvider are set, - the search is made only with these two parameters because they are sufficient to return - a single user.<br> - The search with login and user properties are made default with wild cards. If an exact - match is needed, the parameter msut be quoted:<br> - users?login="username"<br> - Don't forget the right escaping in the URL!<br> - You can make a search with the user properties like this:<br> - users?telMobile=39847592&login=test - </p> + <h4 id="http://www.example.com#addCatalogEntry">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -13648,7 +13248,7 @@ </tr> <tr> <td> - <p><strong>login</strong></p> + <p><strong>name</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -13657,7 +13257,7 @@ </tr> <tr> <td> - <p><strong>authProvider</strong></p> + <p><strong>description</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -13666,101 +13266,73 @@ </tr> <tr> <td> - <p><strong>authUsername</strong></p> + <p><strong>type</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>statusVisibleLimit</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4940">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4953"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4671">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4672">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e4956">/users/{identityKey}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The user key identifier of the user being searched</p> - </td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#update">POST</h4> - <p>Update an user</p> + <h4 id="http://www.example.com#updatePostCatalogEntry">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e4964">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> - <li><a href="#d2e4965">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4969">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>)</a></li> + <li><a href="#d2e4675">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e4982"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4988"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e4994">application/xml, application/json (<abbr title="{http://www.example.com} errorVO">ns3:errorVO</abbr>)</a></li> + <li><a href="#d2e4680">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4681">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#delete">DELETE</h4> - <p>Delete an user from the system</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5010"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#updateCatalogEntry">POST</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>newParentKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5016"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4685">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> + <li><a href="#d2e4686">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5022"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4688">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4689">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#findById">GET</h4> - <p>Retrieves an user given its unique key identifier</p> + <h4 id="http://www.example.com#updateCatalogEntry">POST</h4> <h6>request query parameters</h6> <table> <tr> @@ -13770,34 +13342,50 @@ </tr> <tr> <td> - <p><strong>withPortrait</strong></p> + <p><strong>name</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>false</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>description</strong></p> </td> <td> - <p>If true return the portrait as Base64 (default false)</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>newParentKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5035">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5048"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4696">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4697">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deleteCatalogEntry">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5054"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4700">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4701">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5057">/users/{identityKey}/status</h3> + <h3 id="d2e4702">/catalog/{path:.*}/owners</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -13807,66 +13395,125 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>path</strong></p> </td> <td> - <p>The user key identifier of the user being searched</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getStatus">GET</h4> - <p>Retrieves the status of a user given its unique key identifier</p> + <h4 id="http://www.example.com#getOwners">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5067">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4706">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4707">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4708">/catalog/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5080"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4711">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4712">/system</h3> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e4713">/system/environment</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getEnvironnementXml">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5086"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4716">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4717">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4718">/system/release</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateStatus">POST</h4> - <p>Update the roles of a user given its unique key identifier: - <ul> - <li>1: Permanent user</li> - <li>2: activ</li> - <li>101: login denied</li> - <li>199: deleted</li> - </ul> - </p> + <h4 id="http://www.example.com#getReleaseInfos">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4721">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4722">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4723">/system/notifications</h3> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e4724">/system/notifications/status</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getStatus">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4727">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4728">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#setStatus">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5093">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>)</a></li> - <li><a href="#d2e5094">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>)</a></li> + <li><a href="#d2e4731">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5098">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4734">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getPlainTextStatus">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5111"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4737">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4738">/system/log</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getCurrentLogFile">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5117"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4741">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4742">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5120">/users/{identityKey}/roles</h3> + <h3 id="d2e4743">/system/log/{date}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -13876,236 +13523,519 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><strong>date</strong></p> </td> <td> - <p>The user key identifier of the user being searched</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getRoles">GET</h4> - <p>Retrieves the roles of a user given its unique key identifier</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5130">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5143"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getLogFileByDate">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5149"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4747">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4748">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4749">/system/log/version</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateRoles">POST</h4> - <p>Update the roles of a user given its unique key identifier</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e5156">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>)</a></li> - <li><a href="#d2e5157">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5161">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4752">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4753">/system/monitoring</h3> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e4754">/system/monitoring/configuration</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getImplementedProbes">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5174"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4757">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4758">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4759">/system/monitoring/status</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getSystemSummaryVO">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4762">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4763">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5183">/users/version</h3> + <h3 id="d2e4764">/system/monitoring/runtime</h3> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p>The version of the User Web Service</p> + <h4 id="http://www.example.com#getSystemSummaryVO">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5190">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4767">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4768">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5200">/users/{identityKey}/portrait</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The identity key identifier of the user being searched</p> - </td> - </tr> - </table> + <h3 id="d2e4769">/system/monitoring/runtime/memory</h3> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getPortrait">GET</h4> - <p>Retrieves the portrait of an user</p> + <h4 id="http://www.example.com#getMemoryStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5210">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4772">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4773">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4774">/system/monitoring/runtime/threads</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getThreadStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5216"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4777">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4778">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4779">/system/monitoring/runtime/classes</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getPortraitHead">HEAD</h4> - <p>Retrieves the portrait of an user</p> + <h4 id="http://www.example.com#getCompilationXml">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5225">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4782">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4783">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4784">/system/monitoring/database</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getDatabaseStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5231"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4787">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4788">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4789">/system/monitoring/openolat</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#postPortrait">POST</h4> - <p>Upload the portrait of an user</p> + <h4 id="http://www.example.com#getStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5240">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4792">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4793">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4794">/system/monitoring/openolat/tasks</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getTasks">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5246"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4797">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4798">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4799">/system/monitoring/openolat/users</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getUserStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5252"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4802">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4803">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4804">/system/monitoring/openolat/repository</h3> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#deletePortrait">DELETE</h4> - <p>Deletes the portrait of an user</p> + <h4 id="http://www.example.com#getRepositoryStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5261"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4807">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4808">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4809">/system/monitoring/openolat/sessions</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getSessions">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5267"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4812">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4813">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5270">/users/managed</h3> + <h3 id="d2e4814">/system/monitoring/openolat/indexer</h3> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getManagedUsers">GET</h4> + <h4 id="http://www.example.com#getStatistics">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5273">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5274">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4817">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4818">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5275">/users/{identityKey}/preferences</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The user key identifier of the user being searched</p> - </td> - </tr> - </table> + <h3 id="d2e4819">/system/monitoring/openolat/indexer/status</h3> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getUserPreferences">GET</h4> - <p>Retrieves the preferences of a user given its unique key identifier</p> + <h4 id="http://www.example.com#getStatus">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5285">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4822">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4823">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - <p><em>available response representations:</em></p> + </div> + <div class="method"> + <h4 id="http://www.example.com#setStatus">POST</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5298"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4826">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5304"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4829">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#updatePreferences">POST</h4> - <p>Update the preferences of a user given its unique key identifier</p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e5311">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>)</a></li> - <li><a href="#d2e5312">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getPlainTextStatus">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5316">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4832">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4833">/system/monitoring/memory</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getMemory">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5329"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4836">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getMemoryXml">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5335"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4839">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4840">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5338">/users/{identityKey}/portrait/{size}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> + <h3 id="d2e4841">/system/monitoring/memory/pools</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getMemoryPools">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4844">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getMemoryPoolsXml">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4847">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4848">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4849">/system/monitoring/memory/samples<span class="optional">?from</span><span class="optional">&to</span><span class="optional">&lastSamples</span></h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getSamplesXml">GET</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>from</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>to</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>lastSamples</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + </td> + <td></td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4856">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4857">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4858">/system/monitoring/threads</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getThreads">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4861">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getThreadsXml">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4864">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4865">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4866">/system/monitoring/threads/cpu</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getThreadsCpu">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4869">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4870">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4871">/system/indexer</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getStatistics">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4874">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4875">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4876">/system/indexer/status</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getStatus">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4879">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4880">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#setStatus">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e4883">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4886">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getPlainTextStatus">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4889">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4890">/registration<span class="optional">?email</span></h3> + <p>Description:<br> + Web service to trigger the registration process + + <P> + Initial Date: 14 juil. 2011 <br> + </p> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#register">PUT</h4> + <p>Register with the specified email</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>email</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The email address</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4901"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4905"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#registerPost">POST</h4> + <p>Register with the specified email</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e4912">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4917"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4921"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4924">/repo/sharedfolder</h3> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e4925">/repo/sharedfolder/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e4928">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e4929">/repo/sharedfolder/{repoEntryKey}/{path:.*}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> <th>value</th> <th>description</th> </tr> <tr> <td> - <p><strong>size</strong></p> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -14114,7 +14044,7 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -14125,26 +14055,16 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getOriginalPortraitHead">HEAD</h4> - <p>Retrieves the portrait of an user</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5347">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getSharedFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5353"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4934">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5357">/users/{identityKey}/folders</h3> - <p>Description:<br> - - <P> - Initial Date: 16 déc. 2011 <br> - </p> + <h3 id="d2e4935">/repo/sharedfolder/{repoEntryKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14154,7 +14074,7 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -14165,24 +14085,16 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getFolders">GET</h4> - <p>Retrieves a list of folders on a user base. All folders of groups - where the user is participant/tutor + all folders in course where - the user is a participant (owner, tutor or participant) - </p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5367">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>)</a></li> - </ul> + <h4 id="http://www.example.com#getSharedFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5380"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4939">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5383">/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}</h3> + <h3 id="d2e4940">/repo/sharedfolder/{repoEntryKey}/files</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14192,31 +14104,13 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>courseNodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> @@ -14224,58 +14118,58 @@ <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5388">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5389">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5390">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5391">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5392">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4944">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4945">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4946">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4947">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4948">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#postFileToRoot">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5395">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5396">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4951">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4952">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5399">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4955">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5404">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5405">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4960">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4961">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFileToRoot">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5408">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5409">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4964">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4965">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5412">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5413">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e4968">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e4969">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5415">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5416">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4971">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4972">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5417">/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/{path:.*}</h3> + <h3 id="d2e4973">/repo/sharedfolder/{repoEntryKey}/files/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14285,7 +14179,7 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -14294,28 +14188,10 @@ </tr> <tr> <td> - <p><strong>courseKey</strong></p> + <p><strong>path</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseNodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> @@ -14326,77 +14202,77 @@ <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5421">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5422">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5423">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5424">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5425">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4977">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4978">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4979">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4980">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4981">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#postFileToFolder">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5428">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5429">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5430">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4984">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4985">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4986">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5433">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4989">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5438">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5439">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5440">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4994">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4995">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4996">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5443">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5444">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5445">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e4999">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5000">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5001">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5448">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5449">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5004">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5005">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5451">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5007">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5008">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFolders">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5455">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5456">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5011">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5012">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5459">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5460">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5015">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5016">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5461">/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/version</h3> + <h3 id="d2e5017">/repo/sharedfolder/{repoEntryKey}/files/metadata/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14406,16 +14282,7 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -14424,7 +14291,7 @@ </tr> <tr> <td> - <p><strong>courseNodeId</strong></p> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -14435,16 +14302,17 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#getFileMetadata">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5464">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5021">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5022">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5465">/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/metadata/{path:.*}</h3> + <h3 id="d2e5023">/repo/sharedfolder/{repoEntryKey}/files/version</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14454,55 +14322,58 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseKey</strong></p> + <p><strong>repoEntryKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>courseNodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getFileMetadata">GET</h4> + <h4 id="http://www.example.com#getVersion">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5026">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e5027">/repo/forums</h3> + <p>Description:<br> + Web service to manage forums. + + <P> + Initial Date: 26 aug. 2010 <br> + </p> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e5030">/repo/forums/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> + <p>The version of the Forum Web Service</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5469">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5470">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5035">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5471">/users/{identityKey}/folders/personal</h3> + <h3 id="d2e5045">/repo/forums/{forumKey}</h3> + <p>Description:<br> + Web service to manage a forum. + + <P> + Initial Date: 20 apr. 2010 <br> + </p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14512,72 +14383,38 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>forumKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the forum</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5475">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5476">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5477">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5478">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFileToRoot">POST</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5481">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5482">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e5485">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#getForum">GET</h4> + <p>Retrieves the forum.</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5490">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5491">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5057">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>)</a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFileToRoot">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5494">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5495">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e5498">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5499">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5070"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5501">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5502">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5076"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5503">/users/{identityKey}/folders/personal/{path:.*}</h3> + <h3 id="d2e5079">/repo/forums/{forumKey}/threads<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14587,100 +14424,167 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>forumKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>The key of the forum</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> + <h4 id="http://www.example.com#getThreads">GET</h4> + <p>Retrieves the threads in the forum</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>start</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>limit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>orderBy</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>creationDate</tt></p> + </td> + <td> + <p>(value name,creationDate)</p> + </td> + </tr> + <tr> + <td> + <p><strong>asc</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>true</tt></p> + </td> + <td> + <p>(value true/false)</p> + </td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5507">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5508">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5509">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5510">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5511">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5095">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5108"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFileToFolder">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5514">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5515">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5516">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5114"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#newThreadToForum">PUT</h4> + <p>Creates a new thread in the forum of the course node</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>title</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The title for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>body</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The body for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>authorKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The author user key (optional)</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5519">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5133">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5524">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5525">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5526">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5146"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5529">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5530">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5531">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5152"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> + <h4 id="http://www.example.com#newThreadToForumPost">POST</h4> + <p>Creates a new thread in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5534">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5535">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5159">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5537">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5538">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5166">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFolders">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5541">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5542">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5179"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5545">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5546">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5185"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5547">/users/{identityKey}/folders/personal/version</h3> + <h3 id="d2e5188">/repo/forums/{forumKey}/posts/{threadKey}<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&orderBy</span><span class="optional">&asc</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14690,67 +14594,101 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>forumKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5550">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e5551">/users/{identityKey}/folders/personal/metadata/{path:.*}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> + <td> + <p>The key of the forum</p> + </td> </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>threadKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>The key of the thread</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getFileMetadata">GET</h4> + <h4 id="http://www.example.com#getMessages">GET</h4> + <p>Retrieves the messages in the thread</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>start</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>limit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>orderBy</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>creationDate</tt></p> + </td> + <td> + <p>(value name, creationDate)</p> + </td> + </tr> + <tr> + <td> + <p><strong>asc</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>true</tt></p> + </td> + <td> + <p>(value true/false)</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5207">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5220"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5555">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5556">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5226"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5557">/users/{identityKey}/folders/group/{groupKey}</h3> + <h3 id="d2e5229">/repo/forums/{forumKey}/posts/{messageKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14760,81 +14698,131 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>forumKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the forum</p> + </td> </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>messageKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The id of the reply message</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> + <h4 id="http://www.example.com#replyToPostPost">POST</h4> + <p>Creates a new reply in the forum of the course node</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e5237">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5561">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5562">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5563">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5564">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5565">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5250">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5263"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFileToRoot">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5568">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5569">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5269"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> + <h4 id="http://www.example.com#replyToPost">PUT</h4> + <p>Creates a new reply in the forum of the course node</p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5572">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5276">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> + <li><a href="#d2e5277">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5577">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5578">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5281">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5294"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFileToRoot">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5581">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5582">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5300"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#replyToPost">PUT</h4> + <p>Creates a new reply in the forum of the course node</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>title</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The title for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>body</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The body for the first post in the thread</p> + </td> + </tr> + <tr> + <td> + <p><strong>authorKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td> + <p>The author user key (optional)</p> + </td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5319">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5585">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5586">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5332"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5588">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5589">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5338"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5590">/users/{identityKey}/folders/group/{groupKey}/{path:.*}</h3> + <h3 id="d2e5341">/repo/forums/{forumKey}/posts/{messageKey}/attachments</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14844,109 +14832,99 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>forumKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the forum</p> + </td> </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>messageKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>The key of the message</p> </td> - <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#listFiles">GET</h4> + <h4 id="http://www.example.com#getAttachments">GET</h4> + <p>Retrieves the attachments of the message</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5594">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5595">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5596">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5597">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5598">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5351">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#postFileToFolder">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5601">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5602">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5603">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5357"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> + <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5606">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5364">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5611">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5612">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5613">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5370">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5616">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5617">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5618">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5376"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> + <h4 id="http://www.example.com#replyToPostAttachment">PUT</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5621">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e5622">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5383">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5384">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5624">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5625">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5388">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#putFolders">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5628">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5629">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5394"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#deleteItem">DELETE</h4> + <h4 id="http://www.example.com#replyToPostAttachment">POST</h4> + <p>Upload the attachment of a message, as parameter:<br> + filename The name of the attachment<br> + file The attachment. + </p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5403">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5632">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5633">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5409"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5634">/users/{identityKey}/folders/group/{groupKey}/version</h3> + <h3 id="d2e5412">/repo/forums/{forumKey}/posts/{messageKey}/attachments/{filename}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -14956,107 +14934,61 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>forumKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The key of the forum</p> + </td> </tr> <tr> <td> - <p><strong>groupKey</strong></p> + <p><strong>messageKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The identity key of the user being searched</p> + </td> + </tr> + <tr> + <td> + <p><strong>filename</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td> + <p>The name of the attachment</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#getAttachment">GET</h4> + <p>Retrieves the attachment of the message</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5425">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5637">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5431"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5638">/users/{identityKey}/folders/group/{groupKey}/metadata/{path:.*}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>groupKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getFileMetadata">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5642">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5643">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e5644">/users/{identityKey}/courses</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> + <h3 id="d2e5434">/auth</h3> <h6>Methods</h6> <div class="methods"></div> </div> <div class="resource"> - <h3 id="d2e5646">/users/{identityKey}/courses/my<span class="optional">?start</span><span class="optional">&limit</span></h3> + <h3 id="d2e5435">/auth/{username}<span class="optional">?password</span><span class="optional">&x-olat-token</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15066,10 +14998,10 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>username</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> @@ -15077,8 +15009,7 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getMyCourses">GET</h4> - <p>Retrieves the list of "My entries" but limited to courses.</p> + <h4 id="http://www.example.com#login">GET</h4> <h6>request query parameters</h6> <table> <tr> @@ -15088,64 +15019,83 @@ </tr> <tr> <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> + <p><strong>password</strong></p> </td> <td> - <p>The first result</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> + <p><strong>x-olat-token</strong></p> </td> <td> - <p>Max result</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5660">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> + <li><a href="#d2e5442">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5443">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e5444">/auth/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5673"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5447">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5676">/users/{identityKey}/courses/teached<span class="optional">?start</span><span class="optional">&limit</span></h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityKey</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> + <h3 id="d2e5448">/users</h3> + <p>This web service handles functionalities related to <code>User</code>.</p> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getTeachedCourses">GET</h4> - <p>Retrieves the list of "My supervised courses" but limited to courses.</p> + <h4 id="http://www.example.com#create">PUT</h4> + <p>Creates and persists a new user entity</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e5455">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> + <li><a href="#d2e5456">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5460">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5473"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5479">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getUserListQuery">GET</h4> + <p>Search users and return them in a simple form (without user properties). User properties + can be added two the query parameters. If the authUsername and the authProvider are set, + the search is made only with these two parameters because they are sufficient to return + a single user.<br> + The search with login and user properties are made default with wild cards. If an exact + match is needed, the parameter msut be quoted:<br> + users?login="username"<br> + Don't forget the right escaping in the URL!<br> + You can make a search with the user properties like this:<br> + users?telMobile=39847592&login=test + </p> <h6>request query parameters</h6> <table> <tr> @@ -15155,42 +15105,54 @@ </tr> <tr> <td> - <p><strong>start</strong></p> + <p><strong>login</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>The first result</p> + <p><strong>authProvider</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> <tr> <td> - <p><strong>limit</strong></p> + <p><strong>authUsername</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>Max result</p> + <p><strong>statusVisibleLimit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> + <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5690">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> + <li><a href="#d2e5500">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5703"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5513"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5706">/users/{identityKey}/courses/favorite<span class="optional">?start</span><span class="optional">&limit</span></h3> + <h3 id="d2e5516">/users/{identityKey}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15205,14 +15167,57 @@ <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The user key identifier of the user being searched</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getFavoritCourses">GET</h4> - <p>Retrieves the list of my favorite courses.</p> + <h4 id="http://www.example.com#update">POST</h4> + <p>Update an user</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e5524">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> + <li><a href="#d2e5525">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5529">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5542"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5548"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5554">application/xml, application/json (<abbr title="{http://www.example.com} errorVO">ns3:errorVO</abbr>)</a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#delete">DELETE</h4> + <p>Delete an user from the system</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5570"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5576"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5582"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#findById">GET</h4> + <p>Retrieves an user given its unique key identifier</p> <h6>request query parameters</h6> <table> <tr> @@ -15222,42 +15227,34 @@ </tr> <tr> <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td> - <p>The first result</p> - </td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> + <p><strong>withPortrait</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p>Default: <tt>false</tt></p> </td> <td> - <p>Max result</p> + <p>If true return the portrait as Base64 (default false)</p> </td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5720">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> + <li><a href="#d2e5595">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5608"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5733"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5614"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5736">/users/{identityKey}/groups<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&externalId</span><span class="optional">&managed</span></h3> + <h3 id="d2e5617">/users/{identityKey}/portrait</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15272,69 +15269,69 @@ <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The identity key identifier of the user being searched</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getUserGroupList">GET</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>externalId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>managed</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - </td> - <td></td> - </tr> - </table> + <h4 id="http://www.example.com#getPortrait">GET</h4> + <p>Retrieves the portrait of an user</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5627">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5633"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#getPortraitHead">HEAD</h4> + <p>Retrieves the portrait of an user</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5642">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5648"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postPortrait">POST</h4> + <p>Upload the portrait of an user</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5657">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5663"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5669"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deletePortrait">DELETE</h4> + <p>Deletes the portrait of an user</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5678"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5745">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5746">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5684"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5747">/users/{identityKey}/groups/owner<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&externalId</span><span class="optional">&managed</span></h3> + <h3 id="d2e5687">/users/{identityKey}/status</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15349,69 +15346,61 @@ <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The user key identifier of the user being searched</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getOwnedGroupList">GET</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>externalId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>managed</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - </td> - <td></td> - </tr> - </table> + <h4 id="http://www.example.com#getStatus">GET</h4> + <p>Retrieves the status of a user given its unique key identifier</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5697">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5710"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5716"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#updateStatus">POST</h4> + <p>Update the roles of a user given its unique key identifier: + <ul> + <li>1: Permanent user</li> + <li>2: activ</li> + <li>101: login denied</li> + <li>199: deleted</li> + </ul> + </p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e5723">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>)</a></li> + <li><a href="#d2e5724">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5728">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5755">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5756">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5741"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5747"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5757">/users/{identityKey}/groups/participant<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&externalId</span><span class="optional">&managed</span></h3> + <h3 id="d2e5750">/users/{identityKey}/roles</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15426,69 +15415,68 @@ <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The user key identifier of the user being searched</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getParticipatingGroupList">GET</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>externalId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>managed</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - </td> - <td></td> - </tr> - </table> + <h4 id="http://www.example.com#getRoles">GET</h4> + <p>Retrieves the roles of a user given its unique key identifier</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5760">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5773"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5779"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#updateRoles">POST</h4> + <p>Update the roles of a user given its unique key identifier</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e5786">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>)</a></li> + <li><a href="#d2e5787">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5791">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5804"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5810"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e5813">/users/managed</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getManagedUsers">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5765">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5766">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5816">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5817">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5767">/users/{identityKey}/groups/infos<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&externalId</span><span class="optional">&managed</span></h3> + <h3 id="d2e5818">/users/{identityKey}/preferences</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15503,69 +15491,54 @@ <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td></td> + <td> + <p>The user key identifier of the user being searched</p> + </td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getUserGroupInfosList">GET</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>externalId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>managed</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - </td> - <td></td> - </tr> - </table> + <h4 id="http://www.example.com#getUserPreferences">GET</h4> + <p>Retrieves the preferences of a user given its unique key identifier</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5828">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5841"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5847"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#updatePreferences">POST</h4> + <p>Update the preferences of a user given its unique key identifier</p> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e5854">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>)</a></li> + <li><a href="#d2e5855">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5859">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5872"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5775">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5776">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5878"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5777">/repo/courses/{courseId}/assessments</h3> + <h3 id="d2e5881">/users/{identityKey}/portrait/{size}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15575,7 +15548,16 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>size</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -15586,17 +15568,40 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getCourseResults">GET</h4> + <h4 id="http://www.example.com#getOriginalPortraitHead">HEAD</h4> + <p>Retrieves the portrait of an user</p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5890">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5896"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e5899">/users/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> + <p>The version of the User Web Service</p> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5781">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5782">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5906">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5783">/repo/courses/{courseId}/assessments/version</h3> + <h3 id="d2e5917">/users/{identityKey}/folders</h3> + <p>Description:<br> + + <P> + Initial Date: 16 déc. 2011 <br> + </p> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15606,7 +15611,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -15617,16 +15622,24 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#getFolders">GET</h4> + <p>Retrieves a list of folders on a user base. All folders of groups + where the user is participant/tutor + all folders in course where + the user is a participant (owner, tutor or participant) + </p> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5927">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5786">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5940"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5787">/repo/courses/{courseId}/assessments/users/{identityKey}</h3> + <h3 id="d2e5943">/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15636,7 +15649,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -15645,7 +15658,7 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>courseKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -15654,10 +15667,10 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>courseNodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> @@ -15665,17 +15678,61 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getCourseResultsOf">GET</h4> + <h4 id="http://www.example.com#listFiles">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5948">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5949">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5950">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5951">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5952">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFileToRoot">POST</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5955">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5956">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e5959">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5964">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5965">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFileToRoot">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5792">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5793">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5968">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5969">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e5972">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e5973">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5975">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5976">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5794">/repo/courses/{courseId}/assessments/{nodeId}</h3> + <h3 id="d2e5977">/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15685,7 +15742,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -15694,7 +15751,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>courseKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -15703,7 +15760,16 @@ </tr> <tr> <td> - <p><strong>nodeId</strong></p> + <p><strong>courseNodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -15714,29 +15780,80 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getAssessableResults">GET</h4> + <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5799">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5800">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5981">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5982">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5983">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5984">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5985">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#postAssessableResults">POST</h4> + <h4 id="http://www.example.com#postFileToFolder">POST</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5988">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5989">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5990">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e5993">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e5998">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e5999">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6000">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFileToFolder">PUT</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6003">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6004">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6005">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5803">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>)</a></li> - <li><a href="#d2e5804">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>)</a></li> + <li><a href="#d2e6008">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6009">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6011">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6012">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFolders">PUT</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6015">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6016">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5806">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6019">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6020">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5807">/repo/courses/{courseId}/assessments/{nodeId}/users/{identityKey}</h3> + <h3 id="d2e6021">/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/metadata/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15746,7 +15863,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -15755,7 +15872,7 @@ </tr> <tr> <td> - <p><strong>identityKey</strong></p> + <p><strong>courseKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -15764,19 +15881,19 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>courseNodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>nodeId</strong></p> + <p><strong>path</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> @@ -15784,22 +15901,17 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getCourseNodeResultsForNode">GET</h4> + <h4 id="http://www.example.com#getFileMetadata">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5813">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e5814">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6025">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6026">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5815">/repo/courses/{courseId}/elements/folder</h3> - <p>Description:<br> - - <P> - Initial Date: 6 févr. 2012 <br> - </p> + <h3 id="d2e6027">/users/{identityKey}/folders/course/{courseKey}/{courseNodeId}/version</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15809,177 +15921,120 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>The course resourceable's id</p> + <p><strong>courseKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>courseNodeId</strong></p> </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getFolders">GET</h4> - <p>Retrieves metadata of the course node</p> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5827">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>)</a></li> + <li><a href="#d2e6030">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6031">/users/{identityKey}/folders/personal</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5840"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6034">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6035">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6036">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6037">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6038">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFileToRoot">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5846"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6041">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6042">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#attachFolder">PUT</h4> - <p>This attaches a Folder Element onto a given course. The element will be - inserted underneath the supplied parentNodeId. - </p> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>parentNodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The node's id which will be the parent of this folder</p> - </td> - </tr> - <tr> - <td> - <p><strong>position</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - </td> - <td> - <p>The node's position relative to its sibling nodes (optional)</p> - </td> - </tr> - <tr> - <td> - <p><strong>shortTitle</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td> - <p>The node short title</p> - </td> - </tr> - <tr> - <td> - <p><strong>longTitle</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td> - <p>The node long title</p> - </td> - </tr> - <tr> - <td> - <p><strong>objectives</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td> - <p>The node learning objectives</p> - </td> - </tr> - <tr> - <td> - <p><strong>visibilityExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The rules to view the node (optional)</p> - </td> - </tr> - <tr> - <td> - <p><strong>downloadExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The rules to download files (optional)</p> - </td> - </tr> - <tr> - <td> - <p><strong>uploadExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The rules to upload files (optional)</p> - </td> - </tr> - </table> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5880">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e6045">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5893"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6050">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6051">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFileToRoot">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5899"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6054">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6055">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#attachFolderPost">POST</h4> - <p>This attaches a Folder Element onto a given course. The element will be - inserted underneath the supplied parentNodeId. - </p> + <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e5906">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5934">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e6058">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6059">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5947"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e5953"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6061">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6062">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e5956">/repo/courses/{courseId}/elements/folder/{nodeId}</h3> + <h3 id="d2e6063">/users/{identityKey}/folders/personal/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -15989,80 +16044,100 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The course resourceable's id</p> - </td> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The course resourceable's id</p> - </td> + <td></td> </tr> <tr> <td> - <p><strong>nodeId</strong></p> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> - <td> - <p>The node's id</p> - </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateFolder">POST</h4> - <p>This updates a Folder Element onto a given course.</p> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#listFiles">GET</h4> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5967">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6067">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6068">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6069">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6070">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6071">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFileToFolder">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e5989">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> + <li><a href="#d2e6074">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6075">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6076">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e6079">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6002"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6084">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6085">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6086">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6008"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6089">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6090">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6091">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#getFolder">GET</h4> - <p>Retrieves metadata of the course node</p> + <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e6094">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6095">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6017">application/xml, application/json (<abbr title="{http://www.example.com} folderVO">ns3:folderVO</abbr>)</a></li> + <li><a href="#d2e6097">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6098">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#putFolders">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6030"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6101">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6102">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6036"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6105">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6106">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6039">/repo/courses/{courseId}/elements/folder/{nodeId}/files</h3> + <h3 id="d2e6107">/users/{identityKey}/folders/personal/metadata/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -16072,18 +16147,77 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> + </tr> + <tr> <td> - <p>The course resourceable's id</p> + <p><strong>path</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getFileMetadata">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6111">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6112">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6113">/users/{identityKey}/folders/personal/version</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6116">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6117">/users/{identityKey}/folders/group/{groupKey}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -16092,10 +16226,10 @@ </tr> <tr> <td> - <p><strong>nodeId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -16106,58 +16240,58 @@ <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6044">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6045">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6046">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6047">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6048">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6121">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6122">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6123">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6124">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6125">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#postFileToRoot">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6051">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6052">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6128">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6129">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#postFile64ToRoot">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6055">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6132">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6060">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6061">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6137">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6138">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFileToRoot">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6064">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6065">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6141">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6142">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFile64VOToRoot">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6068">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e6069">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6145">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6146">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6071">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6072">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6148">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6149">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6073">/repo/courses/{courseId}/elements/folder/{nodeId}/files/{path:.*}</h3> + <h3 id="d2e6150">/users/{identityKey}/folders/group/{groupKey}/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -16167,18 +16301,16 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The course resourceable's id</p> - </td> + <td></td> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -16187,16 +16319,7 @@ </tr> <tr> <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>path</strong></p> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -16210,77 +16333,77 @@ <h4 id="http://www.example.com#listFiles">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6077">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6078">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6079">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6080">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6081">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6154">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6155">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6156">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6157">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6158">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#postFileToFolder">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6084">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6085">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6086">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6161">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6162">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6163">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#postFile64ToFolder">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6089">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6166">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6094">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6095">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6096">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6171">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6172">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6173">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFileToFolder">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6099">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6100">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6101">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6176">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6177">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6178">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFile64ToFolder">PUT</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6104">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> - <li><a href="#d2e6105">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6181">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> + <li><a href="#d2e6182">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>)</a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6107">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6108">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6184">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6185">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#putFolders">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6111">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6112">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6188">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6189">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#deleteItem">DELETE</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6115">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6116">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6192">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6193">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6117">/repo/courses/{courseId}/elements/folder/{nodeId}/files/version</h3> + <h3 id="d2e6194">/users/{identityKey}/folders/group/{groupKey}/metadata/{path:.*}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -16290,18 +16413,16 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> - <td> - <p>The course resourceable's id</p> - </td> + <td></td> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>groupKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -16310,7 +16431,7 @@ </tr> <tr> <td> - <p><strong>nodeId</strong></p> + <p><strong>path</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -16321,16 +16442,17 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> + <h4 id="http://www.example.com#getFileMetadata">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6120">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6198">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6199">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6121">/repo/courses/{courseId}/elements/folder/{nodeId}/files/metadata/{path:.*}</h3> + <h3 id="d2e6200">/users/{identityKey}/folders/group/{groupKey}/version</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -16340,18 +16462,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td> - <p>The course resourceable's id</p> - </td> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -16360,19 +16471,10 @@ </tr> <tr> <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>path</strong></p> + <p><strong>groupKey</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -16380,23 +16482,16 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#getFileMetadata">GET</h4> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6125">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6126">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6203">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6127">/repo/courses/{courseId}/elements/contact</h3> - <p>Description:<br> - This handles the contact building block. - - <P> - Initial Date: 10 mai 2010 <br> - </p> + <h3 id="d2e6204">/users/{identityKey}/courses</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -16406,45 +16501,41 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e6206">/users/{identityKey}/courses/my<span class="optional">?start</span><span class="optional">&limit</span></h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> + </td> <td> - <p>The course resourceable's id</p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> + <td></td> </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachContactPost">POST</h4> - <p>This attaches a contact element onto a given course, the element will be - inserted underneath the supplied parentNodeId - </p> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e6137">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6160">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6173"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6179"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachContact">PUT</h4> - <p>This attaches a contact element onto a given course, the element will be - inserted underneath the supplied parentNodeId - </p> + <h4 id="http://www.example.com#getMyCourses">GET</h4> + <p>Retrieves the list of "My entries" but limited to courses.</p> <h6>request query parameters</h6> <table> <tr> @@ -16454,239 +16545,176 @@ </tr> <tr> <td> - <p><strong>parentNodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The node's id which will be the parent of this structure</p> - </td> - </tr> - <tr> - <td> - <p><strong>position</strong></p> + <p><strong>start</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td> - <p>The node's position relative to its sibling nodes (optional)</p> + <p>The first result</p> </td> </tr> <tr> <td> - <p><strong>shortTitle</strong></p> + <p><strong>limit</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td> - <p>The node short title</p> + <p>Max result</p> </td> </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6220">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6233"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6236">/users/{identityKey}/courses/teached<span class="optional">?start</span><span class="optional">&limit</span></h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getTeachedCourses">GET</h4> + <p>Retrieves the list of "My supervised courses" but limited to courses.</p> + <h6>request query parameters</h6> + <table> <tr> - <td> - <p><strong>longTitle</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td> - <p>The node long title</p> - </td> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>objectives</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td> - <p>The node learning objectives</p> + <p>The first result</p> </td> </tr> <tr> <td> - <p><strong>visibilityExpertRules</strong></p> + <p><strong>limit</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td> - <p>The rules to view the node (optional)</p> + <p>Max result</p> </td> </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6250">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6263"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6266">/users/{identityKey}/courses/favorite<span class="optional">?start</span><span class="optional">&limit</span></h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getFavoritCourses">GET</h4> + <p>Retrieves the list of my favorite courses.</p> + <h6>request query parameters</h6> + <table> <tr> - <td> - <p><strong>accessExpertRules</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The rules to access the node (optional)</p> - </td> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>coaches</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>false</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td> - <p>Send to coaches (true/false)</p> + <p>The first result</p> </td> </tr> <tr> <td> - <p><strong>participants</strong></p> + <p><strong>limit</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> - <p>Default: <tt>false</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td> - <p>Send to participants (true/false)</p> - </td> - </tr> - <tr> - <td> - <p><strong>groups</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>A list of learning groups (list of keys)</p> - </td> - </tr> - <tr> - <td> - <p><strong>areas</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>A list of learning areas (list of keys)</p> - </td> - </tr> - <tr> - <td> - <p><strong>to</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The list of e-mail address</p> - </td> - </tr> - <tr> - <td> - <p><strong>defaultSubject</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The default subject</p> - </td> - </tr> - <tr> - <td> - <p><strong>defaultBody</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The default body text</p> + <p>Max result</p> </td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6232">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>)</a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6245"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6251"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6254">/repo/courses/{courseId}/elements</h3> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e6255">/repo/courses/{courseId}/elements/version</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6258">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6280">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>)</a></li> </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6259">/repo/courses/{courseId}/elements/{nodeId}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getCourseNode">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6264">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6265">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6293"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6266">/repo/courses/{courseId}/elements/structure/{nodeId}</h3> + <h3 id="d2e6296">/users/{identityKey}/groups<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&externalId</span><span class="optional">&managed</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -16696,37 +16724,74 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateStructure">POST</h4> + <h4 id="http://www.example.com#getUserGroupList">GET</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>start</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>limit</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>externalId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>managed</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td></td> + </tr> + </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6271">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6272">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6305">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6306">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6273">/repo/courses/{courseId}/elements/structure</h3> + <h3 id="d2e6307">/users/{identityKey}/groups/owner<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&externalId</span><span class="optional">&managed</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -16736,7 +16801,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -16747,15 +16812,7 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachStructurePostMultiparts">POST</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6277">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6278">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachStructure">PUT</h4> + <h4 id="http://www.example.com#getOwnedGroupList">GET</h4> <h6>request query parameters</h6> <table> <tr> @@ -16765,64 +16822,104 @@ </tr> <tr> <td> - <p><strong>parentNodeId</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>position</strong></p> + <p><strong>limit</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>shortTitle</strong></p> + <p><strong>externalId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>longTitle</strong></p> + <p><strong>managed</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> </td> <td></td> </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6315">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6316">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6317">/users/{identityKey}/groups/participant<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&externalId</span><span class="optional">&managed</span></h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>identityKey</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getParticipatingGroupList">GET</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> <tr> <td> - <p><strong>objectives</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>visibilityExpertRules</strong></p> + <p><strong>limit</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>accessExpertRules</strong></p> + <p><strong>externalId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> @@ -16831,25 +16928,24 @@ </tr> <tr> <td> - <p><strong>displayType</strong></p> + <p><strong>managed</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>toc</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6290">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6291">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6325">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6326">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6292">/repo/courses/{courseId}/elements/singlepage/{nodeId}</h3> + <h3 id="d2e6327">/users/{identityKey}/groups/infos<span class="optional">?start</span><span class="optional">&limit</span><span class="optional">&externalId</span><span class="optional">&managed</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -16859,47 +16955,7 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#updateSinglePage">POST</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6297">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6298">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6299">/repo/courses/{courseId}/elements/singlepage</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> + <p><strong>identityKey</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -16910,35 +16966,7 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachSinglePagePost">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e6303">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6314">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6315">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachSinglePagePost">POST</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6318">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6319">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachSinglePage">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6322">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6323">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachSinglePage">PUT</h4> + <h4 id="http://www.example.com#getUserGroupInfosList">GET</h4> <h6>request query parameters</h6> <table> <tr> @@ -16948,99 +16976,178 @@ </tr> <tr> <td> - <p><strong>parentNodeId</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>position</strong></p> + <p><strong>limit</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>shortTitle</strong></p> + <p><strong>externalId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>longTitle</strong></p> + <p><strong>managed</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> </td> <td></td> </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6335">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6336">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6337">/repo/courses/infos<span class="optional">?start</span><span class="optional">&limit</span></h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getCourseInfoList">GET</h4> + <h6>request query parameters</h6> + <table> <tr> - <td> - <p><strong>objectives</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - <p>Default: <tt>undefined</tt></p> - </td> - <td></td> + <th>parameter</th> + <th>value</th> + <th>description</th> </tr> <tr> <td> - <p><strong>visibilityExpertRules</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>accessExpertRules</strong></p> + <p><strong>limit</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td></td> </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6343">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6344">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6345">/repo/courses/infos/{courseId}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getCourseInfo">GET</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6349">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6350">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6351">/contacts<span class="optional">?start</span><span class="optional">&limit</span></h3> + <p>Description:<br> + + <P> + Initial Date: 21 oct. 2011 <br> + </p> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getMyContacts">GET</h4> + <p>Retrieve the contacts of the logged in identity.</p> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> <tr> <td> - <p><strong>filename</strong></p> + <p><strong>start</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>0</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>path</strong></p> + <p><strong>limit</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + <p>Default: <tt>25</tt></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6336">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6337">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6363"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6338">/repo/courses/{courseId}/elements/task/{nodeId}</h3> + <h3 id="d2e6366">/repo/courses/{courseId}/elements</h3> + <h6>Methods</h6> + <div class="methods"></div> + </div> + <div class="resource"> + <h3 id="d2e6367">/repo/courses/{courseId}/elements/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17070,21 +17177,30 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateTask">POST</h4> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#getCourseNode">GET</h4> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6343">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6372">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6373">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6374">/repo/courses/{courseId}/elements/version</h3> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#getVersion">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6352">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6353">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6377">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6354">/repo/courses/{courseId}/elements/task</h3> + <h3 id="d2e6378">/repo/courses/{courseId}/elements/structure/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17101,23 +17217,59 @@ </td> <td></td> </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachTaskPost">POST</h4> - <p><em>acceptable request representations:</em></p> + <h4 id="http://www.example.com#updateStructure">POST</h4> + <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6358">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6383">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6384">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6385">/repo/courses/{courseId}/elements/structure</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#attachStructurePostMultiparts">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6369">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6370">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6389">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6390">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#attachTask">PUT</h4> + <h4 id="http://www.example.com#attachStructure">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -17193,33 +17345,25 @@ </tr> <tr> <td> - <p><strong>text</strong></p> + <p><strong>displayType</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>points</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#float">float</a></em></p> + <p>Default: <tt>toc</tt></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6383">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6384">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6402">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6403">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6385">/repo/courses/{courseId}/elements/test/{nodeId}</h3> + <h3 id="d2e6404">/repo/courses/{courseId}/elements/singlepage/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17249,21 +17393,17 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateTest">POST</h4> - <p><em>acceptable request representations:</em></p> - <ul> - <li><a href="#d2e6390">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> + <h4 id="http://www.example.com#updateSinglePage">POST</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6398">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6399">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6409">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6410">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6400">/repo/courses/{courseId}/elements/test</h3> + <h3 id="d2e6411">/repo/courses/{courseId}/elements/singlepage</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17284,27 +17424,43 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachTestPost">POST</h4> + <h4 id="http://www.example.com#attachSinglePagePost">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6404">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6415">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6414">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6415">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6426">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6427">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#attachTest">PUT</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> + <h4 id="http://www.example.com#attachSinglePagePost">POST</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6430">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6431">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachSinglePage">PUT</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6434">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6435">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachSinglePage">PUT</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> <td> <p><strong>parentNodeId</strong></p> </td> @@ -17372,24 +17528,33 @@ </tr> <tr> <td> - <p><strong>testResourceableId</strong></p> + <p><strong>filename</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>path</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6427">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6428">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6448">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6449">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6429">/repo/courses/{courseId}/elements/assessment/{nodeId}</h3> + <h3 id="d2e6450">/repo/courses/{courseId}/elements/task/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17419,21 +17584,21 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateAssessment">POST</h4> + <h4 id="http://www.example.com#updateTask">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6434">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6455">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6441">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6442">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6464">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6465">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6444">/repo/courses/{courseId}/elements/assessment</h3> + <h3 id="d2e6466">/repo/courses/{courseId}/elements/task</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17454,19 +17619,19 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachAssessmentPost">POST</h4> + <h4 id="http://www.example.com#attachTaskPost">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6448">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6470">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6457">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6458">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6481">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6482">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#attachAssessment">PUT</h4> + <h4 id="http://www.example.com#attachTask">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -17540,17 +17705,35 @@ </td> <td></td> </tr> + <tr> + <td> + <p><strong>text</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>points</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#float">float</a></em></p> + </td> + <td></td> + </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6469">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6470">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6495">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6496">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6471">/repo/courses/{courseId}/elements/wiki/{nodeId}</h3> + <h3 id="d2e6497">/repo/courses/{courseId}/elements/test/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17580,21 +17763,21 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateWiki">POST</h4> + <h4 id="http://www.example.com#updateTest">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6476">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6502">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6484">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6485">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6510">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6511">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6486">/repo/courses/{courseId}/elements/wiki<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&wikiResourceableId</span></h3> + <h3 id="d2e6512">/repo/courses/{courseId}/elements/test</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17615,7 +17798,19 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachWikiPost">POST</h4> + <h4 id="http://www.example.com#attachTestPost">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e6516">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6526">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6527">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachTest">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -17691,7 +17886,7 @@ </tr> <tr> <td> - <p><strong>wikiResourceableId</strong></p> + <p><strong>testResourceableId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -17701,12 +17896,91 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6499">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6500">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6539">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6540">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6541">/repo/courses/{courseId}/elements/assessment/{nodeId}</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachWiki">PUT</h4> + <h4 id="http://www.example.com#updateAssessment">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e6546">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6553">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6554">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6556">/repo/courses/{courseId}/elements/assessment</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#attachAssessmentPost">POST</h4> + <p><em>acceptable request representations:</em></p> + <ul> + <li><a href="#d2e6560">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6569">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6570">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachAssessment">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -17780,26 +18054,17 @@ </td> <td></td> </tr> - <tr> - <td> - <p><strong>wikiResourceableId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6512">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6513">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6581">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6582">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6514">/repo/courses/{courseId}/elements/blog/{nodeId}</h3> + <h3 id="d2e6583">/repo/courses/{courseId}/elements/wiki/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17829,21 +18094,21 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateBlog">POST</h4> + <h4 id="http://www.example.com#updateWiki">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6519">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6588">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6527">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6528">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6596">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6597">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6529">/repo/courses/{courseId}/elements/blog<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&repoEntry</span></h3> + <h3 id="d2e6598">/repo/courses/{courseId}/elements/wiki<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&wikiResourceableId</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -17864,7 +18129,7 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachBlogPost">POST</h4> + <h4 id="http://www.example.com#attachWikiPost">POST</h4> <h6>request query parameters</h6> <table> <tr> @@ -17940,7 +18205,7 @@ </tr> <tr> <td> - <p><strong>repoEntry</strong></p> + <p><strong>wikiResourceableId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -17950,12 +18215,12 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6542">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6543">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6611">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6612">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#attachBlog">PUT</h4> + <h4 id="http://www.example.com#attachWiki">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -18031,7 +18296,7 @@ </tr> <tr> <td> - <p><strong>repoEntry</strong></p> + <p><strong>wikiResourceableId</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -18041,14 +18306,14 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6555">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6556">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6624">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6625">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6557">/repo/courses/{courseId}/elements/survey/{nodeId}</h3> + <h3 id="d2e6626">/repo/courses/{courseId}/elements/blog/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -18078,21 +18343,21 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachSurveyPost">POST</h4> + <h4 id="http://www.example.com#updateBlog">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6562">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6631">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6570">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6571">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6639">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6640">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6572">/repo/courses/{courseId}/elements/survey<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&surveyResourceableId</span></h3> + <h3 id="d2e6641">/repo/courses/{courseId}/elements/blog<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&repoEntry</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -18113,7 +18378,7 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachSurveyPost">POST</h4> + <h4 id="http://www.example.com#attachBlogPost">POST</h4> <h6>request query parameters</h6> <table> <tr> @@ -18189,7 +18454,7 @@ </tr> <tr> <td> - <p><strong>surveyResourceableId</strong></p> + <p><strong>repoEntry</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -18199,12 +18464,12 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6585">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6586">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6654">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6655">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#attachSurvey">PUT</h4> + <h4 id="http://www.example.com#attachBlog">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -18280,7 +18545,7 @@ </tr> <tr> <td> - <p><strong>surveyResourceableId</strong></p> + <p><strong>repoEntry</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> @@ -18290,14 +18555,14 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6598">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6599">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6667">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6668">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6600">/repo/courses/{courseId}/elements/externalpage/{nodeId}</h3> + <h3 id="d2e6669">/repo/courses/{courseId}/elements/survey/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -18307,19 +18572,19 @@ </tr> <tr> <td> - <p><strong>parentNodeId</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>nodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> @@ -18327,21 +18592,21 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#updateExternalPage">POST</h4> + <h4 id="http://www.example.com#attachSurveyPost">POST</h4> <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6605">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6674">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6613">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6614">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6682">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6683">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6615">/repo/courses/{courseId}/elements/externalpage<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&url</span></h3> + <h3 id="d2e6684">/repo/courses/{courseId}/elements/survey<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&surveyResourceableId</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -18362,7 +18627,7 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachExternalPagePost">POST</h4> + <h4 id="http://www.example.com#attachSurveyPost">POST</h4> <h6>request query parameters</h6> <table> <tr> @@ -18438,22 +18703,22 @@ </tr> <tr> <td> - <p><strong>url</strong></p> + <p><strong>surveyResourceableId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6628">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6629">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6697">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6698">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> - <h4 id="http://www.example.com#attachExternalPage">PUT</h4> + <h4 id="http://www.example.com#attachSurvey">PUT</h4> <h6>request query parameters</h6> <table> <tr> @@ -18529,24 +18794,24 @@ </tr> <tr> <td> - <p><strong>url</strong></p> + <p><strong>surveyResourceableId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6641">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6642">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6710">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6711">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6643">/repo/courses/{courseId}/elements/task/{nodeId}/file</h3> + <h3 id="d2e6712">/repo/courses/{courseId}/elements/externalpage/{nodeId}</h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -18556,19 +18821,19 @@ </tr> <tr> <td> - <p><strong>courseId</strong></p> + <p><strong>parentNodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>nodeId</strong></p> + <p><strong>courseId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> </td> <td></td> </tr> @@ -18576,25 +18841,21 @@ <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#attachTaskFilePost">POST</h4> - <p><em>available response representations:</em></p> + <h4 id="http://www.example.com#updateExternalPage">POST</h4> + <p><em>acceptable request representations:</em></p> <ul> - <li><a href="#d2e6648">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6649">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6717">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachTaskFile">PUT</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6652">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6653">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6725">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6726">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6654">/repo/courses/{courseId}/elements/task/{nodeId}/configuration<span class="optional">?enableAssignment</span><span class="optional">&taskAssignmentType</span><span class="optional">&taskAssignmentText</span><span class="optional">&enableTaskPreview</span><span class="optional">&enableTaskDeselect</span><span class="optional">&onlyOneUserPerTask</span><span class="optional">&enableDropbox</span><span class="optional">&enableDropboxConfirmationMail</span><span class="optional">&dropboxConfirmationText</span><span class="optional">&enableReturnbox</span><span class="optional">&enableScoring</span><span class="optional">&grantScoring</span><span class="optional">&scoreMin</span><span class="optional">&scoreMax</span><span class="optional">&grantPassing</span><span class="optional">&scorePassingThreshold</span><span class="optional">&enableCommentField</span><span class="optional">&commentForUser</span><span class="optional">&commentForCoaches</span><span class="optional">&enableSolution</span><span class="optional">&accessExpertRuleTask</span><span class="optional">&accessExpertRuleDropbox</span><span class="optional">&accessExpertRuleReturnbox</span><span class="optional">&accessExpertRuleScoring</span><span class="optional">&accessExpertRuleSolution</span></h3> + <h3 id="d2e6727">/repo/courses/{courseId}/elements/externalpage<span class="optional">?parentNodeId</span><span class="optional">&position</span><span class="optional">&shortTitle</span><span class="optional">&longTitle</span><span class="optional">&objectives</span><span class="optional">&visibilityExpertRules</span><span class="optional">&accessExpertRules</span><span class="optional">&url</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -18611,20 +18872,11 @@ </td> <td></td> </tr> - <tr> - <td> - <p><strong>nodeId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> </table> <h6>Methods</h6> <div class="methods"> <div class="method"> - <h4 id="http://www.example.com#addTaskConfigurationPost">POST</h4> + <h4 id="http://www.example.com#attachExternalPagePost">POST</h4> <h6>request query parameters</h6> <table> <tr> @@ -18634,73 +18886,335 @@ </tr> <tr> <td> - <p><strong>enableAssignment</strong></p> + <p><strong>parentNodeId</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>taskAssignmentType</strong></p> + <p><strong>position</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>taskAssignmentText</strong></p> + <p><strong>shortTitle</strong></p> </td> <td> <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>enableTaskPreview</strong></p> + <p><strong>longTitle</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>enableTaskDeselect</strong></p> + <p><strong>objectives</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> </td> <td></td> </tr> <tr> <td> - <p><strong>onlyOneUserPerTask</strong></p> + <p><strong>visibilityExpertRules</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>enableDropbox</strong></p> + <p><strong>accessExpertRules</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> </td> <td></td> </tr> <tr> <td> - <p><strong>enableDropboxConfirmationMail</strong></p> + <p><strong>url</strong></p> </td> <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6740">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6741">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachExternalPage">PUT</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>parentNodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>position</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>shortTitle</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>longTitle</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>objectives</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + <p>Default: <tt>undefined</tt></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>visibilityExpertRules</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>accessExpertRules</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>url</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6753">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6754">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6755">/repo/courses/{courseId}/elements/task/{nodeId}/file</h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#attachTaskFilePost">POST</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6760">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6761">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + <div class="method"> + <h4 id="http://www.example.com#attachTaskFile">PUT</h4> + <p><em>available response representations:</em></p> + <ul> + <li><a href="#d2e6764">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6765">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + </ul> + </div> + </div> + </div> + <div class="resource"> + <h3 id="d2e6766">/repo/courses/{courseId}/elements/task/{nodeId}/configuration<span class="optional">?enableAssignment</span><span class="optional">&taskAssignmentType</span><span class="optional">&taskAssignmentText</span><span class="optional">&enableTaskPreview</span><span class="optional">&enableTaskDeselect</span><span class="optional">&onlyOneUserPerTask</span><span class="optional">&enableDropbox</span><span class="optional">&enableDropboxConfirmationMail</span><span class="optional">&dropboxConfirmationText</span><span class="optional">&enableReturnbox</span><span class="optional">&enableScoring</span><span class="optional">&grantScoring</span><span class="optional">&scoreMin</span><span class="optional">&scoreMax</span><span class="optional">&grantPassing</span><span class="optional">&scorePassingThreshold</span><span class="optional">&enableCommentField</span><span class="optional">&commentForUser</span><span class="optional">&commentForCoaches</span><span class="optional">&enableSolution</span><span class="optional">&accessExpertRuleTask</span><span class="optional">&accessExpertRuleDropbox</span><span class="optional">&accessExpertRuleReturnbox</span><span class="optional">&accessExpertRuleScoring</span><span class="optional">&accessExpertRuleSolution</span></h3> + <h6>resource-wide template parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>courseId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>nodeId</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + </table> + <h6>Methods</h6> + <div class="methods"> + <div class="method"> + <h4 id="http://www.example.com#addTaskConfigurationPost">POST</h4> + <h6>request query parameters</h6> + <table> + <tr> + <th>parameter</th> + <th>value</th> + <th>description</th> + </tr> + <tr> + <td> + <p><strong>enableAssignment</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>taskAssignmentType</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>taskAssignmentText</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>enableTaskPreview</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>enableTaskDeselect</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>onlyOneUserPerTask</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>enableDropbox</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> + </td> + <td></td> + </tr> + <tr> + <td> + <p><strong>enableDropboxConfirmationMail</strong></p> + </td> + <td> + <p><em><a href="http://www.w3.org/TR/xmlschema-2/#boolean">boolean</a></em></p> </td> <td></td> </tr> @@ -18860,8 +19374,8 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6687">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6688">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6799">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6800">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -19101,22 +19615,22 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6719">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6720">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6831">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6832">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#getTaskConfiguration">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6723">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6724">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6835">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6836">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6726">/repo/courses/{courseId}/elements/survey/{nodeId}/configuration<span class="optional">?allowCancel</span><span class="optional">&allowNavigation</span><span class="optional">&allowSuspend</span><span class="optional">&sequencePresentation</span><span class="optional">&showNavigation</span><span class="optional">&showQuestionTitle</span><span class="optional">&showSectionsOnly</span></h3> + <h3 id="d2e6838">/repo/courses/{courseId}/elements/survey/{nodeId}/configuration<span class="optional">?allowCancel</span><span class="optional">&allowNavigation</span><span class="optional">&allowSuspend</span><span class="optional">&sequencePresentation</span><span class="optional">&showNavigation</span><span class="optional">&showQuestionTitle</span><span class="optional">&showSectionsOnly</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -19227,8 +19741,8 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6739">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6740">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6851">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6852">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -19313,22 +19827,22 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6751">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6752">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6863">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6864">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#getSurveyConfiguration">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6755">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6756">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6867">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6868">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <div class="resource"> - <h3 id="d2e6757">/repo/courses/{courseId}/elements/test/{nodeId}/configuration<span class="optional">?allowCancel</span><span class="optional">&allowNavigation</span><span class="optional">&allowSuspend</span><span class="optional">&numAttempts</span><span class="optional">&sequencePresentation</span><span class="optional">&showNavigation</span><span class="optional">&showQuestionTitle</span><span class="optional">&showResultsAfterFinish</span><span class="optional">&showResultsDependendOnDate</span><span class="optional">&showResultsOnHomepage</span><span class="optional">&showScoreInfo</span><span class="optional">&showQuestionProgress</span><span class="optional">&showScoreProgress</span><span class="optional">&showSectionsOnly</span><span class="optional">&summaryPresentation</span><span class="optional">&startDate</span><span class="optional">&endDate</span></h3> + <h3 id="d2e6869">/repo/courses/{courseId}/elements/test/{nodeId}/configuration<span class="optional">?allowCancel</span><span class="optional">&allowNavigation</span><span class="optional">&allowSuspend</span><span class="optional">&numAttempts</span><span class="optional">&sequencePresentation</span><span class="optional">&showNavigation</span><span class="optional">&showQuestionTitle</span><span class="optional">&showResultsAfterFinish</span><span class="optional">&showResultsDependendOnDate</span><span class="optional">&showResultsOnHomepage</span><span class="optional">&showScoreInfo</span><span class="optional">&showQuestionProgress</span><span class="optional">&showScoreProgress</span><span class="optional">&showSectionsOnly</span><span class="optional">&summaryPresentation</span><span class="optional">&startDate</span><span class="optional">&endDate</span></h3> <h6>resource-wide template parameters</h6> <table> <tr> @@ -19537,8 +20051,8 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6781">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6782">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6893">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6894">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> @@ -19721,643 +20235,1069 @@ </table> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6804">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6805">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6916">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6917">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> <div class="method"> <h4 id="http://www.example.com#getTestConfiguration">GET</h4> <p><em>available response representations:</em></p> <ul> - <li><a href="#d2e6808">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6809">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6810">/ping</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#ping">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6813">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6814">/ping/version</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6817">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6818">/ping/{name}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>name</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#ping">POST</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6822">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6823">/repo/courses/infos<span class="optional">?start</span><span class="optional">&limit</span></h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getCourseInfoList">GET</h4> - <h6>request query parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>start</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>0</tt></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>limit</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#int">int</a></em></p> - <p>Default: <tt>25</tt></p> - </td> - <td></td> - </tr> - </table> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6829">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6830">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6831">/repo/courses/infos/{courseId}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getCourseInfo">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6835">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6836">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6837">/openmeetings</h3> - <p>Initial date: 13.11.2012<br></p> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e6840">/openmeetings/{identityToken}/portrait</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>identityToken</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td> - <p>The identity key of the user being searched</p> - </td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getPortrait">GET</h4> - <p>Retrieves the portrait of an user</p> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6850">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6856"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6859">/repo/courses/{courseId}/resourcefolders</h3> - <h6>Methods</h6> - <div class="methods"></div> - </div> - <div class="resource"> - <h3 id="d2e6860">/repo/courses/{courseId}/resourcefolders/version</h3> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getVersion">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6863">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6864">/repo/courses/{courseId}/resourcefolders/sharedfolder/{path:.*}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getSharedFiles">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6869">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6870">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6871">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6872">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6873">/repo/courses/{courseId}/resourcefolders/sharedfolder</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getSharedFiles">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6877">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6878">/repo/courses/{courseId}/resourcefolders/coursefolder/{path:.*}</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>path</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#string">string</a></em></p> - </td> - <td></td> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getCourseFiles">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6883">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6884">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6885">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - <li><a href="#d2e6886">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachFileToFolderPost">POST</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6889">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachFileToFolder">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6892">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - </div> - </div> - <div class="resource"> - <h3 id="d2e6893">/repo/courses/{courseId}/resourcefolders/coursefolder</h3> - <h6>resource-wide template parameters</h6> - <table> - <tr> - <th>parameter</th> - <th>value</th> - <th>description</th> - </tr> - <tr> - <td> - <p><strong>courseId</strong></p> - </td> - <td> - <p><em><a href="http://www.w3.org/TR/xmlschema-2/#long">long</a></em></p> - </td> - <td></td> - </tr> - </table> - <h6>Methods</h6> - <div class="methods"> - <div class="method"> - <h4 id="http://www.example.com#getCourseFiles">GET</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6897">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachFileToFolderPost">POST</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6900">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> - </ul> - </div> - <div class="method"> - <h4 id="http://www.example.com#attachFileToFolder">PUT</h4> - <p><em>available response representations:</em></p> - <ul> - <li><a href="#d2e6903">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6920">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> + <li><a href="#d2e6921">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></a></li> </ul> </div> </div> </div> <h2 id="representations">Representations</h2> - <h3 id="d2e10">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e39">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<courseNodeVO> + <id>id</id> +</courseNodeVO> +</code></pre></p> + <p>The folder node metadatas</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e52"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e58"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or parentNode not found</p> + <h3 id="d2e67">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<folders totalCount="1"> + <folders> + <folder name="Course folder" courseKey="375397" courseNodeId="438950850389" subscribed="true" write="false" read="false" list="false" delete="false"/> + </folders> +</folders> +</code></pre></p> + <p>The course node metadatas</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e80"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e86"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or parentNode not found</p> + <h3 id="d2e93">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e121">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<courseNodeVO> + <id>id</id> +</courseNodeVO> +</code></pre></p> + <p>The folder node metadatas</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e134"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e140"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or parentNode not found</p> + <h3 id="d2e154">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e176">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<courseNodeVO> + <id>id</id> +</courseNodeVO> +</code></pre></p> + <p>The folder node metadatas</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e189"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e195"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or parentNode not found</p> + <h3 id="d2e204">application/xml, application/json (<abbr title="{http://www.example.com} folderVO">ns3:folderVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<folder name="Course folder" courseKey="375397" courseNodeId="438950850389" subscribed="true" write="false" read="false" list="false" delete="false"/> +</code></pre></p> + <p>The course node metadatas</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e217"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e223"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or parentNode not found</p> + <h3 id="d2e231">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e232">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e233">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e234">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e235">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e238">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e239">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e242">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e247">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e248">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e251">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e252">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e255">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e256">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e258">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e259">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e264">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e265">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e266">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e267">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e268">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e271">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e272">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e273">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e276">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e281">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e282">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e283">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e286">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e287">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e288">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e291">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e292">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e294">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e295">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e298">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e299">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e302">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e303">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e308">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e309">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e313">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e318">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e319">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e328">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e329">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e342">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e343">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e346">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e347">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e349">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e350">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e353">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e354">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e356">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e357">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e362">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e363">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e367">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e368">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e370">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e371">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e374">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e375">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e376">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e378">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e379">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e390">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e391">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e412">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e413">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e416">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e417">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e419">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e420">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e423">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e424">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e428">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e433">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e434">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e437">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e438">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e443">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e444">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e447">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e455">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e456">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e461">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e465">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e466">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e470">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e473">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e478">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e482">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e487">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e488">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e491">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e494">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e495">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e499">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e500">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e502">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e505">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e506">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e511">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e512">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e514">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e517">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e518">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e522">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e523">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e526">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e527">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e529">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e534">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e538">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e542">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e543">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e551">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e552">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e556">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e557">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e560">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e561">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e563">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e564">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e569">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e572">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e575">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e577">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e581">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e586">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e587">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e588">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e589">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e590">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e593">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e594">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e597">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e602">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e603">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e606">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e607">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e610">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e611">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e613">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e614">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e619">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e620">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e621">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e622">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e623">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e626">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e627">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e628">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e631">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e636">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e637">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e638">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e641">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e642">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e643">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e646">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e647">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e649">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e650">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e653">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e654">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e657">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e658">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e663">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e664">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e668">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e679">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<forum name="My forum" detailsName="It is a forum" forumKey="3865487" courseKey="286" courseNodeId="2784628" subscribed="false"/> +</code></pre></p> + <p>The root message of the thread</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e692"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e698"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The forum not found</p> + <h3 id="d2e717">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messages totalCount="1"> + <messages> + <message> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> + </message> + </messages> +</messages> +</code></pre></p> + <p>The root message of the thread</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e730"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e736"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author, forum or message not found</p> + <h3 id="d2e755">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> +</code></pre></p> + <p>The root message of the thread</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e768"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e774"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author, forum or message not found</p> + <h3 id="d2e781">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e788">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> +</code></pre></p> + <p>The root message of the thread</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e801"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e807"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author, forum or message not found</p> + <h3 id="d2e829">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messages totalCount="1"> + <messages> + <message> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> + </message> + </messages> +</messages> +</code></pre></p> + <p>The root message of the thread</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e842"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e848"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author, forum or message not found</p> + <h3 id="d2e859">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e872">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> +</code></pre></p> + <p>The root message of the thread</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e885"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e891"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author or message not found</p> + <h3 id="d2e898">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e899">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e903">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + </h3> <p> - <h6>Example</h6><pre><code>1.0</code></pre></p> - <p>The version of this specific Web Service</p> - <h3 id="d2e32">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> +</code></pre></p> + <p>The root message of the thread</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e916"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e922"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author or message not found</p> + <h3 id="d2e941">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> +</code></pre></p> + <p>The root message of the thread</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e954"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e960"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author or message not found</p> + <h3 id="d2e973">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The links to the attachments</p> + <h3 id="d2e979"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The message not found</p> + <h3 id="d2e986">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e992">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e998"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e1005">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1006">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1010">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e1016"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e1025">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e1031"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e1047">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The portrait as image</p> + <h3 id="d2e1053"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e1066">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1067">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1070">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1071">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1073">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1074">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1077">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1078">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1080">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1081">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1086">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1087">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1091">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1092">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1094">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1095">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1098">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1099">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1100">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1102">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1103">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1114">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<viteroBookingVO> + <bookingId>23</bookingId> + <groupId>24</groupId> + <groupName>NEW-EVENT_OLAT_938745983</groupName> + <eventName>New event</eventName> + <externalId>AC-234</externalId> + <start>2017-07-20T10:13:15.641+02:00</start> + <startBuffer>15</startBuffer> + <end>2017-07-20T10:13:15.641+02:00</end> + <endBuffer>15</endBuffer> + <roomSize>22</roomSize> + <autoSignIn>true</autoSignIn> + <timeZoneId></timeZoneId> +</viteroBookingVO> +</code></pre></p> + <p>This is the list of all bookings of a resource</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1128">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1129">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1133">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<viteroBookingVO> + <bookingId>23</bookingId> + <groupId>24</groupId> + <groupName>NEW-EVENT_OLAT_938745983</groupName> + <eventName>New event</eventName> + <externalId>AC-234</externalId> + <start>2017-07-20T10:13:15.641+02:00</start> + <startBuffer>15</startBuffer> + <end>2017-07-20T10:13:15.641+02:00</end> + <endBuffer>15</endBuffer> + <roomSize>22</roomSize> + <autoSignIn>true</autoSignIn> + <timeZoneId></timeZoneId> +</viteroBookingVO> +</code></pre></p> + <p>The created booking</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1147">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1148">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1152">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<viteroBookingVO> + <bookingId>23</bookingId> + <groupId>24</groupId> + <groupName>NEW-EVENT_OLAT_938745983</groupName> + <eventName>New event</eventName> + <externalId>AC-234</externalId> + <start>2017-07-20T10:13:15.641+02:00</start> + <startBuffer>15</startBuffer> + <end>2017-07-20T10:13:15.641+02:00</end> + <endBuffer>15</endBuffer> + <roomSize>22</roomSize> + <autoSignIn>true</autoSignIn> + <timeZoneId></timeZoneId> +</viteroBookingVO> +</code></pre></p> + <p>The created booking</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1172">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<viteroGroupMemberVO> + <identityKey>23497</identityKey> + <groupRole>participant</groupRole> +</viteroGroupMemberVO> +</code></pre></p> + <p>This is the list of all bookings of a resource</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1186">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1187">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1191">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<viteroGroupMemberVO> + <identityKey>23497</identityKey> + <groupRole>participant</groupRole> +</viteroGroupMemberVO> +</code></pre></p> + <p>This is the list of all bookings of a resource</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1209"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The booking is deleted</p> + <h3 id="d2e1223">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<trainingVO> + <key>4534759</key> + <name>Training</name> + <externalId>AC-234</externalId> + <start>2017-07-20T10:13:15.633+02:00</start> + <end>2017-07-20T10:13:15.633+02:00</end> +</trainingVO> +</code></pre></p> + <p>This is the list of all training of a resource</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1237">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1238">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1242">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<trainingVO> + <key>4534759</key> + <name>Training</name> + <externalId>AC-234</externalId> + <start>2017-07-20T10:13:15.633+02:00</start> + <end>2017-07-20T10:13:15.633+02:00</end> +</trainingVO> +</code></pre></p> + <p>Created a training</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1256">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1257">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1261">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>) + </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<trainingVO> + <key>4534759</key> + <name>Training</name> + <externalId>AC-234</externalId> + <start>2017-07-20T10:13:15.633+02:00</start> + <end>2017-07-20T10:13:15.633+02:00</end> +</trainingVO> +</code></pre></p> + <p>The created booking</p> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1279"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The training is deleted</p> + <h3 id="d2e1285">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1286">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1289">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1290">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1292">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1293">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1296">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1297">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1298">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1300">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1301">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1305">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1306">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1309">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1310">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<forum name="My forum" detailsName="It is a forum" forumKey="3865487" courseKey="286" courseNodeId="2784628" subscribed="false"/> -</code></pre></p> - <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e45"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e51"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The forum not found</p> - <h3 id="d2e70">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e1311">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messages totalCount="1"> - <messages> - <message> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> - </message> - </messages> -</messages> -</code></pre></p> - <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e83"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e89"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author, forum or message not found</p> - <h3 id="d2e108">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1313">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1314">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1318">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1322">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1327">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1330">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1331">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1336">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1339">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1343">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1344">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1348">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1351">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1355">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1363">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1364">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1380">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> +<viteroBookingVO> + <bookingId>23</bookingId> + <groupId>24</groupId> + <groupName>NEW-EVENT_OLAT_938745983</groupName> + <eventName>New event</eventName> + <externalId>AC-234</externalId> + <start>2017-07-20T10:13:15.641+02:00</start> + <startBuffer>15</startBuffer> + <end>2017-07-20T10:13:15.641+02:00</end> + <endBuffer>15</endBuffer> + <roomSize>22</roomSize> + <autoSignIn>true</autoSignIn> + <timeZoneId></timeZoneId> +</viteroBookingVO> </code></pre></p> - <p>The root message of the thread</p> + <p>This is the list of all bookings of a resource</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e121"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e127"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author, forum or message not found</p> - <h3 id="d2e134">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e141">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1394">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> -</code></pre></p> - <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e154"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e160"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author, forum or message not found</p> - <h3 id="d2e182">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e1395">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messages totalCount="1"> - <messages> - <message> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> - </message> - </messages> -</messages> -</code></pre></p> - <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e195"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e201"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author, forum or message not found</p> - <h3 id="d2e212">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e225">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1399">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> +<viteroBookingVO> + <bookingId>23</bookingId> + <groupId>24</groupId> + <groupName>NEW-EVENT_OLAT_938745983</groupName> + <eventName>New event</eventName> + <externalId>AC-234</externalId> + <start>2017-07-20T10:13:15.641+02:00</start> + <startBuffer>15</startBuffer> + <end>2017-07-20T10:13:15.641+02:00</end> + <endBuffer>15</endBuffer> + <roomSize>22</roomSize> + <autoSignIn>true</autoSignIn> + <timeZoneId></timeZoneId> +</viteroBookingVO> </code></pre></p> - <p>The root message of the thread</p> + <p>The created booking</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e238"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e244"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author or message not found</p> - <h3 id="d2e251">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e1413">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e252">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e1414">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e256">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1418">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> +<viteroBookingVO> + <bookingId>23</bookingId> + <groupId>24</groupId> + <groupName>NEW-EVENT_OLAT_938745983</groupName> + <eventName>New event</eventName> + <externalId>AC-234</externalId> + <start>2017-07-20T10:13:15.641+02:00</start> + <startBuffer>15</startBuffer> + <end>2017-07-20T10:13:15.641+02:00</end> + <endBuffer>15</endBuffer> + <roomSize>22</roomSize> + <autoSignIn>true</autoSignIn> + <timeZoneId></timeZoneId> +</viteroBookingVO> </code></pre></p> - <p>The root message of the thread</p> + <p>The created booking</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e269"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e275"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author or message not found</p> - <h3 id="d2e294">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1438">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> +<viteroGroupMemberVO> + <identityKey>23497</identityKey> + <groupRole>participant</groupRole> +</viteroGroupMemberVO> </code></pre></p> - <p>The root message of the thread</p> + <p>This is the list of all bookings of a resource</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e307"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e313"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author or message not found</p> - <h3 id="d2e326">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The links to the attachments</p> - <h3 id="d2e332"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The message not found</p> - <h3 id="d2e339">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e345">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e351"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e358">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e1452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1453">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1457">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>) </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<viteroGroupMemberVO> + <identityKey>23497</identityKey> + <groupRole>participant</groupRole> +</viteroGroupMemberVO> +</code></pre></p> + <p>This is the list of all bookings of a resource</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e359">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e1475"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The booking is deleted</p> + <h3 id="d2e1484">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1485">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1488">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e363">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e369"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e378">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e384"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e400">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The portrait as image</p> - <h3 id="d2e406"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e413">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e421">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e422">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e426">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + <h3 id="d2e1489">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e427">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + <h3 id="d2e1491">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1492">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1497">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1498">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1501">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e429">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e430">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e436">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e437">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e441">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e446">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + <h3 id="d2e1502">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e447">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + <h3 id="d2e1504">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1505">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1508">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1513">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1516">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e1519">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1522">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1527">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e449">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e450">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e453">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e454">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e457">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e462">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e465">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1529">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1534">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1535">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1540">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1541">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1546">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1547">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1553">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1556">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1562">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1565">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1569">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1579">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1580">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1585">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1586">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1587">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1588">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1589">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1592">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1593">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1596">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e468">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e471">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e476">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + <h3 id="d2e1601">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1602">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1605">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1606">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1609">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e478">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e483">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e484">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e489">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e490">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e495">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e496">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e502">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e505">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e511">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e514">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e526">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + <h3 id="d2e1610">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1612">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1613">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1618">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1619">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1620">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1621">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1622">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1625">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1626">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1627">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1630">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e1635">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1636">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1637">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1640">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1641">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1642">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1645">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1646">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e1648">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1649">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1652">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1653">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1656">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1657">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1662">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1663">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1667">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1678">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -20367,11 +21307,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e539"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1691"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e545"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1697"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The forum not found</p> - <h3 id="d2e564">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e1716">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -20390,11 +21330,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e577"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1729"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e583"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1735"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e602">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1754">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -20409,13 +21349,13 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e615"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1767"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e621"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1773"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e628">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1780">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e635">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1787">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -20430,11 +21370,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e648"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1800"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e654"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1806"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e676">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e1828">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -20453,13 +21393,13 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e689"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1841"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e695"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1847"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e706">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1858">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e719">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1871">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -20474,21 +21414,21 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e732"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1884"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e738"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1890"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author or message not found</p> - <h3 id="d2e745">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e1897">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e746">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e1898">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e750">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1902">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -20503,11 +21443,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e763"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1915"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e769"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1921"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author or message not found</p> - <h3 id="d2e788">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e1940">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -20522,460 +21462,180 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e801"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1953"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e807"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1959"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author or message not found</p> - <h3 id="d2e820">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1972">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The links to the attachments</p> - <h3 id="d2e826"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1978"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The message not found</p> - <h3 id="d2e833">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1985">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e839">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e845"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e852">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e853">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e857">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e863"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e872">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1991">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>Ok</p> - <h3 id="d2e878"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e894">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The portrait as image</p> - <h3 id="d2e900"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e1997"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e907">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e908">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e909">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e910">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e911">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e914">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e915">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e918">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e923">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e924">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e927">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e928">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e931">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e932">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e934">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e935">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e940">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e941">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e942">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e943">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e944">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e947">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e948">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e949">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e952">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e957">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e958">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e959">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e962">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e963">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e964">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e967">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e968">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e970">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e971">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e974">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e975">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e978">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e979">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e983">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e988">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e989">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e998">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e999">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1004">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1012">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1017">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1018">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1022">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1023">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1028">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1029">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1032">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e1035">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1038">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1043">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1044">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1048">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1049">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1053">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1054">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1058">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1059">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1063">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1064">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1068">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1069">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1073">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1074">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1078">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1079">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1083">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1084">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1088">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1089">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1093">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1094">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1098">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1099">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1103">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1104">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1108">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1109">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1112">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e1115">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1118">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1122">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1125">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1126">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1130">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1133">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1134">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1142">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1143">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1147">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1150">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1151">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1155">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1156">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1160">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1161">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1165">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1166">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1169">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e1172">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1175">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1179">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1180">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1184">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1189">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1190">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1203"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The list of contacts</p> - <h3 id="d2e1209">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1210">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1216">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1219">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1222">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1226">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1234">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1235">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1240">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1241">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1244">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1245">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1247">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1248">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1256">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1257">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1260">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e1265">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1266">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1270">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1271">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1273">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1274">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1281">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1282">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1285">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1286">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1291">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1292">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1303">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1304">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1307">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1308">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1311">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1312">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1321">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1322">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1326">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1331">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1332">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1335">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1336">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1338">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1339">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1342">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1343">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1346">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1347">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1352">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1353">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1356">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1357">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1359">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1365">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1368">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1373">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1374">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1377">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1378">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1380">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1386">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1389">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1394">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1395">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1397">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1400">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1401">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1407">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1410">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1416">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1417">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1422">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e1425">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1426">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1431">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1432">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1435">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1436">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1438">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1439">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1442">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1443">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1444">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1446">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1447">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1451">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1455">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1456">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>) + <h3 id="d2e2004">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1457">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>) + <h3 id="d2e2005">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1459">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1460">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1465">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1468">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1473">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1476">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1480">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1484">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1487">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1491">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1496">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1497">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1506">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1507">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1517">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1518">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1522">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + <h3 id="d2e2009">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e2015"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e2024">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e2030"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e2046">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The portrait as image</p> + <h3 id="d2e2052"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e2072">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>) </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<keyValuePair> + <key>Prefered color</key> + <value>Green</value> +</keyValuePair> +</code></pre></p> + <p>The value in the course</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1523">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + <h3 id="d2e2083"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The entry cannot be found</p> + <h3 id="d2e2090">text/plain, text/html (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>) </h3> + <p> + <h6>Example</h6><pre><code>Green</code></pre></p> + <p>A value of the course</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1525">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1526">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1529">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1530">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + <h3 id="d2e2101"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The entry cannot be found</p> + <h3 id="d2e2108">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e2113"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The value is saved in the course</p> + <h3 id="d2e2120"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>the key value pair is remove from the db</p> + <h3 id="d2e2124"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e2128"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The entry cannot be found</p> + <h3 id="d2e2139"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The value is saved in the course</p> + <h3 id="d2e2153">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>) </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<keyValuePairVOes> + <keyValuePairVO> + <key>Prefered color</key> + <value>Green</value> + </keyValuePairVO> +</keyValuePairVOes> +</code></pre></p> + <p>All the values in the course</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1531">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) + <h3 id="d2e2167">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1533">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1534">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1538">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1539">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1541">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1542">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1549">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1550">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1553">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1554">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1556">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1557">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e1598">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) + <h3 id="d2e2168">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<courseNodeVO> - <id>id</id> -</courseNodeVO> -</code></pre></p> - <p>The course node metadatas</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1611"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1617"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or parentNode not found</p> - <h3 id="d2e1624">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e1655">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) + <h3 id="d2e2170"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>the key value pair is saved on the db</p> + <h3 id="d2e2177">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<courseNodeVO> - <id>id</id> -</courseNodeVO> -</code></pre></p> - <p>The course node metadatas</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1668"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1674"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or parentNode not found</p> - <h3 id="d2e1686">application/xml, application/json (<abbr title="{http://www.example.com} groupVO">ns3:groupVO</abbr>) + <h3 id="d2e2178">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<groupVO> - <key>123467</key> - <description>My group description</description> - <externalId>External Identifier</externalId> - <managedFlags>title,description</managedFlags> - <name>My group</name> - <minParticipants>0</minParticipants> - <maxParticipants>0</maxParticipants> -</groupVO> -</code></pre></p> - <p>The groups</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1699"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>the key value pair is saved on the db</p> + <h3 id="d2e2197"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>the key value pair is remove from the db</p> + <h3 id="d2e2201"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1705"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or course node not found</p> - <h3 id="d2e1729">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) + <h3 id="d2e2205"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The entry cannot be found</p> + <h3 id="d2e2213">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p> + <h6>Example</h6><pre><code>1.0</code></pre></p> + <p>The version of this specific Web Service</p> + <h3 id="d2e2227">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2233">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2234">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2235">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2236">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2241">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2247">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2248">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2249">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2250">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2253">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2256">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2261">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2264">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2267">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2278">application/xml, application/json (<abbr title="{http://www.example.com} forumVOes">ns3:forumVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<courseNodeVO> - <id>id</id> -</courseNodeVO> +<forums totalCount="1"> + <forums> + <forums name="My forum" detailsName="It is a forum" forumKey="3865487" courseKey="286" courseNodeId="2784628" subscribed="false"/> + </forums> +</forums> </code></pre></p> <p>The course node metadatas</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1742"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2291"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1748"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2297"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The course or parentNode not found</p> - <h3 id="d2e1757">application/xml, application/json (<abbr title="{http://www.example.com} forumVOes">ns3:forumVOes</abbr>) + <h3 id="d2e2304">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e2318">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<forums totalCount="1"> - <forums> - <forums name="My forum" detailsName="It is a forum" forumKey="3865487" courseKey="286" courseNodeId="2784628" subscribed="false"/> - </forums> -</forums> +<courseNodeVO> + <id>id</id> +</courseNodeVO> </code></pre></p> <p>The course node metadatas</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1770"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2331"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1776"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2337"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The course or parentNode not found</p> - <h3 id="d2e1783">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e1797">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) + <h3 id="d2e2357">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -20987,11 +21647,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1810"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2370"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1816"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2376"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The course or parentNode not found</p> - <h3 id="d2e1832">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + <h3 id="d2e2392">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21001,11 +21661,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1845"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2405"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1851"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2411"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The course or parentNode not found</p> - <h3 id="d2e1880">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e2440">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21020,11 +21680,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1893"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2453"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1899"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2459"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e1928">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e2488">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21039,11 +21699,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1941"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2501"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1947"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2507"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e1961">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + <h3 id="d2e2521">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21053,11 +21713,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e1974"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2534"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e1980"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2540"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The forum not found</p> - <h3 id="d2e1999">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e2559">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21076,11 +21736,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2012"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2572"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2018"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2578"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e2037">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e2597">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21095,13 +21755,13 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2050"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2610"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2056"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2616"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e2063">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2623">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e2070">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e2630">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21116,11 +21776,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2083"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2643"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2089"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2649"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e2111">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e2671">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21139,13 +21799,13 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2124"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2684"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2130"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2690"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e2141">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2701">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e2154">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e2714">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21160,21 +21820,21 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2167"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2727"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2173"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2733"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author or message not found</p> - <h3 id="d2e2180">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e2740">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2181">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e2741">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2185">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e2745">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21189,11 +21849,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2198"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2758"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2204"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2764"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author or message not found</p> - <h3 id="d2e2223">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e2783">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21208,390 +21868,256 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2236"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2796"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2242"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2802"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author or message not found</p> - <h3 id="d2e2255">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2815">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The links to the attachments</p> - <h3 id="d2e2261"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2821"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The message not found</p> - <h3 id="d2e2268">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2828">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e2274">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2834">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>Ok</p> - <h3 id="d2e2280"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2840"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e2287">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e2847">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2288">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e2848">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2292">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2852">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>Ok</p> - <h3 id="d2e2298"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2858"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e2307">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2867">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>Ok</p> - <h3 id="d2e2313"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2873"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e2329">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2889">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The portrait as image</p> - <h3 id="d2e2335"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2895"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e2355">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2910">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<subscriptionInfoVOes> - <subscriptionInfoVO> - <title>Infos</title> - <items/> - </subscriptionInfoVO> -</subscriptionInfoVOes> +<forum name="My forum" detailsName="It is a forum" forumKey="3865487" courseKey="286" courseNodeId="2784628" subscribed="false"/> </code></pre></p> - <p>The notifications</p> - <h3 id="d2e2368"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity not found</p> - <h3 id="d2e2374">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2375">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2377">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2382">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2389">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2390">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2395">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2401">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2406">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2411">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2412">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2413">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2414">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2415">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2418">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2419">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2422">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e2427">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2428">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2431">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2432">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2435">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2436">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2438">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2439">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2444">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2445">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2446">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2447">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2448">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2451">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2453">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2456">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e2461">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2462">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2463">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2466">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2467">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2468">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2471">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2472">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2475">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2478">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2479">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2482">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2483">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2487">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2492">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2493">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2504">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>) - </h3> + <p>The forums</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2505">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>) + <h3 id="d2e2923"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e2937">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<forum name="My forum" detailsName="It is a forum" forumKey="3865487" courseKey="286" courseNodeId="2784628" subscribed="false"/> +</code></pre></p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2509">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>) + <h3 id="d2e2950"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e2956"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The forum not found</p> + <h3 id="d2e2975">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<authenticationVO> - <key>38759</key> - <identityKey>345</identityKey> - <provider>OLAT</provider> - <authUsername>john</authUsername> -</authenticationVO> +<messages totalCount="1"> + <messages> + <message> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> + </message> + </messages> +</messages> </code></pre></p> - <p>The saved authentication</p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2522"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e2988"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2528"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity not found</p> - <h3 id="d2e2534"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Cannot create the authentication for an unkown reason</p> - <h3 id="d2e2540"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Cannot create the authentication because the authentication username is already used by someone else within the same provider</p> - <h3 id="d2e2547">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>) + <h3 id="d2e2994"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author, forum or message not found</p> + <h3 id="d2e3013">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<authenticationVOes> - <authenticationVO> - <key>38759</key> - <identityKey>345</identityKey> - <provider>OLAT</provider> - <authUsername>john</authUsername> - </authenticationVO> -</authenticationVOes> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> </code></pre></p> - <p>The list of all users in the OLAT system</p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2558"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2562"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity not found</p> - <h3 id="d2e2578"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The authentication successfully deleted</p> - <h3 id="d2e2584"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3026"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2590"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the authentication not found</p> - <h3 id="d2e2601">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3032"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author, forum or message not found</p> + <h3 id="d2e3039">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e2608"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The password successfully changed</p> - <h3 id="d2e2614"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2620"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The password was not changed</p> - <h3 id="d2e2626"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the authentication not found</p> - <h3 id="d2e2636">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p> - <h6>Example</h6><pre><code>1.0</code></pre></p> - <p>The version of this specific Web Service</p> - <h3 id="d2e2663">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>) + <h3 id="d2e3046">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<keyValuePair> - <key>Prefered color</key> - <value>Green</value> -</keyValuePair> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> </code></pre></p> - <p>The value in the course</p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2674"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The entry cannot be found</p> - <h3 id="d2e2685"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The value is saved in the course</p> - <h3 id="d2e2692">text/plain, text/html (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>) + <h3 id="d2e3059"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3065"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author, forum or message not found</p> + <h3 id="d2e3087">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> - <h6>Example</h6><pre><code>Green</code></pre></p> - <p>A value of the course</p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messages totalCount="1"> + <messages> + <message> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> + </message> + </messages> +</messages> +</code></pre></p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2703"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The entry cannot be found</p> - <h3 id="d2e2710">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e2715"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The value is saved in the course</p> - <h3 id="d2e2722"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>the key value pair is remove from the db</p> - <h3 id="d2e2726"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3100"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2730"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The entry cannot be found</p> - <h3 id="d2e2744">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2745">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2747"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>the key value pair is saved on the db</p> - <h3 id="d2e2754">application/xml, application/json (<abbr title="{http://www.example.com} keyValuePair">ns3:keyValuePair</abbr>) + <h3 id="d2e3106"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author, forum or message not found</p> + <h3 id="d2e3117">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e3130">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<keyValuePairVOes> - <keyValuePairVO> - <key>Prefered color</key> - <value>Green</value> - </keyValuePairVO> -</keyValuePairVOes> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> </code></pre></p> - <p>All the values in the course</p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2768">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>) + <h3 id="d2e3143"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3149"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author or message not found</p> + <h3 id="d2e3156">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2769">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">keyValuePair</abbr>) + <h3 id="d2e3157">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2771"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>the key value pair is saved on the db</p> - <h3 id="d2e2779">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p> - <h6>Example</h6><pre><code>1.0</code></pre></p> - <p>The version of this specific Web Service</p> - <h3 id="d2e2803"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>the key value pair is remove from the db</p> - <h3 id="d2e2807"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e2811"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The entry cannot be found</p> - <h3 id="d2e2825"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Registration successful</p> - <h3 id="d2e2829"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Already registered, HTTP-Header location set to redirect</p> - <h3 id="d2e2836">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e2841"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Registration successful</p> - <h3 id="d2e2845"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Already registered, HTTP-Header location set to redirect</p> - <h3 id="d2e2858">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2859">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2862">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>) + <h3 id="d2e3161">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> +</code></pre></p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2863">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">courseVO</abbr>) + <h3 id="d2e3174"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author or message not found</p> + <h3 id="d2e3199">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> + <p> + <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> +</code></pre></p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e2865">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2866">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2887">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2888">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2891">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2892">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2896">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2901">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2902">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2905">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2906">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2910">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2915">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2916">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2919">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e2927">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2928">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2932">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2933">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2936">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2937">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2939">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2943">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2944">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2952">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2953">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2957">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2958">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2961">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2962">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2964">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2968">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2969">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2972">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2973">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2975">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2980">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2985">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2986">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2990">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3212"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3218"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author or message not found</p> + <h3 id="d2e3231">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The links to the attachments</p> + <h3 id="d2e3237"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The message not found</p> + <h3 id="d2e3244">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e2993">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2994">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e2998">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3002">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3007">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3008">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3011">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3014">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3015">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3020">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3024">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3025">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + <h3 id="d2e3250">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e3256"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e3263">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3027">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3028">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3031">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3032">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3036">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3041">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3044">*/* (<abbr title="{http://wadl.dev.java.net/2009/02} ">groupVO</abbr>) + <h3 id="d2e3264">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3046">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3049">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3060">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + <h3 id="d2e3268">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e3274"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e3283">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e3289"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e3305">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The portrait as image</p> + <h3 id="d2e3311"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e3324">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21601,11 +22127,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3073"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3337"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3079"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3343"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The forum not found</p> - <h3 id="d2e3098">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e3362">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21624,11 +22150,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3111"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3375"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3117"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3381"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e3136">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e3400">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21643,13 +22169,13 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3149"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3413"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3155"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3419"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e3162">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3426">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e3169">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e3433">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21664,11 +22190,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3182"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3446"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3188"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3452"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e3210">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e3474">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21687,13 +22213,13 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3223"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3487"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3229"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3493"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e3240">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3504">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e3253">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e3517">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21708,21 +22234,21 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3266"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3530"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3272"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3536"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author or message not found</p> - <h3 id="d2e3279">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e3543">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3280">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e3544">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3284">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e3548">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21737,11 +22263,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3297"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3561"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3303"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3567"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author or message not found</p> - <h3 id="d2e3322">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e3586">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -21756,629 +22282,597 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3335"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3599"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3341"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3605"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author or message not found</p> - <h3 id="d2e3354">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3618">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The links to the attachments</p> - <h3 id="d2e3360"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3624"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The message not found</p> - <h3 id="d2e3367">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3631">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e3373">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3637">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>Ok</p> - <h3 id="d2e3379"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3643"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e3386">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e3650">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3387">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e3651">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3391">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3655">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>Ok</p> - <h3 id="d2e3397"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3661"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e3406">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3670">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>Ok</p> - <h3 id="d2e3412"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3676"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e3428">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3692">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The portrait as image</p> - <h3 id="d2e3434"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3698"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e3441">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3442">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3443">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3444">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3445">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3448">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3449">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3452">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e3457">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3458">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3461">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3462">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3465">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3466">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3468">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3469">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3475">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3476">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3477">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3478">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3481">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3482">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3483">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3486">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e3491">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3492">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3493">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3496">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3497">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3498">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3501">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3502">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3504">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3505">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3508">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3509">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3512">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3513">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3517">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3522">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3523">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3531">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3532">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3536">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3537">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3539">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3540">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3543">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3544">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3545">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">eventVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3547">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3548">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3552">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3553">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3555">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3556">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3563">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3564">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3567">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3568">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3570">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3571">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3582">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroBookingVO> - <bookingId>23</bookingId> - <groupId>24</groupId> - <groupName>NEW-EVENT_OLAT_938745983</groupName> - <eventName>New event</eventName> - <externalId>AC-234</externalId> - <start>2017-06-09T11:28:51.381+02:00</start> - <startBuffer>15</startBuffer> - <end>2017-06-09T11:28:51.381+02:00</end> - <endBuffer>15</endBuffer> - <roomSize>22</roomSize> - <autoSignIn>true</autoSignIn> - <timeZoneId></timeZoneId> -</viteroBookingVO> -</code></pre></p> - <p>This is the list of all bookings of a resource</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3596">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3597">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3601">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) + <h3 id="d2e3713">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3720">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The certificate as file</p> + <h3 id="d2e3726"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3732"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The owner or the certificate cannot be found</p> + <h3 id="d2e3737">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3754"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>If the certificate was created</p> + <h3 id="d2e3760"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3766"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>An unexpected error happened during the creation of the certificate</p> + <h3 id="d2e3772"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the resource cannot be found</p> + <h3 id="d2e3781"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>if the certificate was uploaded</p> + <h3 id="d2e3787"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3793"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the resource cannot be found</p> + <h3 id="d2e3800">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3804">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3809">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3823">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The portrait as image</p> + <h3 id="d2e3829"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e3836">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3837">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3843">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3844">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3850">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3851">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3854">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroBookingVO> - <bookingId>23</bookingId> - <groupId>24</groupId> - <groupName>NEW-EVENT_OLAT_938745983</groupName> - <eventName>New event</eventName> - <externalId>AC-234</externalId> - <start>2017-06-09T11:28:51.381+02:00</start> - <startBuffer>15</startBuffer> - <end>2017-06-09T11:28:51.381+02:00</end> - <endBuffer>15</endBuffer> - <roomSize>22</roomSize> - <autoSignIn>true</autoSignIn> - <timeZoneId></timeZoneId> -</viteroBookingVO> -</code></pre></p> - <p>The created booking</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3615">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) + <h3 id="d2e3855">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3616">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) + <h3 id="d2e3857">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3861">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3868">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3869">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3877">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3878">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3889">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3890">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e3901">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3620">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) + <h3 id="d2e3902">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">authenticationVO</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroBookingVO> - <bookingId>23</bookingId> - <groupId>24</groupId> - <groupName>NEW-EVENT_OLAT_938745983</groupName> - <eventName>New event</eventName> - <externalId>AC-234</externalId> - <start>2017-06-09T11:28:51.381+02:00</start> - <startBuffer>15</startBuffer> - <end>2017-06-09T11:28:51.381+02:00</end> - <endBuffer>15</endBuffer> - <roomSize>22</roomSize> - <autoSignIn>true</autoSignIn> - <timeZoneId></timeZoneId> -</viteroBookingVO> -</code></pre></p> - <p>The created booking</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3640">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>) + <h3 id="d2e3906">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroGroupMemberVO> - <identityKey>23497</identityKey> - <groupRole>participant</groupRole> -</viteroGroupMemberVO> +<authenticationVO> + <key>38759</key> + <identityKey>345</identityKey> + <provider>OLAT</provider> + <authUsername>john</authUsername> +</authenticationVO> </code></pre></p> - <p>This is the list of all bookings of a resource</p> + <p>The saved authentication</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3654">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3655">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3659">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>) + <h3 id="d2e3919"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3925"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity not found</p> + <h3 id="d2e3931"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Cannot create the authentication for an unkown reason</p> + <h3 id="d2e3937"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Cannot create the authentication because the authentication username is already used by someone else within the same provider</p> + <h3 id="d2e3944">application/xml, application/json (<abbr title="{http://www.example.com} authenticationVO">ns3:authenticationVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroGroupMemberVO> - <identityKey>23497</identityKey> - <groupRole>participant</groupRole> -</viteroGroupMemberVO> +<authenticationVOes> + <authenticationVO> + <key>38759</key> + <identityKey>345</identityKey> + <provider>OLAT</provider> + <authUsername>john</authUsername> + </authenticationVO> +</authenticationVOes> </code></pre></p> - <p>This is the list of all bookings of a resource</p> + <p>The list of all users in the OLAT system</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3677"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The booking is deleted</p> - <h3 id="d2e3691">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>) - </h3> + <h3 id="d2e3955"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3959"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity not found</p> + <h3 id="d2e3975"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The authentication successfully deleted</p> + <h3 id="d2e3981"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e3987"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the authentication not found</p> + <h3 id="d2e3998">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e4005"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The password successfully changed</p> + <h3 id="d2e4011"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e4017"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The password was not changed</p> + <h3 id="d2e4023"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the authentication not found</p> + <h3 id="d2e4033">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<trainingVO> - <key>4534759</key> - <name>Training</name> - <externalId>AC-234</externalId> - <start>2017-06-09T11:28:51.373+02:00</start> - <end>2017-06-09T11:28:51.373+02:00</end> -</trainingVO> -</code></pre></p> - <p>This is the list of all training of a resource</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3705">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3706">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3710">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>) - </h3> + <h6>Example</h6><pre><code>1.0</code></pre></p> + <p>The version of this specific Web Service</p> + <h3 id="d2e4046">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4047">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4064">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<trainingVO> - <key>4534759</key> - <name>Training</name> - <externalId>AC-234</externalId> - <start>2017-06-09T11:28:51.373+02:00</start> - <end>2017-06-09T11:28:51.373+02:00</end> -</trainingVO> +<subscriptionInfoVOes> + <subscriptionInfoVO> + <title>Infos</title> + <items/> + </subscriptionInfoVO> +</subscriptionInfoVOes> </code></pre></p> - <p>Created a training</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3724">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>) + <p>The notifications</p> + <h3 id="d2e4077"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity not found</p> + <h3 id="d2e4083">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3725">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">trainingVO</abbr>) + <h3 id="d2e4084">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">subscribersVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3729">application/xml, application/json (<abbr title="{http://www.example.com} goToTrainingVO">ns3:goToTrainingVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<trainingVO> - <key>4534759</key> - <name>Training</name> - <externalId>AC-234</externalId> - <start>2017-06-09T11:28:51.373+02:00</start> - <end>2017-06-09T11:28:51.373+02:00</end> -</trainingVO> -</code></pre></p> - <p>The created booking</p> + <h3 id="d2e4086">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4091">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4098">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4099">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4108">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4112">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4123">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4124">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4127">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4128">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4131">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4132">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4141">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4142">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4146">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4151">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4152">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4155">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4156">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4159">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>) + </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3747"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The training is deleted</p> - <h3 id="d2e3753">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3754">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3757">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) + <h3 id="d2e4160">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3758">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) + <h3 id="d2e4162">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4163">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4166">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4167">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4173">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4176">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4181">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4182">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4184">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4187">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4188">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4193">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4194">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4199">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e4202">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4203">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4208">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4209">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4212">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4213">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4215">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4221">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4224">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4230">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4231">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4233">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4236">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4237">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4243">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4246">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4251">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4252">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4255">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3760">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3761">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3764">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3765">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) + <h3 id="d2e4256">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3766">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) + <h3 id="d2e4258">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4259">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4262">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4263">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3768">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3769">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3773">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3774">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3777">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3778">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>) + <h3 id="d2e4264">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">lectureBlocksVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3779">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>) + <h3 id="d2e4266">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4267">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4271">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4272">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4275">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4276">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3781">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3782">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3787">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3790">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3795">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3798">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3802">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3806">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3809">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3813">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3821">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3822">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3833">application/zip<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3834">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3842">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3843">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3848">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3852">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3857">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3862">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3866">application/xhtml+xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3867">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3870">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3874">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3875">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3888">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3895">application/pdf<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The certificate as file</p> - <h3 id="d2e3901"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3907"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The owner or the certificate cannot be found</p> - <h3 id="d2e3912">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e3929"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>If the certificate was created</p> - <h3 id="d2e3935"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3941"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>An unexpected error happened during the creation of the certificate</p> - <h3 id="d2e3947"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the resource cannot be found</p> - <h3 id="d2e3956"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>if the certificate was uploaded</p> - <h3 id="d2e3962"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e3968"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the resource cannot be found</p> - <h3 id="d2e3984">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + <h3 id="d2e4277">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">repositoryEntryLectureConfigurationVO</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<forum name="My forum" detailsName="It is a forum" forumKey="3865487" courseKey="286" courseNodeId="2784628" subscribed="false"/> -</code></pre></p> - <p>The forums</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e3997"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4011">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + <h3 id="d2e4279">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4280">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4284">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4288">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4293">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4296">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4297">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4302">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4305">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4309">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4310">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4314">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4317">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4321">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4376">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<forum name="My forum" detailsName="It is a forum" forumKey="3865487" courseKey="286" courseNodeId="2784628" subscribed="false"/> +<courseNodeVO> + <id>id</id> +</courseNodeVO> </code></pre></p> - <p>The root message of the thread</p> + <p>The course node metadatas</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4024"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4389"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4030"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The forum not found</p> - <h3 id="d2e4049">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e4395"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or parentNode not found</p> + <h3 id="d2e4402">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e4425">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messages totalCount="1"> - <messages> - <message> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> - </message> - </messages> -</messages> +<courseNodeVO> + <id>id</id> +</courseNodeVO> </code></pre></p> - <p>The root message of the thread</p> + <p>The course node metadatas</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4062"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4438"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4068"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author, forum or message not found</p> - <h3 id="d2e4087">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e4444"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or parentNode not found</p> + <h3 id="d2e4451">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4456">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4461">image/jpeg<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4465">application/xhtml+xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4466">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4469">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4473">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4515">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> +<courseNodeVO> + <id>id</id> +</courseNodeVO> </code></pre></p> - <p>The root message of the thread</p> + <p>The course node metadatas</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4100"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4528"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4106"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author, forum or message not found</p> - <h3 id="d2e4113">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4534"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or parentNode not found</p> + <h3 id="d2e4541">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e4120">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e4572">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> +<courseNodeVO> + <id>id</id> +</courseNodeVO> </code></pre></p> - <p>The root message of the thread</p> + <p>The course node metadatas</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4133"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4585"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4139"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author, forum or message not found</p> - <h3 id="d2e4161">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e4591"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or parentNode not found</p> + <h3 id="d2e4603">application/xml, application/json (<abbr title="{http://www.example.com} groupVO">ns3:groupVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messages totalCount="1"> - <messages> - <message> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> - </message> - </messages> -</messages> +<groupVO> + <key>123467</key> + <description>My group description</description> + <externalId>External Identifier</externalId> + <managedFlags>title,description</managedFlags> + <name>My group</name> + <minParticipants>0</minParticipants> + <maxParticipants>0</maxParticipants> +</groupVO> </code></pre></p> - <p>The root message of the thread</p> + <p>The groups</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4174"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4616"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author, forum or message not found</p> - <h3 id="d2e4191">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e4204">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e4622"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The course or course node not found</p> + <h3 id="d2e4628">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4629">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4637">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4638">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4644">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4647">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4650">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4655">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4656">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4659">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> -</code></pre></p> - <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4217"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4223"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author or message not found</p> - <h3 id="d2e4230">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e4660">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4231">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) + <h3 id="d2e4662">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4663">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4671">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4672">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4675">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e4680">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4681">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4685">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4235">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e4686">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">catalogEntryVO</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> -</code></pre></p> - <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4248"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4254"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author or message not found</p> - <h3 id="d2e4273">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e4688">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4689">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4696">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4697">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4700">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4701">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4706">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4707">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4711">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4716">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4717">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4721">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4722">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4727">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4728">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4731">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e4734">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4737">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4741">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4742">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4747">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4748">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4752">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4757">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4758">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4762">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4763">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4767">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4768">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4772">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4773">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4777">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4778">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4782">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4783">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4787">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4788">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4792">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4793">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4797">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4798">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4802">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4803">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4807">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4808">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4812">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4813">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4817">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4818">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4822">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4823">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4826">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e4829">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4832">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4836">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4839">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4840">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4844">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4847">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4848">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4856">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4857">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4861">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4864">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4865">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4869">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4870">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4874">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4875">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4879">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4880">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4883">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e4886">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4889">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4901"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Registration successful</p> + <h3 id="d2e4905"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Already registered, HTTP-Header location set to redirect</p> + <h3 id="d2e4912">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e4917"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Registration successful</p> + <h3 id="d2e4921"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Already registered, HTTP-Header location set to redirect</p> + <h3 id="d2e4928">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4934">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4939">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4944">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4945">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4946">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4947">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4948">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4951">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4952">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4955">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e4960">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4961">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4964">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4965">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4968">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> -</code></pre></p> - <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4286"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4292"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author or message not found</p> - <h3 id="d2e4305">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The links to the attachments</p> - <h3 id="d2e4311"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The message not found</p> - <h3 id="d2e4318">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4969">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e4971">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4972">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4977">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4978">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4979">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4980">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4981">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4984">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4985">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4986">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4989">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e4324">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e4330"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e4337">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e4994">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4995">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4996">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e4999">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5000">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5001">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5004">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4338">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e5005">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4342">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e4348"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e4357">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e4363"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e4379">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The portrait as image</p> - <h3 id="d2e4385"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e4398">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) + <h3 id="d2e5007">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5008">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5011">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5012">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5015">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5016">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5021">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5022">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5026">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5035">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p> + <h6>Example</h6><pre><code>1.0</code></pre></p> + <p>The version of this specific Web Service</p> + <h3 id="d2e5057">application/xml, application/json (<abbr title="{http://www.example.com} forumVO">ns3:forumVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -22388,11 +22882,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4411"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5070"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4417"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5076"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The forum not found</p> - <h3 id="d2e4436">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e5095">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -22411,11 +22905,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4449"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5108"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4455"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5114"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e4474">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e5133">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -22430,13 +22924,13 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4487"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5146"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4493"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5152"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e4500">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5159">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e4507">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) + <h3 id="d2e5166">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -22451,11 +22945,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4520"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5179"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4526"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5185"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The author, forum or message not found</p> - <h3 id="d2e4548">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) + <h3 id="d2e5207">application/xml, application/json (<abbr title="{http://www.example.com} messageVOes">ns3:messageVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -22470,245 +22964,129 @@ </messages> </messages> </code></pre></p> - <p>The root message of the thread</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4561"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4567"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author, forum or message not found</p> - <h3 id="d2e4578">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e4591">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> -</code></pre></p> - <p>The root message of the thread</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4604"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4610"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author or message not found</p> - <h3 id="d2e4617">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4618">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4622">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> -</code></pre></p> - <p>The root message of the thread</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4635"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4641"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author or message not found</p> - <h3 id="d2e4660">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<messageVO> - <key>380</key> - <authorKey>345</authorKey> - <title>A message</title> - <body>The content of the message</body> -</messageVO> -</code></pre></p> - <p>The root message of the thread</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4673"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4679"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The author or message not found</p> - <h3 id="d2e4692">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The links to the attachments</p> - <h3 id="d2e4698"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The message not found</p> - <h3 id="d2e4705">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e4711">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e4717"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e4724">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4725">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4729">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e4735"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e4744">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Ok</p> - <h3 id="d2e4750"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e4766">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The portrait as image</p> - <h3 id="d2e4772"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e4790">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroBookingVO> - <bookingId>23</bookingId> - <groupId>24</groupId> - <groupName>NEW-EVENT_OLAT_938745983</groupName> - <eventName>New event</eventName> - <externalId>AC-234</externalId> - <start>2017-06-09T11:28:51.381+02:00</start> - <startBuffer>15</startBuffer> - <end>2017-06-09T11:28:51.381+02:00</end> - <endBuffer>15</endBuffer> - <roomSize>22</roomSize> - <autoSignIn>true</autoSignIn> - <timeZoneId></timeZoneId> -</viteroBookingVO> -</code></pre></p> - <p>This is the list of all bookings of a resource</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4804">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4805">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) - </h3> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4809">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) + <h3 id="d2e5220"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e5226"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author, forum or message not found</p> + <h3 id="d2e5237">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e5250">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroBookingVO> - <bookingId>23</bookingId> - <groupId>24</groupId> - <groupName>NEW-EVENT_OLAT_938745983</groupName> - <eventName>New event</eventName> - <externalId>AC-234</externalId> - <start>2017-06-09T11:28:51.381+02:00</start> - <startBuffer>15</startBuffer> - <end>2017-06-09T11:28:51.381+02:00</end> - <endBuffer>15</endBuffer> - <roomSize>22</roomSize> - <autoSignIn>true</autoSignIn> - <timeZoneId></timeZoneId> -</viteroBookingVO> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> </code></pre></p> - <p>The created booking</p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4823">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) + <h3 id="d2e5263"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e5269"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author or message not found</p> + <h3 id="d2e5276">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4824">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">viteroBookingVO</abbr>) + <h3 id="d2e5277">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">replyVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4828">application/xml, application/json (<abbr title="{http://www.example.com} viteroBookingVO">ns3:viteroBookingVO</abbr>) + <h3 id="d2e5281">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroBookingVO> - <bookingId>23</bookingId> - <groupId>24</groupId> - <groupName>NEW-EVENT_OLAT_938745983</groupName> - <eventName>New event</eventName> - <externalId>AC-234</externalId> - <start>2017-06-09T11:28:51.381+02:00</start> - <startBuffer>15</startBuffer> - <end>2017-06-09T11:28:51.381+02:00</end> - <endBuffer>15</endBuffer> - <roomSize>22</roomSize> - <autoSignIn>true</autoSignIn> - <timeZoneId></timeZoneId> -</viteroBookingVO> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> </code></pre></p> - <p>The created booking</p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4848">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>) + <h3 id="d2e5294"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e5300"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author or message not found</p> + <h3 id="d2e5319">application/xml, application/json (<abbr title="{http://www.example.com} messageVO">ns3:messageVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroGroupMemberVO> - <identityKey>23497</identityKey> - <groupRole>participant</groupRole> -</viteroGroupMemberVO> +<messageVO> + <key>380</key> + <authorKey>345</authorKey> + <title>A message</title> + <body>The content of the message</body> +</messageVO> </code></pre></p> - <p>This is the list of all bookings of a resource</p> + <p>The root message of the thread</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4862">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e4863">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e4867">application/xml, application/json (<abbr title="{http://www.example.com} viteroGroupMemberVO">ns3:viteroGroupMemberVO</abbr>) + <h3 id="d2e5332"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The roles of the authenticated user are not sufficient</p> + <h3 id="d2e5338"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The author or message not found</p> + <h3 id="d2e5351">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The links to the attachments</p> + <h3 id="d2e5357"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The message not found</p> + <h3 id="d2e5364">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <div class="representation"></div> + <h3 id="d2e5370">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e5376"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e5383">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<viteroGroupMemberVO> - <identityKey>23497</identityKey> - <groupRole>participant</groupRole> -</viteroGroupMemberVO> -</code></pre></p> - <p>This is the list of all bookings of a resource</p> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4885"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The booking is deleted</p> - <h3 id="d2e4895">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>) + <h3 id="d2e5384">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + </h3> + <div class="representation"> + <h6>XML Schema</h6> + <p><em>Source: <a href=""></a></em></p><pre></pre></div> + <h3 id="d2e5388">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e5394"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e5403">application/json, application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Ok</p> + <h3 id="d2e5409"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e5425">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The portrait as image</p> + <h3 id="d2e5431"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e5442">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5443">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5447">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5455">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4896">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>) + <h3 id="d2e5456">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4900">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5460">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <userVO> @@ -22731,9 +23109,9 @@ </userVO> </code></pre></p> <p>The persisted user</p> - <h3 id="d2e4913"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5473"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4919">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5479">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <errorVOes> @@ -22744,7 +23122,7 @@ </errorVOes> </code></pre></p> <p>The list of errors</p> - <h3 id="d2e4940">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>) + <h3 id="d2e5500">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -22775,19 +23153,19 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4953"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5513"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4964">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>) + <h3 id="d2e5524">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4965">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>) + <h3 id="d2e5525">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">userVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4969">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>) + <h3 id="d2e5529">application/xml, application/json (<abbr title="{http://www.example.com} userVO">ns3:userVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -22814,11 +23192,11 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e4982"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5542"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e4988"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5548"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity not found</p> - <h3 id="d2e4994">application/xml, application/json (<abbr title="{http://www.example.com} errorVO">ns3:errorVO</abbr>) + <h3 id="d2e5554">application/xml, application/json (<abbr title="{http://www.example.com} errorVO">ns3:errorVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -22833,13 +23211,13 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5010"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5570"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The user is removed from the group</p> - <h3 id="d2e5016"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5576"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5022"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5582"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity not found</p> - <h3 id="d2e5035">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5595">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <userVO> @@ -22862,11 +23240,29 @@ </userVO> </code></pre></p> <p>The user</p> - <h3 id="d2e5048"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5608"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5054"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5614"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity not found</p> - <h3 id="d2e5067">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5627">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The portrait as image</p> + <h3 id="d2e5633"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e5642">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The portrait as image</p> + <h3 id="d2e5648"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e5657">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The portrait as image</p> + <h3 id="d2e5663"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Not authorized</p> + <h3 id="d2e5669"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The identity or the portrait not found</p> + <h3 id="d2e5678"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The portrait deleted</p> + <h3 id="d2e5684"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>Not authorized</p> + <h3 id="d2e5697">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <statusVO> @@ -22874,21 +23270,21 @@ </statusVO> </code></pre></p> <p>The user</p> - <h3 id="d2e5080"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5710"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5086"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5716"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity not found</p> - <h3 id="d2e5093">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>) + <h3 id="d2e5723">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5094">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>) + <h3 id="d2e5724">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">statusVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5098">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5728">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <rolesVO> @@ -22903,11 +23299,11 @@ </rolesVO> </code></pre></p> <p>The user</p> - <h3 id="d2e5111"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5741"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5117"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5747"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity not found</p> - <h3 id="d2e5130">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5760">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <rolesVO> @@ -22922,21 +23318,21 @@ </rolesVO> </code></pre></p> <p>The user</p> - <h3 id="d2e5143"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5773"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5149"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5779"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity not found</p> - <h3 id="d2e5156">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>) + <h3 id="d2e5786">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5157">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>) + <h3 id="d2e5787">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">rolesVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5161">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5791">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <rolesVO> @@ -22951,35 +23347,13 @@ </rolesVO> </code></pre></p> <p>The user</p> - <h3 id="d2e5174"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5804"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5180"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5810"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity not found</p> - <h3 id="d2e5190">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p> - <h6>Example</h6><pre><code>1.0</code></pre></p> - <p>The version of this specific Web Service</p> - <h3 id="d2e5210">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The portrait as image</p> - <h3 id="d2e5216"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e5225">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The portrait as image</p> - <h3 id="d2e5231"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e5240">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The portrait as image</p> - <h3 id="d2e5246"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Not authorized</p> - <h3 id="d2e5252"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e5261"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The portrait deleted</p> - <h3 id="d2e5267"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>Not authorized</p> - <h3 id="d2e5273">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5274">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5285">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5816">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5817">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5828">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <preferencesVO> @@ -22987,21 +23361,21 @@ </preferencesVO> </code></pre></p> <p>The preferences</p> - <h3 id="d2e5298"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5841"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5304"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5847"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity not found</p> - <h3 id="d2e5311">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>) + <h3 id="d2e5854">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5312">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>) + <h3 id="d2e5855">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">preferencesVO</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5316">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5859">application/xml, application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <preferencesVO> @@ -23009,15 +23383,19 @@ </preferencesVO> </code></pre></p> <p>The user</p> - <h3 id="d2e5329"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5872"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5335"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5878"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity not found</p> - <h3 id="d2e5347">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5890">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The portrait as image</p> - <h3 id="d2e5353"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5896"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The identity or the portrait not found</p> - <h3 id="d2e5367">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>) + <h3 id="d2e5906">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p> + <h6>Example</h6><pre><code>1.0</code></pre></p> + <p>The version of this specific Web Service</p> + <h3 id="d2e5927">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -23031,189 +23409,189 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5380"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5940"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5388">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5389">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5390">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5391">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5392">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5395">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5396">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5399">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5948">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5949">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5950">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5951">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5952">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5955">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5956">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5959">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e5404">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5405">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5408">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5409">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5412">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e5964">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5965">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5968">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5969">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5972">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5413">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e5973">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5415">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5416">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5421">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5422">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5423">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5424">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5425">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5428">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5429">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5430">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5433">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5975">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5976">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5981">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5982">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5983">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5984">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5985">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5988">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5989">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5990">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5993">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e5438">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5439">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5440">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5443">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5444">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5445">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5448">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e5998">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e5999">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6000">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6003">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6004">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6005">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6008">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5449">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e6009">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5451">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5452">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5455">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5456">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5459">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5460">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5464">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5469">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5470">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5474">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5475">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5476">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5477">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5478">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5481">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5482">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5485">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6011">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6012">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6015">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6016">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6019">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6020">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6025">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6026">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6030">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6034">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6035">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6036">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6037">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6038">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6041">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6042">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6045">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e5490">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5491">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5494">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5495">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5498">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e6050">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6051">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6054">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6055">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6058">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5499">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e6059">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5501">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5502">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5507">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5508">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5509">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5510">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5511">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5514">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5515">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5516">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5519">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6061">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6062">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6067">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6068">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6069">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6070">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6071">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6074">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6075">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6076">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6079">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e5524">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5525">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5526">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5529">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5530">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5531">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5534">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e6084">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6085">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6086">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6089">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6090">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6091">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6094">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5535">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e6095">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5537">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5538">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5541">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5542">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5545">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5546">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5550">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5555">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5556">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5561">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5562">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5563">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5564">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5565">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5568">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5569">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5572">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6097">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6098">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6101">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6102">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6105">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6106">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6111">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6112">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6116">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6121">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6122">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6123">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6124">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6125">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6128">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6129">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6132">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e5577">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5578">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5581">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5582">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5585">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e6137">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6138">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6141">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6142">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6145">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5586">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e6146">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5588">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5589">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5594">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5595">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5596">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5597">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5598">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5601">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5602">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5603">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5606">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6148">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6149">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6154">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6155">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6156">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6157">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6158">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6161">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6162">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6163">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6166">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e5611">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5612">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5613">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5616">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5617">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5618">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5621">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e6171">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6172">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6173">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6176">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6177">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6178">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6181">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5622">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) + <h3 id="d2e6182">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) </h3> <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5624">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5625">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5628">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5629">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5632">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5633">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5637">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5642">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5643">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5660">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>) + <h3 id="d2e6184">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6185">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6188">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6189">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6192">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6193">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6198">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6199">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6203">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6220">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -23236,9 +23614,9 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5673"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6233"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5690">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>) + <h3 id="d2e6250">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -23261,9 +23639,9 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5703"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6263"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5720">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>) + <h3 id="d2e6280">application/xml, application/json (<abbr title="{http://www.example.com} courseVO">ns3:courseVO</abbr>) </h3> <p> <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> @@ -23286,344 +23664,126 @@ <div class="representation"> <h6>XML Schema</h6> <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5733"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5745">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5746">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5755">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5756">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5765">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5766">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5775">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5776">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5781">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5782">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5786">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5792">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5793">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5799">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5800">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5803">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5804">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">assessableResultsVO</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5806">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5813">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5814">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e5827">application/xml, application/json (<abbr title="{http://www.example.com} folderVOes">ns3:folderVOes</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<folders totalCount="1"> - <folders> - <folder name="Course folder" courseKey="375397" courseNodeId="438950850389" subscribed="true" write="false" read="false" list="false" delete="false"/> - </folders> -</folders> -</code></pre></p> - <p>The course node metadatas</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5840"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5846"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or parentNode not found</p> - <h3 id="d2e5880">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<courseNodeVO> - <id>id</id> -</courseNodeVO> -</code></pre></p> - <p>The folder node metadatas</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5893"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5899"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or parentNode not found</p> - <h3 id="d2e5906">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e5934">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<courseNodeVO> - <id>id</id> -</courseNodeVO> -</code></pre></p> - <p>The folder node metadatas</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e5947"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e5953"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or parentNode not found</p> - <h3 id="d2e5967">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e5989">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<courseNodeVO> - <id>id</id> -</courseNodeVO> -</code></pre></p> - <p>The folder node metadatas</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e6002"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e6008"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or parentNode not found</p> - <h3 id="d2e6017">application/xml, application/json (<abbr title="{http://www.example.com} folderVO">ns3:folderVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<folder name="Course folder" courseKey="375397" courseNodeId="438950850389" subscribed="true" write="false" read="false" list="false" delete="false"/> -</code></pre></p> - <p>The course node metadatas</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e6030"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e6036"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or parentNode not found</p> - <h3 id="d2e6044">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6045">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6046">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6047">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6048">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6051">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6052">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6055">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e6060">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6061">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6064">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6065">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6068">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e6069">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e6071">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6072">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6077">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6078">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6079">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6080">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6081">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6084">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6085">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6086">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6089">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e6094">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6095">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6096">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6099">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6100">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6101">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6104">application/json (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e6105">application/xml (<abbr title="{http://wadl.dev.java.net/2009/02} ">fileUpload</abbr>) - </h3> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e6107">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6108">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6111">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6112">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6115">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6116">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6120">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6125">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6126">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6137">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <div class="representation"></div> - <h3 id="d2e6160">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<courseNodeVO> - <id>id</id> -</courseNodeVO> -</code></pre></p> - <p>The course node metadatas</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e6173"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e6179"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or parentNode not found</p> - <h3 id="d2e6232">application/xml, application/json (<abbr title="{http://www.example.com} courseNodeVO">ns3:courseNodeVO</abbr>) - </h3> - <p> - <h6>Example</h6><pre><code><?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<courseNodeVO> - <id>id</id> -</courseNodeVO> -</code></pre></p> - <p>The course node metadatas</p> - <div class="representation"> - <h6>XML Schema</h6> - <p><em>Source: <a href=""></a></em></p><pre></pre></div> - <h3 id="d2e6245"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6293"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <p>The roles of the authenticated user are not sufficient</p> - <h3 id="d2e6251"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The course or parentNode not found</p> - <h3 id="d2e6258">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6264">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6265">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6271">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6272">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6277">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6278">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6290">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6291">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6297">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6298">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6303">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6305">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6306">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6315">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6316">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6325">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6326">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6335">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6336">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6343">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6344">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6349">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6350">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6363"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <p>The list of contacts</p> + <h3 id="d2e6372">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6373">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6377">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6383">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6384">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6389">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6390">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6402">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6403">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6409">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6410">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6415">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6314">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6315">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6318">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6319">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6322">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6323">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6336">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6337">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6343">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6426">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6427">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6430">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6431">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6434">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6435">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6448">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6449">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6455">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6352">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6353">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6358">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6464">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6465">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6470">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6369">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6370">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6383">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6384">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6390">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6481">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6482">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6495">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6496">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6502">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6398">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6399">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6404">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6510">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6511">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6516">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6414">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6415">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6427">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6428">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6434">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6526">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6527">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6539">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6540">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6546">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6441">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6442">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6448">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6553">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6554">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6560">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6457">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6458">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6469">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6470">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6476">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6569">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6570">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6581">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6582">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6588">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6484">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6485">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6499">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6500">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6512">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6513">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6519">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6596">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6597">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6611">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6612">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6624">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6625">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6631">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6527">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6528">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6542">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6543">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6555">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6556">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6562">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6639">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6640">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6654">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6655">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6667">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6668">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6674">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6570">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6571">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6585">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6586">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6598">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6599">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6605">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6682">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6683">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6697">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6698">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6710">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6711">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6717">application/x-www-form-urlencoded<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <div class="representation"></div> - <h3 id="d2e6613">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6614">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6628">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6629">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6641">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6642">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6648">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6649">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6652">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6653">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6687">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6688">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6719">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6720">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6723">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6724">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6739">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6740">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6751">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6752">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6755">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6756">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6781">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6782">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6804">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6805">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6808">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6809">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6813">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6817">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6822">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6829">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6830">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6725">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6726">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6740">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6741">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6753">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6754">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6760">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6761">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6764">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6765">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6799">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6800">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6831">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6832">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <h3 id="d2e6835">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> <h3 id="d2e6836">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6850">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The portrait as image</p> - <h3 id="d2e6856"><abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <p>The identity or the portrait not found</p> - <h3 id="d2e6863">text/plain<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6869">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6870">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6871">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6872">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6877">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6883">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6884">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6885">text/html<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6886">application/octet-stream<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6889">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6892">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6897">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6900">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> - <h3 id="d2e6903">*/*<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6851">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6852">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6863">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6864">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6867">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6868">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6893">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6894">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6916">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6917">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6920">application/xml<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> + <h3 id="d2e6921">application/json<abbr title="{http://wadl.dev.java.net/2009/02} "></abbr></h3> </body> </html> \ No newline at end of file diff --git a/src/main/java/org/olat/restapi/i18n/I18nWebService.java b/src/main/java/org/olat/restapi/i18n/I18nWebService.java index dedd11c75baee6f09f81766afb5838f3123e079e..206536895251e2ac051180f163afd7c9456277d6 100644 --- a/src/main/java/org/olat/restapi/i18n/I18nWebService.java +++ b/src/main/java/org/olat/restapi/i18n/I18nWebService.java @@ -31,6 +31,7 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.util.StringHelper; import org.olat.core.util.i18n.I18nManager; @@ -83,7 +84,8 @@ public class I18nWebService { @Path("{package}/{key}") @Produces(MediaType.TEXT_PLAIN) public Response getTranslation(@PathParam("package") String packageName, @PathParam("key") String key, @QueryParam("locale") String localeKey, @Context HttpServletRequest request) { - I18nManager i18n = I18nManager.getInstance(); + I18nManager i18n = CoreSpringFactory.getImpl(I18nManager.class); + I18nModule i18nModule = CoreSpringFactory.getImpl(I18nModule.class); Locale locale = null; if(StringHelper.containsNonWhitespace(localeKey)) { @@ -96,10 +98,10 @@ public class I18nWebService { } if(locale == null) { - locale = I18nModule.getDefaultLocale(); + locale = i18nModule.getDefaultLocale(); } - boolean overlayEnabled = I18nModule.isOverlayEnabled(); + boolean overlayEnabled = i18nModule.isOverlayEnabled(); String val = i18n.getLocalizedString(packageName, key, EMPTY_ARRAY, locale, overlayEnabled, true); return Response.ok(val).build(); } diff --git a/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java b/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java index f12afadfb37d27fafe27571a01466321543872ff..f54af70c7af47042ab7e7eb4c7cd4e6b7450b3fc 100644 --- a/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java +++ b/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java @@ -1,4 +1,5 @@ /** + * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> diff --git a/src/main/java/org/olat/restapi/repository/RepositoryEntryLifecycleWebService.java b/src/main/java/org/olat/restapi/repository/RepositoryEntryLifecycleWebService.java index 880b50a88fe737d33211cf27930ed4dd2b108765..0b557293e0a2bb979e3752f48a585d07f80e6641 100644 --- a/src/main/java/org/olat/restapi/repository/RepositoryEntryLifecycleWebService.java +++ b/src/main/java/org/olat/restapi/repository/RepositoryEntryLifecycleWebService.java @@ -51,9 +51,9 @@ public class RepositoryEntryLifecycleWebService { /** * List all public lifecycles * @response.representation.200.qname {http://www.example.com}repositoryEntryVO - * @response.representation.200.mediaType text/plain, text/html, application/xml, application/json - * @response.representation.200.doc List all entries in the repository - * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_REPOENTRYVOes} + * @response.representation.200.mediaType text/plain, text/html, application/xml, application/json + * @response.representation.200.doc List all entries in the repository + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_REPOENTRYVOes} * @param uriInfo The URI information * @param httpRequest The HTTP request * @return diff --git a/src/main/java/org/olat/restapi/repository/RepositoryEntryResource.java b/src/main/java/org/olat/restapi/repository/RepositoryEntryResource.java index 50adb5338224cc61cf436e4fd84f16ecd45969dc..5894f819fbc1acf2ad4706b864206d799a015b1e 100644 --- a/src/main/java/org/olat/restapi/repository/RepositoryEntryResource.java +++ b/src/main/java/org/olat/restapi/repository/RepositoryEntryResource.java @@ -160,7 +160,7 @@ public class RepositoryEntryResource { /** * To get the web service for the lecture blocks of a specific learning resource. - * + * @response.representation.200.doc A web service to manage the lecture blocks * @param repoEntryKey The primary key of the learning resource * @return The web service for lecture blocks. */ @@ -173,8 +173,6 @@ public class RepositoryEntryResource { return service; } - //get put/post delete add owner - /** * Returns the list of owners of the repository entry specified by the groupKey. * @response.representation.200.qname {http://www.example.com}userVO diff --git a/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java b/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java index 179c2290e97df3d6e8e5cac796176015e8d9838f..7f9fc07dec0d4c66d5e7ee150cbaa8d4e49ca53b 100644 --- a/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java +++ b/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java @@ -80,6 +80,7 @@ import org.olat.ims.qti.navigator.Navigator; import org.olat.ims.qti.process.AssessmentFactory; import org.olat.ims.qti.process.AssessmentInstance; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.assessment.Role; import org.olat.modules.iq.IQManager; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; @@ -329,7 +330,7 @@ public class CourseAssessmentWebService { } else { AssessableCourseNode assessableNode = (AssessableCourseNode) node; ScoreEvaluation scoreEval = new ScoreEvaluation(resultsVO.getScore(), Boolean.TRUE, Boolean.TRUE, new Long(nodeKey));//not directly pass this key - assessableNode.updateUserScoreEvaluation(scoreEval, userCourseEnvironment, requestIdentity, true); + assessableNode.updateUserScoreEvaluation(scoreEval, userCourseEnvironment, requestIdentity, true, Role.coach); } CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); @@ -440,7 +441,7 @@ public class CourseAssessmentWebService { AssessableCourseNode acn = (AssessableCourseNode) courseNode; // assessment nodes are assessable boolean incrementUserAttempts = true; - acn.updateUserScoreEvaluation(sceval, userCourseEnv, identity, incrementUserAttempts); + acn.updateUserScoreEvaluation(sceval, userCourseEnv, identity, incrementUserAttempts, Role.coach); } else { log.error("Result set already saved"); } diff --git a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java index e54e985419feb9ba5647c54615b75d8efb903b6e..19ba9ea4bb94b15fadb1021314a1895db39b5bb4 100644 --- a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java +++ b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java @@ -48,6 +48,7 @@ import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +import org.olat.basesecurity.BaseSecurityManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.gui.UserRequest; @@ -87,21 +88,21 @@ import org.olat.restapi.support.vo.CourseVO; import org.olat.restapi.support.vo.CourseVOes; /** - * + * * Description:<br> * This web service handles the courses. - * + * * <P> * Initial Date: 27 apr. 2010 <br> * @author srosse, stephane.rosse@frentix.com */ @Path("repo/courses") public class CoursesWebService { - + private static final OLog log = Tracing.createLoggerFor(CoursesWebService.class); - + private static final String VERSION = "1.0"; - + /** * The version of the Course Web Service * @response.representation.200.mediaType text/plain @@ -115,7 +116,7 @@ public class CoursesWebService { public Response getVersion() { return Response.ok(VERSION).build(); } - + /** * Get all courses viewable by the authenticated user * @response.representation.200.qname {http://www.example.com}courseVO @@ -126,7 +127,7 @@ public class CoursesWebService { * @param limit * @param externalId Search with an external ID * @param externalRef Search with an external reference - * @param managed (true / false) Search only managed / not managed groups + * @param managed (true / false) Search only managed / not managed groups * @param httpRequest The HTTP request * @param request The REST request * @return @@ -145,7 +146,7 @@ public class CoursesWebService { Identity identity = getIdentity(httpRequest); SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(identity, roles, CourseModule.getCourseTypeName()); params.setManaged(managed); - + if(StringHelper.containsNonWhitespace(externalId)) { params.setExternalId(externalId); } @@ -174,10 +175,10 @@ public class CoursesWebService { return Response.ok(vos).build(); } } - + public static CourseVO[] toCourseVo(List<RepositoryEntry> repoEntries) { List<CourseVO> voList = new ArrayList<CourseVO>(); - + int count=0; for (RepositoryEntry repoEntry : repoEntries) { try { @@ -190,12 +191,12 @@ public class CoursesWebService { log.error("Cannot load the course with this repository entry: " + repoEntry, e); } } - + CourseVO[] vos = new CourseVO[voList.size()]; voList.toArray(vos); return vos; } - + @Path("{courseId}") public CourseWebService getCourse(@PathParam("courseId") Long courseId) { ICourse course = loadCourse(courseId); @@ -226,7 +227,7 @@ public class CoursesWebService { @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public Response createEmptyCourse(@QueryParam("shortTitle") String shortTitle, @QueryParam("title") String title, @QueryParam("displayName") String displayName, @QueryParam("description") String description, - @QueryParam("softKey") String softKey, @QueryParam("access") Integer access, @QueryParam("membersOnly") Boolean membersOnly, + @QueryParam("softKey") String softKey, @QueryParam("access") Integer access, @QueryParam("membersOnly") Boolean membersOnly, @QueryParam("externalId") String externalId, @QueryParam("externalRef") String externalRef, @QueryParam("authors") String authors, @QueryParam("location") String location, @QueryParam("managedFlags") String managedFlags, @QueryParam("sharedFolderSoftKey") String sharedFolderSoftKey, @@ -237,7 +238,7 @@ public class CoursesWebService { } CourseConfigVO configVO = new CourseConfigVO(); configVO.setSharedFolderSoftKey(sharedFolderSoftKey); - + int accessInt = (access == null ? RepositoryEntry.ACC_OWNERS : access.intValue()); boolean membersOnlyBool = (membersOnly == null ? false : membersOnly.booleanValue()); if(!StringHelper.containsNonWhitespace(displayName)) { @@ -266,7 +267,7 @@ public class CoursesWebService { CourseVO vo = ObjectFactory.get(course); return Response.ok(vo).build(); } - + /** * Creates an empty course * @response.representation.200.qname {http://www.example.com}courseVO @@ -298,24 +299,39 @@ public class CoursesWebService { CourseVO vo = ObjectFactory.get(course); return Response.ok(vo).build(); } - + /** - * - * - * - * @param request - * @return + * Imports a course from a course archive zip file + * @response.representation.200.qname {http://www.example.com}courseVO + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The metadatas of the imported course + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_COURSEVO} + * @response.representation.401.doc The roles of the authenticated user are not sufficient + * @param ownerUsername set the owner of the imported course to the user of this username. + * @param request The HTTP request + * @return It returns the imported course */ @POST @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Consumes({MediaType.MULTIPART_FORM_DATA}) - public Response importCourse(@Context HttpServletRequest request) { + public Response importCourse(@QueryParam("ownerUsername") String ownerUsername, @Context HttpServletRequest request) { if(!isAuthor(request)) { return Response.serverError().status(Status.UNAUTHORIZED).build(); } UserRequest ureq = RestSecurityHelper.getUserRequest(request); - Identity identity = ureq.getIdentity(); - + + Identity identity = null; + // Set the owner of the imported course to the user defined in the parameter + if (ownerUsername != null && !ownerUsername.isEmpty() && isAuthor(request)) { + identity = BaseSecurityManager.getInstance().findIdentityByName(ownerUsername); + if(identity == null) { + return Response.serverError().status(Status.BAD_REQUEST).build(); + } + } + if (identity == null) { + identity = ureq.getIdentity(); + } + MultipartReader partsReader = null; try { partsReader = new MultipartReader(request); @@ -342,7 +358,7 @@ public class CoursesWebService { CourseVO vo = null; return Response.ok(vo).build(); } - + public static boolean isCourseAccessible(ICourse course, boolean authorRightsMandatory, HttpServletRequest request) { if(authorRightsMandatory && !isAuthor(request)) { return false; @@ -357,7 +373,7 @@ public class CoursesWebService { } return false; } - + public static ICourse loadCourse(Long courseId) { try { ICourse course = CourseFactory.loadCourse(courseId); @@ -367,15 +383,15 @@ public class CoursesWebService { return null; } } - + public static ICourse importCourse(UserRequest ureq, Identity identity, File fCourseImportZIP, String displayName, String softKey, int access, boolean membersOnly) { - + log.info("REST Import course " + displayName + " START"); if(!StringHelper.containsNonWhitespace(displayName)) { displayName = "import-" + UUID.randomUUID().toString(); } - + RepositoryHandler handler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(CourseModule.getCourseTypeName()); RepositoryEntry re = handler.importResource(identity, null, displayName, null, true, Locale.ENGLISH, fCourseImportZIP, null); @@ -391,7 +407,7 @@ public class CoursesWebService { } CoreSpringFactory.getImpl(RepositoryService.class).update(re); log.info("REST Import course " + displayName + " END"); - + //publish log.info("REST Publish course " + displayName + " START"); ICourse course = CourseFactory.loadCourse(re); @@ -399,13 +415,13 @@ public class CoursesWebService { log.info("REST Publish course " + displayName + " END"); return course; } - + private static ICourse copyCourse(Long copyFrom, UserRequest ureq, Identity initialAuthor, String shortTitle, String longTitle, String displayName, String description, String softKey, int access, boolean membersOnly, String authors, String location, String externalId, String externalRef, String managedFlags, CourseConfigVO courseConfigVO) { //String learningObjectives = name + " (Example of creating a new course)"; - + OLATResourceable originalOresTrans = OresHelper.createOLATResourceableInstance(CourseModule.class, copyFrom); RepositoryEntry src = RepositoryManager.getInstance().lookupRepositoryEntry(originalOresTrans, false); if(src == null) { @@ -418,40 +434,40 @@ public class CoursesWebService { OLATResource originalOres = OLATResourceManager.getInstance().findResourceable(src.getOlatResource()); boolean isAlreadyLocked = RepositoryHandlerFactory.getInstance().getRepositoryHandler(src).isLocked(originalOres); LockResult lockResult = RepositoryHandlerFactory.getInstance().getRepositoryHandler(src).acquireLock(originalOres, ureq.getIdentity()); - + //check range of access if(access < 1 || access > RepositoryEntry.ACC_USERS_GUESTS) { access = RepositoryEntry.ACC_OWNERS; } - + if(lockResult == null || (lockResult != null && lockResult.isSuccess()) && !isAlreadyLocked) { RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class); - + //create new repo entry String name; if(description == null || description.trim().length() == 0) { description = src.getDescription(); } - + if (courseConfigVO != null && StringHelper.containsNonWhitespace(displayName)) { name = displayName; } else { name = "Copy of " + src.getDisplayname(); } - + String resName = src.getResourcename(); if (resName == null) { resName = ""; } - + OLATResource sourceResource = src.getOlatResource(); OLATResource copyResource = OLATResourceManager.getInstance().createOLATResourceInstance(sourceResource.getResourceableTypeName()); RepositoryEntry preparedEntry = repositoryService.create(initialAuthor, null, resName, name, description, copyResource, RepositoryEntry.ACC_OWNERS); - + RepositoryHandler handler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(src); preparedEntry = handler.copy(initialAuthor, src, preparedEntry); - + preparedEntry.setCanDownload(src.getCanDownload()); if(StringHelper.containsNonWhitespace(softKey)) { preparedEntry.setSoftkey(softKey); @@ -480,18 +496,18 @@ public class CoursesWebService { preparedEntry.setAllowToLeaveOption(src.getAllowToLeaveOption()); repositoryService.update(preparedEntry); - + // copy image if available RepositoryManager.getInstance().copyImage(src, preparedEntry); - + ICourse course = prepareCourse(preparedEntry,shortTitle, longTitle, courseConfigVO); RepositoryHandlerFactory.getInstance().getRepositoryHandler(src).releaseLock(lockResult); return course; } - + return null; } - + /** * Create an empty course with some defaults settings * @param initialAuthor Author @@ -503,7 +519,7 @@ public class CoursesWebService { public static ICourse createEmptyCourse(Identity initialAuthor, String shortTitle, String longTitle, CourseConfigVO courseConfigVO) { return createEmptyCourse(initialAuthor, shortTitle, longTitle, shortTitle, null, null, RepositoryEntry.ACC_OWNERS, false, null, null, null, null, null, courseConfigVO); } - + /** * Create an empty course with some settings * @param initialAuthor @@ -519,11 +535,11 @@ public class CoursesWebService { public static ICourse createEmptyCourse(Identity initialAuthor, String shortTitle, String longTitle, String reDisplayName, String description, String softKey, int access, boolean membersOnly, String authors, String location, String externalId, String externalRef, String managedFlags, CourseConfigVO courseConfigVO) { - + if(!StringHelper.containsNonWhitespace(reDisplayName)) { reDisplayName = shortTitle; } - + try { // create a repository entry RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class); @@ -550,7 +566,7 @@ public class CoursesWebService { addedEntry.setAccess(access); } addedEntry = repositoryService.update(addedEntry); - + // create an empty course CourseFactory.createCourse(addedEntry, shortTitle, longTitle, ""); @@ -559,7 +575,7 @@ public class CoursesWebService { throw new WebApplicationException(e); } } - + private static ICourse prepareCourse(RepositoryEntry addedEntry, String shortTitle, String longTitle, CourseConfigVO courseConfigVO) { // set root node title String courseShortTitle = addedEntry.getDisplayname(); @@ -570,7 +586,7 @@ public class CoursesWebService { if(StringHelper.containsNonWhitespace(longTitle)) { courseLongTitle = longTitle; } - + ICourse course = CourseFactory.openCourseEditSession(addedEntry.getOlatResource().getResourceableId()); course.getRunStructure().getRootNode().setShortTitle(Formatter.truncate(courseShortTitle, 25)); course.getRunStructure().getRootNode().setLongTitle(courseLongTitle); @@ -578,7 +594,7 @@ public class CoursesWebService { CourseNode rootNode = ((CourseEditorTreeNode) course.getEditorTreeModel().getRootNode()).getCourseNode(); rootNode.setShortTitle(Formatter.truncate(courseShortTitle, 25)); rootNode.setLongTitle(courseLongTitle); - + if(courseConfigVO != null) { CourseConfig courseConfig = course.getCourseEnvironment().getCourseConfig(); if(StringHelper.containsNonWhitespace(courseConfigVO.getSharedFolderSoftKey())) { diff --git a/src/main/java/org/olat/restapi/security/RestSecurityHelper.java b/src/main/java/org/olat/restapi/security/RestSecurityHelper.java index e347e34aaba7c09073027859fdbbe26e559a0085..4ca6e30f5e5eda429165042034fab13825603a0a 100644 --- a/src/main/java/org/olat/restapi/security/RestSecurityHelper.java +++ b/src/main/java/org/olat/restapi/security/RestSecurityHelper.java @@ -19,6 +19,11 @@ */ package org.olat.restapi.security; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; import java.util.Locale; import java.util.UUID; @@ -31,6 +36,7 @@ import org.olat.core.gui.UserRequest; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.Roles; +import org.olat.core.util.StringHelper; import org.olat.core.util.i18n.I18nModule; import org.olat.course.ICourse; import org.olat.course.groupsandrights.CourseGroupManager; @@ -145,6 +151,15 @@ public class RestSecurityHelper { } } + public static boolean isQuestionPoolManager(HttpServletRequest request) { + try { + Roles roles = getRoles(request); + return (roles.isPoolAdmin() || roles.isOLATAdmin()); + } catch (Exception e) { + return false; + } + } + public static boolean isAdmin(HttpServletRequest request) { try { Roles roles = getRoles(request); @@ -186,4 +201,49 @@ public class RestSecurityHelper { if(ureq == null) return I18nModule.getDefaultLocale(); return LocaleNegotiator.getPreferedLocale(ureq); } + + public static Date parseDate(String date, Locale locale) { + if(StringHelper.containsNonWhitespace(date)) { + if(date.indexOf('T') > 0) { + if(date.indexOf('.') > 0) { + try { + return new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.S").parse(date); + } catch (ParseException e) { + //fail silently + } + } else { + try { + return new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss").parse(date); + } catch (ParseException e) { + //fail silently + } + } + } + + //try with the locale + if(date.length() > 10) { + //probably date time + try { + DateFormat format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale); + format.setLenient(true); + return format.parse(date); + } catch (ParseException e) { + //fail silently + } + } else { + try { + DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); + format.setLenient(true); + return format.parse(date); + } catch (ParseException e) { + //fail silently + } + } + } + + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + cal.add(Calendar.MONTH, -1); + return cal.getTime(); + } } diff --git a/src/main/java/org/olat/restapi/system/NotificationsAdminWebService.java b/src/main/java/org/olat/restapi/system/NotificationsAdminWebService.java index a75227d390bddf7adb992b0972cf1883ad4fd625..d6eb54c581689233e47129daebfdc4da9844efc1 100644 --- a/src/main/java/org/olat/restapi/system/NotificationsAdminWebService.java +++ b/src/main/java/org/olat/restapi/system/NotificationsAdminWebService.java @@ -33,8 +33,8 @@ import org.olat.core.CoreSpringFactory; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.restapi.system.vo.NotificationsStatus; -import org.quartz.JobDetail; import org.quartz.JobExecutionContext; +import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; @@ -46,6 +46,8 @@ public class NotificationsAdminWebService { private static final OLog log = Tracing.createLoggerFor(NotificationsAdminWebService.class); + private final JobKey notificationsJobKey = new JobKey("org.olat.notifications.job.enabled", Scheduler.DEFAULT_GROUP); + /** * Return the status of the notifications job: running, stopped * @response.representation.200.mediaType application/xml, application/json @@ -77,10 +79,9 @@ public class NotificationsAdminWebService { private String getJobStatus() { try { Scheduler scheduler = CoreSpringFactory.getImpl(Scheduler.class); - @SuppressWarnings("unchecked") List<JobExecutionContext> jobs = scheduler.getCurrentlyExecutingJobs(); for(JobExecutionContext job:jobs) { - if("org.olat.notifications.job.enabled".equals(job.getJobDetail().getName())) { + if("org.olat.notifications.job.enabled".equals(job.getJobDetail().getKey().getName())) { return "running"; } } @@ -103,9 +104,7 @@ public class NotificationsAdminWebService { public Response setStatus(@FormParam("status") String status) { if("running".equals(status)) { try { - Scheduler scheduler = CoreSpringFactory.getImpl(Scheduler.class); - JobDetail detail = scheduler.getJobDetail("org.olat.notifications.job.enabled", Scheduler.DEFAULT_GROUP); - scheduler.triggerJob(detail.getName(), detail.getGroup()); + CoreSpringFactory.getImpl(Scheduler.class).triggerJob(notificationsJobKey); } catch (SchedulerException e) { log.error("", e); } diff --git a/src/main/java/org/olat/search/SearchModule.java b/src/main/java/org/olat/search/SearchModule.java index 2ecf210c9920cc0558353b8fbddc15a233cf6efc..02fe8febf05422309299fc8b8e0207bee2f28f63 100644 --- a/src/main/java/org/olat/search/SearchModule.java +++ b/src/main/java/org/olat/search/SearchModule.java @@ -35,6 +35,7 @@ import java.util.List; import org.olat.core.commons.modules.bc.FolderModule; import org.olat.core.configuration.AbstractSpringModule; +import org.olat.core.id.Roles; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; @@ -65,11 +66,14 @@ public class SearchModule extends AbstractSpringModule { private static final String CONF_EXCEL_FILE_ENABLED = "excelFileEnabled"; private static final String CONF_PDF_FILE_ENABLED = "pdfFileEnabled"; private static final String CONF_FILE_BLACK_LIST = "fileBlackList"; - + private static final String CONF_GUEST_ENABLED = "search.guest.enabled"; @Value("${search.service:enabled}") private String searchService; + @Value("${search.guest.enabled:false}") + private boolean guestEnabled; + @Value("${search.index.tempIndex:/tmp}") private String tempIndexPath; @Value("${search.index.tempSpellcheck:/tmp}") @@ -196,6 +200,11 @@ public class SearchModule extends AbstractSpringModule { pdfFileEnabled = "true".equals(pdfEnabled); } + //guest enabled + String guestEnabledObj = getStringPropertyValue(CONF_GUEST_ENABLED, true); + if(StringHelper.containsNonWhitespace(guestEnabledObj)) { + guestEnabled = "true".equals(guestEnabledObj); + } } @Override @@ -419,4 +428,20 @@ public class SearchModule extends AbstractSpringModule { public boolean getUseCompoundFile() { return useCompoundFile; } + + public boolean isGuestEnabled() { + return guestEnabled; + } + + public void setGuestEnabled(boolean enabled) { + guestEnabled = enabled; + setStringProperty(CONF_GUEST_ENABLED, enabled ? "true" : "false", true); + } + + public boolean isSearchAllowed(Roles roles) { + if(roles.isGuestOnly()) { + return isGuestEnabled(); + } + return true; + } } diff --git a/src/main/java/org/olat/search/SearchUserToolExtension.java b/src/main/java/org/olat/search/SearchUserToolExtension.java index 8733ac0ea63cf032887169798f05710baeb7910c..f9158a3a356f0fe06d4aaee1f84b12cbb9dee6f1 100644 --- a/src/main/java/org/olat/search/SearchUserToolExtension.java +++ b/src/main/java/org/olat/search/SearchUserToolExtension.java @@ -63,8 +63,7 @@ public class SearchUserToolExtension extends UserToolExtension { return searchOnlyHasInternalSiteMember; } - public void setSearchOnlyHasInternalSiteMember( - boolean searchOnlyHasInternalSiteMember) { + public void setSearchOnlyHasInternalSiteMember(boolean searchOnlyHasInternalSiteMember) { this.searchOnlyHasInternalSiteMember = searchOnlyHasInternalSiteMember; } diff --git a/src/main/java/org/olat/search/service/SearchServiceImpl.java b/src/main/java/org/olat/search/service/SearchServiceImpl.java index b1fe565851fdd8ba011c98ad2adb616e8079db9f..6d886142b7edfd8925b9d9fd323f1e48c6b34ba9 100644 --- a/src/main/java/org/olat/search/service/SearchServiceImpl.java +++ b/src/main/java/org/olat/search/service/SearchServiceImpl.java @@ -80,6 +80,7 @@ import org.olat.search.service.indexer.MainIndexer; import org.olat.search.service.searcher.JmsSearchProvider; import org.olat.search.service.spell.SearchSpellChecker; import org.quartz.JobDetail; +import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; @@ -90,6 +91,8 @@ import org.quartz.SchedulerException; public class SearchServiceImpl implements SearchService, GenericEventListener { private static final OLog log = Tracing.createLoggerFor(SearchServiceImpl.class); + private final JobKey indexerJobKey = new JobKey("org.olat.search.job.enabled", Scheduler.DEFAULT_GROUP); + private Index indexer; private SearchModule searchModuleConfig; private MainIndexer mainIndexer; @@ -180,13 +183,13 @@ public class SearchServiceImpl implements SearchService, GenericEventListener { if (indexer==null) throw new AssertException ("Try to call startIndexing() but indexer is null"); try { - JobDetail detail = scheduler.getJobDetail("org.olat.search.job.enabled", Scheduler.DEFAULT_GROUP); + JobDetail detail = scheduler.getJobDetail(indexerJobKey); if(detail == null) { if("disabled".equals(indexerCron)) { indexer.startFullIndex(); } } else { - scheduler.triggerJob(detail.getName(), detail.getGroup()); + scheduler.triggerJob(indexerJobKey); } log.info("startIndexing..."); } catch (SchedulerException e) { @@ -202,13 +205,13 @@ public class SearchServiceImpl implements SearchService, GenericEventListener { if (indexer==null) throw new AssertException ("Try to call stopIndexing() but indexer is null"); try { - JobDetail detail = scheduler.getJobDetail("org.olat.search.job.enabled", Scheduler.DEFAULT_GROUP); + JobDetail detail = scheduler.getJobDetail(indexerJobKey); if(detail == null) { if("disabled".equals(indexerCron)) { indexer.stopFullIndex(); } } else { - scheduler.interrupt(detail.getName(), detail.getGroup()); + scheduler.interrupt(indexerJobKey); } log.info("stopIndexing."); } catch (SchedulerException e) { @@ -243,8 +246,7 @@ public class SearchServiceImpl implements SearchService, GenericEventListener { if (startingFullIndexingAllowed()) { try { - JobDetail detail = scheduler.getJobDetail("org.olat.search.job.enabled", Scheduler.DEFAULT_GROUP); - scheduler.triggerJob(detail.getName(), detail.getGroup()); + scheduler.triggerJob(indexerJobKey); } catch (SchedulerException e) { log.error("", e); } diff --git a/src/main/java/org/olat/search/service/document/InfoMessageDocument.java b/src/main/java/org/olat/search/service/document/InfoMessageDocument.java index 32dbc0368328cf71ed56d5a4d69d8189a8b5054b..dfa51e3aa66b3a0b1e83642e212de01ef690696f 100644 --- a/src/main/java/org/olat/search/service/document/InfoMessageDocument.java +++ b/src/main/java/org/olat/search/service/document/InfoMessageDocument.java @@ -20,7 +20,7 @@ package org.olat.search.service.document; import org.apache.lucene.document.Document; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.search.model.OlatDocument; diff --git a/src/main/java/org/olat/search/service/indexer/AbstractPortfolioMapIndexer.java b/src/main/java/org/olat/search/service/indexer/AbstractPortfolioMapIndexer.java index b69fb4c6d214b1de632a90c6ea1554483781a4b7..4671049d05075a40478856db32f0eb68eba27d02 100644 --- a/src/main/java/org/olat/search/service/indexer/AbstractPortfolioMapIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/AbstractPortfolioMapIndexer.java @@ -115,7 +115,7 @@ public abstract class AbstractPortfolioMapIndexer extends AbstractHierarchicalIn public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { try { OLATResourceable ores = contextEntry.getOLATResourceable(); - return frontendManager.isMapVisible(identity, ores) && super.checkAccess(contextEntry, businessControl, identity, roles); + return !roles.isGuestOnly() && frontendManager.isMapVisible(identity, ores) && super.checkAccess(contextEntry, businessControl, identity, roles); } catch (Exception e) { logWarn("Couldn't ask if map is visible: " + contextEntry, e); return false; diff --git a/src/main/java/org/olat/search/service/indexer/group/GroupIndexer.java b/src/main/java/org/olat/search/service/indexer/group/GroupIndexer.java index 32a9750d5518d42abc08dafd82f9ea6b25612d9d..8f3e6030c02072769e27c3372cadb1a63d131ecb 100644 --- a/src/main/java/org/olat/search/service/indexer/group/GroupIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/group/GroupIndexer.java @@ -102,10 +102,14 @@ public class GroupIndexer extends AbstractHierarchicalIndexer { @Override public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + Long key = contextEntry.getOLATResourceable().getResourceableId(); BusinessGroupService bgs = CoreSpringFactory.getImpl(BusinessGroupService.class); BusinessGroup group = bgs.loadBusinessGroup(key); - if(group == null) { + if(group == null || roles.isGuestOnly()) { return false; } boolean inGroup = bgs.isIdentityInBusinessGroup(identity, group); diff --git a/src/main/java/org/olat/search/service/indexer/group/GroupInfoIndexer.java b/src/main/java/org/olat/search/service/indexer/group/GroupInfoIndexer.java index 85383e3020e9d1ece2cbdc5c5b8c2889f210b5a5..053630f8296ccb90673f07536906312f1ee68b0e 100644 --- a/src/main/java/org/olat/search/service/indexer/group/GroupInfoIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/group/GroupInfoIndexer.java @@ -23,9 +23,9 @@ import java.io.IOException; import java.util.List; import org.apache.lucene.document.Document; -import org.olat.commons.info.manager.InfoMessageFrontendManager; -import org.olat.commons.info.manager.InfoMessageManager; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageFrontendManager; +import org.olat.commons.info.InfoMessageManager; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.AssertException; import org.olat.core.logging.OLog; diff --git a/src/main/java/org/olat/search/service/indexer/identity/IdentityIndexer.java b/src/main/java/org/olat/search/service/indexer/identity/IdentityIndexer.java index 256f0f2c0be96688ed0faf0d08ddaec5a3dfee4b..4d447fa5d7393b38955636c1fd08209c4b2d32bf 100644 --- a/src/main/java/org/olat/search/service/indexer/identity/IdentityIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/identity/IdentityIndexer.java @@ -26,6 +26,9 @@ import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; import org.olat.core.util.resource.OresHelper; import org.olat.search.service.SearchResourceContext; import org.olat.search.service.indexer.AbstractHierarchicalIndexer; @@ -91,4 +94,12 @@ public class IdentityIndexer extends AbstractHierarchicalIndexer { } if (isLogDebugEnabled()) logDebug("IdentityIndexer finished with counter::" + counter); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return true; + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/CourseIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/CourseIndexer.java index 2003a877efe90d9d83186d68ceafa854c00dd46e..571efd1c87a60c316fa24f9c5a49403a697c52bf 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/CourseIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/CourseIndexer.java @@ -55,6 +55,7 @@ import org.olat.search.service.SearchResourceContext; import org.olat.search.service.indexer.AbstractHierarchicalIndexer; import org.olat.search.service.indexer.Indexer; import org.olat.search.service.indexer.OlatFullIndexer; +import org.olat.search.service.indexer.repository.course.CourseNodeEntry; import org.olat.search.service.indexer.repository.course.CourseNodeIndexer; /** @@ -164,10 +165,16 @@ public class CourseIndexer extends AbstractHierarchicalIndexer { RepositoryEntry repositoryEntry = repositoryManager.lookupRepositoryEntry(repositoryKey); if (isLogDebugEnabled()) logDebug("repositoryEntry=" + repositoryEntry ); + if(roles.isGuestOnly()) { + if(repositoryEntry.getAccess() != RepositoryEntry.ACC_USERS_GUESTS) { + return false; + } + } + Long nodeId = bcContextEntry.getOLATResourceable().getResourceableId(); if (isLogDebugEnabled()) logDebug("nodeId=" + nodeId ); - ICourse course = CourseFactory.loadCourse(repositoryEntry); + IdentityEnvironment ienv = new IdentityEnvironment(); ienv.setIdentity(identity); ienv.setRoles(roles); @@ -200,6 +207,7 @@ public class CourseIndexer extends AbstractHierarchicalIndexer { if (mayAccessWholeTreeUp) { CourseNodeIndexer courseNodeIndexer = getCourseNodeIndexer(courseNode); + bcContextEntry.setTransientState(new CourseNodeEntry(courseNode)); return courseNodeIndexer.checkAccess(bcContextEntry, businessControl, identity, roles) && super.checkAccess(bcContextEntry, businessControl, identity, roles); } else { diff --git a/src/main/java/org/olat/search/service/indexer/repository/RepositoryIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/RepositoryIndexer.java index ec79e70948f9fa2adf0cb526816cec8eff348c63..500d74fcd37fce69c6f2206c221304ec69bba8f8 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/RepositoryIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/RepositoryIndexer.java @@ -204,49 +204,50 @@ public class RepositoryIndexer extends AbstractHierarchicalIndexer { if (debug) logDebug("checkAccess for businessControl=" + businessControl + " identity=" + identity + " roles=" + roles); Long repositoryKey = contextEntry.getOLATResourceable().getResourceableId(); RepositoryEntry repositoryEntry = repositoryManager.lookupRepositoryEntry(repositoryKey); - if (repositoryEntry != null) { - boolean isOwner = repositoryManager.isOwnerOfRepositoryEntry(identity,repositoryEntry); - boolean isAllowedToLaunch = false; - if (!isOwner) { - isAllowedToLaunch = repositoryManager.isAllowedToLaunch(identity, roles, repositoryEntry); - if(isAllowedToLaunch) { - List<ContextEntry> entries = businessControl.getEntriesDownTheControls(); - if(entries.size() > 1) { - boolean hasAccess = false; - ACService acService = CoreSpringFactory.getImpl(ACService.class); - AccessResult acResult = acService.isAccessible(repositoryEntry, identity, false); - if (acResult.isAccessible()) { - hasAccess = true; - } else if (!acResult.getAvailableMethods().isEmpty()) { - for(OfferAccess offer:acResult.getAvailableMethods()) { - String type = offer.getMethod().getType(); - if (type.equals(FreeAccessHandler.METHOD_TYPE) || type.equals(PaypalAccessHandler.METHOD_TYPE)) { - hasAccess = true; - } + if (repositoryEntry == null) { + return false; + } + if(roles.isGuestOnly()) { + if(repositoryEntry.getAccess() != RepositoryEntry.ACC_USERS_GUESTS) { + return false; + } + } + + boolean isOwner = repositoryManager.isOwnerOfRepositoryEntry(identity,repositoryEntry); + boolean isAllowedToLaunch = false; + if (!isOwner) { + isAllowedToLaunch = repositoryManager.isAllowedToLaunch(identity, roles, repositoryEntry); + if(isAllowedToLaunch) { + List<ContextEntry> entries = businessControl.getEntriesDownTheControls(); + if(entries.size() > 1) { + boolean hasAccess = false; + ACService acService = CoreSpringFactory.getImpl(ACService.class); + AccessResult acResult = acService.isAccessible(repositoryEntry, identity, false); + if (acResult.isAccessible()) { + hasAccess = true; + } else if (!acResult.getAvailableMethods().isEmpty()) { + for(OfferAccess offer:acResult.getAvailableMethods()) { + String type = offer.getMethod().getType(); + if (type.equals(FreeAccessHandler.METHOD_TYPE) || type.equals(PaypalAccessHandler.METHOD_TYPE)) { + hasAccess = true; } } - isAllowedToLaunch = hasAccess; } + isAllowedToLaunch = hasAccess; } } - if (debug) logDebug("isOwner=" + isOwner + " isAllowedToLaunch=" + isAllowedToLaunch); - if (isOwner || isAllowedToLaunch) { - Indexer repositoryEntryIndexer = getRepositoryEntryIndexer(repositoryEntry); - if (debug) logDebug("repositoryEntryIndexer=" + repositoryEntryIndexer); - if (repositoryEntryIndexer != null) { - return super.checkAccess(contextEntry, businessControl, identity, roles) - && repositoryEntryIndexer.checkAccess(contextEntry, businessControl, identity, roles); - } else { - // No Indexer => no access - return false; - } - } else { - return false; + } + + if (debug) logDebug("isOwner=" + isOwner + " isAllowedToLaunch=" + isAllowedToLaunch); + if (isOwner || isAllowedToLaunch) { + Indexer repositoryEntryIndexer = getRepositoryEntryIndexer(repositoryEntry); + if (debug) logDebug("repositoryEntryIndexer=" + repositoryEntryIndexer); + if (repositoryEntryIndexer != null) { + return super.checkAccess(contextEntry, businessControl, identity, roles) + && repositoryEntryIndexer.checkAccess(contextEntry, businessControl, identity, roles); } - } else { - logWarn("Can not found RepositoryEntry with key=" + repositoryKey, null); - return false; } + return false; } /** diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/BCCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/BCCourseNodeIndexer.java index 020165e9341261b15fcebcbea2878e9858938b81..ae1853fc4adc439af88a32470d4d08a37cb5cfa2 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/BCCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/BCCourseNodeIndexer.java @@ -28,10 +28,6 @@ package org.olat.search.service.indexer.repository.course; import java.io.IOException; import org.apache.lucene.document.Document; -import org.olat.core.id.Identity; -import org.olat.core.id.Roles; -import org.olat.core.id.context.BusinessControl; -import org.olat.core.id.context.ContextEntry; import org.olat.core.util.vfs.NamedContainerImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; @@ -89,16 +85,4 @@ public class BCCourseNodeIndexer extends FolderIndexer implements CourseNodeInde public String getSupportedTypeName() { return SUPPORTED_TYPE_NAME; } - - @Override - public boolean checkAccess(BusinessControl businessControl, Identity identity, Roles roles) { - return super.checkAccess(businessControl, identity, roles); - } - - @Override - public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { - return super.checkAccess(contextEntry, businessControl, identity, roles); - } - - } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/BasicLTICourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/BasicLTICourseNodeIndexer.java index a34d8f82ef7749b4c93255421a26174bcf63b432..cb4b77fbbb111adc9e2a8fc719707c2f4bdc74e4 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/BasicLTICourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/BasicLTICourseNodeIndexer.java @@ -19,6 +19,13 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; +import org.olat.course.nodes.BasicLTICourseNode; +import org.olat.course.nodes.CourseNode; + /** * * Initial date: 20 mars 2017<br> @@ -34,5 +41,19 @@ public class BasicLTICourseNodeIndexer extends AbstractCourseNodeIndexer { public BasicLTICourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } - + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + if(contextEntry.getTransientState() instanceof CourseNodeEntry) { + CourseNode courseNode = ((CourseNodeEntry)contextEntry.getTransientState()).getCourseNode(); + if(courseNode instanceof BasicLTICourseNode) { + BasicLTICourseNode ltiNode = (BasicLTICourseNode)courseNode; + return ltiNode.isGuestAllowed(); + } + } + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/COCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/COCourseNodeIndexer.java index 3d75400c63c7a91db9bc0578f72384bc49c3f9a5..c7d7531154ca119770d1bddf25d3b19a87f7c8b0 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/COCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/COCourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class COCourseNodeIndexer extends AbstractCourseNodeIndexer { public COCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/CheckListCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/CheckListCourseNodeIndexer.java index 58f3c5d595f3a093bbd4b7114c4e5e9de5e35c47..4efa9398a119d08f28771bffef157acc73b2c795 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/CheckListCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/CheckListCourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class CheckListCourseNodeIndexer extends AbstractCourseNodeIndexer { public CheckListCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeEntry.java b/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..892c41b38b9e166b0819b339a17c672f0e46cc1c --- /dev/null +++ b/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeEntry.java @@ -0,0 +1,50 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.search.service.indexer.repository.course; + +import org.olat.core.id.context.StateEntry; +import org.olat.course.nodes.CourseNode; + +/** + * Hack to pass the course node to the sub-indexer as a state entry + * without reloading the whole course. + * + * Initial date: 12 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CourseNodeEntry implements StateEntry { + + private static final long serialVersionUID = 272047155723467386L; + private final CourseNode courseNode; + + public CourseNodeEntry(CourseNode courseNode) { + this.courseNode = courseNode; + } + + public CourseNode getCourseNode() { + return courseNode; + } + + @Override + public CourseNodeEntry clone() { + return new CourseNodeEntry(courseNode); + } +} diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeIndexer.java index 5739b590aa2e4dc852689bd7a7f81e741058e290..e6c5d99cbd060795a849098b6b41d935b328e11c 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/CourseNodeIndexer.java @@ -46,8 +46,8 @@ public interface CourseNodeIndexer extends Indexer { public default SearchResourceContext createSearchResourceContext(SearchResourceContext courseResourceContext, CourseNode node, String type) { SearchResourceContext courseNodeResourceContext = new SearchResourceContext(courseResourceContext); - courseNodeResourceContext.setBusinessControlFor(node); - courseNodeResourceContext.setDocumentType(type); + courseNodeResourceContext.setBusinessControlFor(node); + courseNodeResourceContext.setDocumentType(type); if(StringHelper.containsNonWhitespace(node.getShortTitle())) { courseNodeResourceContext.setTitle(node.getShortTitle()); } else if(StringHelper.containsNonWhitespace(node.getLongTitle())) { diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/DENCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/DENCourseNodeIndexer.java index 0cc8b2b60d8a0218974889fdc5e1f261650b8940..6df6e008b01d229990a42b5dd91ed08e075c8d1e 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/DENCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/DENCourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class DENCourseNodeIndexer extends AbstractCourseNodeIndexer { public DENCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java index 21fcae121461573aa33e384bd3f5f42667f0f055..880100a0c98b00f572624be342d31e516dc57ad6 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java @@ -158,12 +158,16 @@ public class DialogCourseNodeIndexer extends DefaultIndexer implements CourseNod @Override public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { ContextEntry ce = businessControl.popLauncherContextEntry(); + if(ce == null || ce.getOLATResourceable() == null || ce.getOLATResourceable().getResourceableId() == null) { + return true;// it's the node itself + } + OLATResourceable ores = ce.getOLATResourceable(); if(isLogDebugEnabled()) logDebug("OLATResourceable=" + ores); - if ( (ores != null) && (ores.getResourceableTypeName().startsWith("path=")) ) { + if (ores.getResourceableTypeName().startsWith("path=")) { // => it is a file element, typeName format: 'path=/test1/test2/readme.txt' return true; - } else if ((ores != null) && ores.getResourceableTypeName().equals( OresHelper.calculateTypeName(Message.class) ) ) { + } else if (ores.getResourceableTypeName().equals(OresHelper.calculateTypeName(Message.class))) { // it is message => check message access Long resourceableId = ores.getResourceableId(); Message message = ForumManager.getInstance().loadMessage(resourceableId); @@ -174,9 +178,10 @@ public class DialogCourseNodeIndexer extends DefaultIndexer implements CourseNod boolean isMessageHidden = Status.getStatus(threadtop.getStatusCode()).isHidden(); //assumes that if is owner then is moderator so it is allowed to see the hidden forum threads //TODO: (LD) fix this!!! - the contextEntry is not the right context for this check - boolean isOwner = BaseSecurityManager.getInstance().isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_ACCESS, contextEntry.getOLATResourceable()); - if(isMessageHidden && !isOwner) { - return false; + if(isMessageHidden) { + boolean isOwner = BaseSecurityManager.getInstance() + .isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_ACCESS, contextEntry.getOLATResourceable()); + return isOwner; } return true; } else { diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/ENCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/ENCourseNodeIndexer.java index 7735b2edd708d27d8a488f7057d3324a17ee4367..3eeb68e80e7a67b3979d5d4c33527153f4bb6902 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/ENCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/ENCourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class ENCourseNodeIndexer extends AbstractCourseNodeIndexer { public ENCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/FOCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/FOCourseNodeIndexer.java index 8ff69fc8bc3d55f70d773ddb139f90cf3d7fdc52..0b6526a04467ab6c2da1834bfa95dd94a4cddc9f 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/FOCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/FOCourseNodeIndexer.java @@ -86,7 +86,7 @@ public class FOCourseNodeIndexer extends ForumIndexer implements CourseNodeIndex public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { ContextEntry ce = businessControl.popLauncherContextEntry(); if(ce == null || ce.getOLATResourceable() == null || ce.getOLATResourceable().getResourceableId() == null) { - return false; + return true;//it's the node itself } Long resourceableId = ce.getOLATResourceable().getResourceableId(); @@ -120,13 +120,11 @@ public class FOCourseNodeIndexer extends ForumIndexer implements CourseNodeIndex ForumManager fom = ForumManager.getInstance(); CoursePropertyManager cpm = course.getCourseEnvironment().getCoursePropertyManager(); - Property forumKeyProperty = cpm.findCourseNodeProperty(courseNode, null, null, FOCourseNode.FORUM_KEY); + Property forumKeyProperty = cpm.findCourseNodeProperty(courseNode, null, null, FOCourseNode.FORUM_KEY); // Check if forum-property exist if (forumKeyProperty != null) { Long forumKey = forumKeyProperty.getLongValue(); Forum forum = fom.loadForum(forumKey); -// SearchResourceContext forumSearchResourceContext = new SearchResourceContext(parentResourceContext); -// forumSearchResourceContext.setBusinessControlFor(BusinessGroupMainRunController.ORES_TOOLFORUM); // TODO:chg: Must be an other Class e.g. CourseRunMainController parentResourceContext.setDocumentType(TYPE); doIndexAllMessages(parentResourceContext, forum, indexWriter ); } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/GTACourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/GTACourseNodeIndexer.java index a8cf9940c332d1e464dbdf26be83f4d8f07cf0ec..0e456ea9eb39277fbf5f527aa2d4a8f18e110d4a 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/GTACourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/GTACourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class GTACourseNodeIndexer extends AbstractCourseNodeIndexer { public GTACourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/GoToMeetingCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/GoToMeetingCourseNodeIndexer.java index 6cf0ed37040d78812b7732273b58fabe29364f56..79dd6ee20c1cb91998dd1427298cbed2f7a8c9c5 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/GoToMeetingCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/GoToMeetingCourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class GoToMeetingCourseNodeIndexer extends AbstractCourseNodeIndexer { public GoToMeetingCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/IQSURVCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/IQSURVCourseNodeIndexer.java index 36a1bc1002fd70637b421527f241e47527e0c832..87d46cebc2782f4bfae44eeeb21698a5d0f3e0e5 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/IQSURVCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/IQSURVCourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class IQSURVCourseNodeIndexer extends AbstractCourseNodeIndexer { public IQSURVCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/IQTESTCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/IQTESTCourseNodeIndexer.java index 23a3c41b0c3c732df83e94aa1f73634b5eb9759e..746100472646e519c15be8bba6cc1b377def910b 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/IQTESTCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/IQTESTCourseNodeIndexer.java @@ -19,6 +19,13 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; +import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.IQTESTCourseNode; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +41,19 @@ public class IQTESTCourseNodeIndexer extends AbstractCourseNodeIndexer { public IQTESTCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + if(contextEntry.getTransientState() instanceof CourseNodeEntry) { + CourseNode courseNode = ((CourseNodeEntry)contextEntry.getTransientState()).getCourseNode(); + if(courseNode instanceof IQTESTCourseNode) { + IQTESTCourseNode qtiNode = (IQTESTCourseNode)courseNode; + return qtiNode.isGuestAllowedForQTI21(qtiNode.getReferencedRepositoryEntry()); + } + } + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java index 911f50bb9a1a00c6057be64ab6165e11fede5cd2..5e8f9f4457c00304d11dd60898abfa7cad486a57 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java @@ -29,8 +29,8 @@ import java.io.IOException; import java.util.List; import org.apache.lucene.document.Document; -import org.olat.commons.info.manager.InfoMessageManager; -import org.olat.commons.info.model.InfoMessage; +import org.olat.commons.info.InfoMessage; +import org.olat.commons.info.InfoMessageManager; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/MSCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/MSCourseNodeIndexer.java index cfb36dab8b0345fad39bab67567492cb756e99f0..1d2d8b07e0bef072cf2cc26dd859712a98851d16 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/MSCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/MSCourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class MSCourseNodeIndexer extends AbstractCourseNodeIndexer { public MSCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/MembersCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/MembersCourseNodeIndexer.java index 3fe92d6833c5685ac2f8404a5a39b97519176449..5fd2d09312c322a78fa53b115af19987176843eb 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/MembersCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/MembersCourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class MembersCourseNodeIndexer extends AbstractCourseNodeIndexer { public MembersCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/PortfolioCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/PortfolioCourseNodeIndexer.java index 490ce2d521f8db287285495b00a2f5704e7e366b..52392eb09b94da8f97b577286d894e1273768fc4 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/PortfolioCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/PortfolioCourseNodeIndexer.java @@ -22,6 +22,10 @@ package org.olat.search.service.indexer.repository.course; import java.io.IOException; import org.apache.lucene.document.Document; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; import org.olat.course.ICourse; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.PortfolioCourseNode; @@ -100,4 +104,12 @@ public class PortfolioCourseNodeIndexer extends DefaultIndexer implements Course } } } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } \ No newline at end of file diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/ProjectBrokerCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/ProjectBrokerCourseNodeIndexer.java index 920ed0b45baf86b872ca60f002f77488e68c0cf7..c1d789d8381d8ab7beff49c270dee3510c348984 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/ProjectBrokerCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/ProjectBrokerCourseNodeIndexer.java @@ -30,6 +30,10 @@ import java.util.List; import org.apache.lucene.document.Document; import org.olat.core.CoreSpringFactory; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.course.ICourse; @@ -79,4 +83,12 @@ public class ProjectBrokerCourseNodeIndexer extends AbstractHierarchicalIndexer public String getSupportedTypeName() { return SUPPORTED_TYPE_NAME; } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/TACourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/TACourseNodeIndexer.java index 6fbe0c0d21fa12082282048297888bc9e27432ed..9eb185dab43ef7eeed619d81af3fd3b3115e908e 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/TACourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/TACourseNodeIndexer.java @@ -30,6 +30,10 @@ import java.io.IOException; import org.apache.lucene.document.Document; import org.olat.core.commons.modules.bc.FolderConfig; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; import org.olat.core.util.vfs.LocalFolderImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.course.ICourse; @@ -96,4 +100,13 @@ public class TACourseNodeIndexer extends FolderIndexer implements CourseNodeInde public String getSupportedTypeName() { return SUPPORTED_TYPE_NAME; } + + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/ViteroCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/ViteroCourseNodeIndexer.java index 433644d3cc6ac572d77b221174c5c77b117c25c7..63d1a145fe720d5be294971c2ccd60b57ab514cb 100644 --- a/src/main/java/org/olat/search/service/indexer/repository/course/ViteroCourseNodeIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/repository/course/ViteroCourseNodeIndexer.java @@ -19,6 +19,11 @@ */ package org.olat.search.service.indexer.repository.course; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControl; +import org.olat.core.id.context.ContextEntry; + /** * * Initial date: 20 mars 2017<br> @@ -34,4 +39,12 @@ public class ViteroCourseNodeIndexer extends AbstractCourseNodeIndexer { public ViteroCourseNodeIndexer() { super(TYPE, SUPPORTED_TYPE_NAME); } + + @Override + public boolean checkAccess(ContextEntry contextEntry, BusinessControl businessControl, Identity identity, Roles roles) { + if(roles.isGuestOnly()) { + return false; + } + return super.checkAccess(contextEntry, businessControl, identity, roles); + } } diff --git a/src/main/java/org/olat/search/ui/ResultsController.java b/src/main/java/org/olat/search/ui/ResultsController.java index 31e05d3976da9ede3d15af2d5614d19131854f98..2311601ccbf59c5f36fb6c2f17d827fdabff3720 100644 --- a/src/main/java/org/olat/search/ui/ResultsController.java +++ b/src/main/java/org/olat/search/ui/ResultsController.java @@ -52,7 +52,7 @@ import org.olat.search.model.ResultDocument; * @author srosse, stephane.rosse@frentix.com */ public class ResultsController extends FormBasicController { - private FormLink previousTopLink, nextTopLink, previousLink, nextLink; + private FormLink previousLink, nextLink; private FormLink highlightLink, dishighlightLink; private int currentPage; @@ -77,10 +77,8 @@ public class ResultsController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { previousLink = uifactory.addFormLink("previous.page", formLayout); - previousTopLink = uifactory.addFormLink("previous.top.page", null, "previous.page", formLayout, Link.LINK); nextLink = uifactory.addFormLink("next.page", formLayout); - nextTopLink = uifactory.addFormLink("next.top.page", null, "next.page", formLayout, Link.LINK); - + highlightLink = uifactory.addFormLink("highlight.page", "enable.highlighting", "enable.highlighting", formLayout, Link.LINK); dishighlightLink = uifactory.addFormLink("dishighlight.page", "disable.highlighting", "disable.highlighting", formLayout, Link.LINK); flc.contextPut("highlight", true); @@ -158,9 +156,7 @@ public class ResultsController extends FormBasicController { flc.contextPut("currentPage", currentPage + 1); previousLink.setEnabled(currentPage != 0); - previousTopLink.setEnabled(currentPage != 0); nextLink.setEnabled(currentPage != getMaxPage()); - nextTopLink.setEnabled(currentPage != getMaxPage()); String [] args = {Integer.toString(getStartResult()), Integer.toString(getEndResult()), Integer.toString(getNumOfResults())}; flc.contextPut("resultTitle", getTranslator().translate("search.result.title",args)); @@ -186,9 +182,9 @@ public class ResultsController extends FormBasicController { highlight = false; flc.contextPut("highlight", highlight); reload(ureq); - } else if (source == previousLink || source == previousTopLink) { + } else if (source == previousLink) { setSearchResults(ureq, Math.max(0, --currentPage)); - } else if (source == nextLink || source == nextTopLink) { + } else if (source == nextLink) { if(documents.size() <= (currentPage + 1) * RESULT_PER_PAGE) { SearchEvent e = new SearchEvent(getLastLucenePosition() + 1, RESULT_PER_PAGE); fireEvent(ureq, e); diff --git a/src/main/java/org/olat/search/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/search/ui/_i18n/LocalStrings_en.properties index 28a25d0024e5d5ee943f8d258aa77fa2b4aaa8c0..57020cbafc9b102368147ea85ab8fe0e4d10d6d6 100644 --- a/src/main/java/org/olat/search/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/search/ui/_i18n/LocalStrings_en.properties @@ -1,5 +1,8 @@ -#Thu Aug 15 19:28:39 CEST 2013 +#Mon Jul 17 21:16:44 CEST 2017 +EPSite=Portfolio +HomeSite=Home LibrarySite=Library +Portfolio=Portfolio all.search.result.title=All {0} results area.blogs=Blog/Podcast area.courses=OLAT course @@ -10,9 +13,6 @@ area.users=User area.wikis=Wiki disable.highlighting=Without search keys drop.down.no.selection=No selection -EPSite=Portfolio -HomeSite=Home -Portfolio=Portfolio enable.highlighting=With search keys error.resource.could.not.found=Selected resource not found. It either does not exist anymore or its access rights have been modified in the meantime. form.search.label.area=Area @@ -65,20 +65,21 @@ toolforum=Forums type.course.node=Course element type.course.node.bc=Course element, folder type.course.node.blog=Course element, blog -type.course.node.cp=Course element, CP learning content +type.course.node.cal=Course element, calendar type.course.node.checklist=Course element, checklist type.course.node.co=Course element, E-mail +type.course.node.cp=Course element, CP learning content type.course.node.den=Course element, assignment of dates type.course.node.dialog.file=Course element, file dialog (file) type.course.node.dialog.forum.message=Course element, file dialog (discussion) type.course.node.en=Course element, enrolment type.course.node.ep=Course element, portfolio task -type.course.node.iqself=Course element, self-test -type.course.node.iqsurv=Course element, survey -type.course.node.iqtest=Course element, test type.course.node.forum.message=Course element, forum type.course.node.gotomeeting=Course element, GoToMeeting type.course.node.gta=Course element, task +type.course.node.iqself=Course element, self-test +type.course.node.iqsurv=Course element, survey +type.course.node.iqtest=Course element, test type.course.node.ll=Course element, link list type.course.node.lti=Course element, LTI page type.course.node.membersCourseNodeConf=Course element, participant list diff --git a/src/main/java/org/olat/shibboleth/ShibbolethDispatcher.java b/src/main/java/org/olat/shibboleth/ShibbolethDispatcher.java index 4f07968e8cdea31cba85ba7850696b28aa2e23d7..fcf07e40c8fe4043b850ad1266368fa47cf27999 100644 --- a/src/main/java/org/olat/shibboleth/ShibbolethDispatcher.java +++ b/src/main/java/org/olat/shibboleth/ShibbolethDispatcher.java @@ -31,7 +31,6 @@ import java.net.URLDecoder; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; -import java.util.Set; import java.util.StringTokenizer; import javax.servlet.http.HttpServletRequest; @@ -41,6 +40,7 @@ import org.olat.admin.user.delete.service.UserDeletionManager; import org.olat.basesecurity.AuthHelper; import org.olat.basesecurity.Authentication; import org.olat.basesecurity.BaseSecurity; +import org.olat.core.CoreSpringFactory; import org.olat.core.dispatcher.Dispatcher; import org.olat.core.dispatcher.DispatcherModule; import org.olat.core.gui.UserRequest; @@ -51,8 +51,6 @@ import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.media.RedirectMediaResource; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; -import org.olat.core.id.User; -import org.olat.core.id.UserConstants; import org.olat.core.logging.AssertException; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.logging.OLATSecurityException; @@ -64,9 +62,8 @@ import org.olat.core.util.Util; import org.olat.core.util.WebappHelper; import org.olat.core.util.i18n.I18nModule; import org.olat.restapi.security.RestSecurityBean; -import org.olat.shibboleth.util.ShibbolethAttribute; -import org.olat.shibboleth.util.ShibbolethHelper; -import org.olat.user.UserManager; +import org.olat.shibboleth.manager.ShibbolethAttributes; +import org.springframework.beans.factory.annotation.Autowired; /** * Initial Date: 17.07.2004 @@ -74,22 +71,24 @@ import org.olat.user.UserManager; * @author Mike Stock */ public class ShibbolethDispatcher implements Dispatcher{ - + private static final OLog log = Tracing.createLoggerFor(ShibbolethDispatcher.class); /** Provider identifier */ public static final String PROVIDER_SHIB = "Shib"; /** Identifies requests for the ShibbolethDispatcher */ public static final String PATH_SHIBBOLETH = "/shib/"; - + private Translator translator; private boolean mobile = false; private BaseSecurity securityManager; private ShibbolethModule shibbolethModule; private RestSecurityBean restSecurityBean; private UserDeletionManager userDeletionManager; - - + + @Autowired + private ShibbolethManager shibbolethManager; + /** * [used by Spring] * @param mobile @@ -97,7 +96,7 @@ public class ShibbolethDispatcher implements Dispatcher{ public void setMobile(boolean mobile) { this.mobile = mobile; } - + /** * [used by Spring] * @param shibbolethModule @@ -105,7 +104,7 @@ public class ShibbolethDispatcher implements Dispatcher{ public void setShibbolethModule(ShibbolethModule shibbolethModule) { this.shibbolethModule = shibbolethModule; } - + /** * [used by Spring] * @param restSecurityBean @@ -113,7 +112,7 @@ public class ShibbolethDispatcher implements Dispatcher{ public void setRestSecurityBean(RestSecurityBean restSecurityBean) { this.restSecurityBean = restSecurityBean; } - + /** * [used by Spring] * @param securityManager @@ -133,7 +132,7 @@ public class ShibbolethDispatcher implements Dispatcher{ /** * Main method called by OpenOLATServlet. * This processess all shibboleth requests. - * + * * @param req * @param resp * @param uriPrefix @@ -152,21 +151,25 @@ public class ShibbolethDispatcher implements Dispatcher{ throw new AssertException("UTF-8 encoding not supported!!!!"); } String uriPrefix = DispatcherModule.getLegacyUriPrefix(req); - uri = uri.substring(uriPrefix.length()); // guaranteed to exist by DispatcherAction - + uri = uri.substring(uriPrefix.length()); // guaranteed to exist by DispatcherAction + Map<String, String> attributesMap = getShibbolethAttributesFromRequest(req); - String uniqueID = getUniqueIdentifierFromRequest(req, resp, attributesMap); - if(uniqueID == null) { + ShibbolethAttributes shibbolethAttriutes = CoreSpringFactory.getImpl(ShibbolethAttributes.class); + shibbolethAttriutes.init(attributesMap); + String uid = shibbolethAttriutes.getUID(); + if(uid == null) { + handleException(new ShibbolethException(ShibbolethException.UNIQUE_ID_NOT_FOUND,"Unable to get unique identifier for subject. Make sure you are listed in the metadata.xml file and your resources your are trying to access are available and your are allowed to see them. (Resourceregistry). "), + req, resp, translator); return; } - - if(!authorization(req, resp, attributesMap)) { + + if(!authorization(req, resp, shibbolethAttriutes)) { return; } UserRequest ureq = null; try{ - //upon creation URL is checked for + //upon creation URL is checked for ureq = new UserRequestImpl(uriPrefix, req, resp); } catch(NumberFormatException nfe) { //MODE could not be decoded @@ -181,11 +184,11 @@ public class ShibbolethDispatcher implements Dispatcher{ DispatcherModule.sendBadRequest(req.getPathInfo(), resp); return; } - - Authentication auth = securityManager.findAuthenticationByAuthusername(uniqueID, PROVIDER_SHIB); + + Authentication auth = securityManager.findAuthenticationByAuthusername(uid, PROVIDER_SHIB); if (auth == null) { // no matching authentication... - ShibbolethRegistrationController.putShibAttributes(req, attributesMap); - ShibbolethRegistrationController.putShibUniqueID(req, uniqueID); + ShibbolethRegistrationController.putShibAttributes(req, shibbolethAttriutes); + ShibbolethRegistrationController.putShibUniqueID(req, uid); redirectToShibbolethRegistration(resp); return; } @@ -202,37 +205,17 @@ public class ShibbolethDispatcher implements Dispatcher{ } return; } - - // successfull login - userDeletionManager.setIdentityAsActiv(ureq.getIdentity()); - ureq.getUserSession().getIdentityEnvironment().addAttributes( - shibbolethModule.getAttributeTranslator().translateAttributesMap(attributesMap)); - // update user attributes + // Successful login Identity authenticationedIdentity = ureq.getIdentity(); - User user = authenticationedIdentity.getUser(); - String s = attributesMap.get(shibbolethModule.getFirstName()); - if (s != null) user.setProperty(UserConstants.FIRSTNAME, s); - s = attributesMap.get(shibbolethModule.getLastName()); - if (s != null) user.setProperty(UserConstants.LASTNAME, s); - s = attributesMap.get(shibbolethModule.getInstitutionalName()); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALNAME, s); - s = ShibbolethHelper.getFirstValueOf(shibbolethModule.getInstitutionalEMail(), attributesMap); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALEMAIL, s); - s = attributesMap.get(shibbolethModule.getInstitutionalUserIdentifier()); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, s); - // Optional organization unit property - String orgUnitIdent = shibbolethModule.getOrgUnit(); - if(orgUnitIdent != null) { - s = ShibbolethHelper.getFirstValueOf(orgUnitIdent, attributesMap); - if (s != null) user.setProperty(UserConstants.ORGUNIT, s); - } - UserManager.getInstance().updateUser(user); + userDeletionManager.setIdentityAsActiv(authenticationedIdentity); + shibbolethManager.syncUser(authenticationedIdentity, shibbolethAttriutes); + ureq.getUserSession().getIdentityEnvironment().addAttributes( + shibbolethModule.getAttributeTranslator().translateAttributesMap(shibbolethAttriutes.toMap())); - if(mobile) { String token = restSecurityBean.generateToken(ureq.getIdentity(), ureq.getHttpReq().getSession(true)); - + try { resp.sendRedirect(WebappHelper.getServletContextPath() + "/mobile?x-olat-token=" + token + "&username=" + ureq.getIdentity().getName()); } catch (IOException e) { @@ -249,69 +232,30 @@ public class ShibbolethDispatcher implements Dispatcher{ } } - private String getUniqueIdentifierFromRequest(HttpServletRequest req, HttpServletResponse resp, Map<String, String> attributesMap) { - - String uniqueID = attributesMap.get(shibbolethModule.getDefaultUIDAttribute()); - if (uniqueID == null) { - handleException(new ShibbolethException(ShibbolethException.UNIQUE_ID_NOT_FOUND,"Unable to get unique identifier for subject. Make sure you are listed in the metadata.xml file and your resources your are trying to access are available and your are allowed to see them. (Resourceregistry). "), - req, resp, translator); - return null; - } else if (!checkAttributes(attributesMap)) { - handleException(new ShibbolethException(ShibbolethException.INSUFFICIENT_ATTRIBUTES,"Insufficient shibboleth attributes!"), - req, resp, translator); - return null; - } - return uniqueID; - } - private Map<String, String> getShibbolethAttributesFromRequest(HttpServletRequest req) { - Set<String> translateableAttributes = shibbolethModule.getAttributeTranslator().getTranslateableAttributes(); - Map<String, String> attributesMap = new HashMap<String, String>(); + Map<String, String> attributesMap = new HashMap<>(); Enumeration<String> headerEnum = req.getHeaderNames(); while(headerEnum.hasMoreElements()) { - String attribute = headerEnum.nextElement(); - String attributeValue = req.getHeader(attribute); - - ShibbolethAttribute shibbolethAttribute = ShibbolethAttribute.createFromUserRequestValue(attribute, attributeValue); - - boolean validAndTranslateableAttribute = shibbolethAttribute.isValid() && translateableAttributes.contains(shibbolethAttribute.getName()); - if(validAndTranslateableAttribute){ - attributesMap.put(shibbolethAttribute.getName(),shibbolethAttribute.getValueString()); + String attributeName = headerEnum.nextElement(); + String attributeValue = req.getHeader(attributeName); + + try { + attributeValue = new String(attributeValue.getBytes("ISO-8859-1"), "UTF-8"); + if (shibbolethModule.getShibbolethAttributeNames().contains(attributeName)) { + attributesMap.put(attributeName, attributeValue); + } + } catch (UnsupportedEncodingException e) { + //bad luck + throw new AssertException("ISO-8859-1, or UTF-8 Encoding not supported",e); } } - + if(log.isDebug()){ log.debug("Shib attribute Map: \n\n"+attributesMap.toString()+"\n\n"); } - + return attributesMap; } - - /** - * Check if all required attributes are here. - * @param attributesMap - * @return true if all required attributes are present, false otherwise. - */ - private boolean checkAttributes(Map<String, String> attributesMap) { - if(attributesMap.keySet().size()==1) { - return false; - } - try { - String lastname = attributesMap.get(shibbolethModule.getLastName()); - String firstname = attributesMap.get(shibbolethModule.getFirstName()); - String email = ShibbolethHelper.getFirstValueOf(shibbolethModule.getEMail(), attributesMap); - String institutionalEMail = ShibbolethHelper.getFirstValueOf(shibbolethModule.getInstitutionalEMail(), attributesMap); - String institutionalName = attributesMap.get(shibbolethModule.getInstitutionalName()); - //String institutionalUserIdentifier = userMapping.getInstitutionalUserIdentifier(); - if(lastname!=null && !lastname.equals("") && firstname!=null && !firstname.equals("") && email!=null && !email.equals("") && - institutionalEMail!=null && !institutionalEMail.equals("") && institutionalName!=null && !institutionalName.equals("")) { - return true; - } - } catch (IllegalArgumentException e) { - log.error("Error when reading Shib attributes. Either home org not allowed to connect to this OO instance or user has missing attributes."); - } - return false; - } private final void redirectToShibbolethRegistration(HttpServletResponse response) { try { @@ -320,54 +264,46 @@ public class ShibbolethDispatcher implements Dispatcher{ log.error("Redirect failed: url=" + WebappHelper.getServletContextPath() + DispatcherModule.getPathDefault(),e); } } - - private boolean authorization(HttpServletRequest req, HttpServletResponse resp, Map<String,String> attributesMap) { + + private boolean authorization(HttpServletRequest req, HttpServletResponse resp, ShibbolethAttributes shibbolethAttibutes) { boolean authorized = false; if(shibbolethModule.isAccessControlByAttributes()) { if(StringHelper.containsNonWhitespace(shibbolethModule.getAttribute1()) && StringHelper.containsNonWhitespace(shibbolethModule.getAttribute1Values())) { - authorized |= authorization(shibbolethModule.getAttribute1(), shibbolethModule.getAttribute1Values(), attributesMap); + authorized |= authorization(shibbolethModule.getAttribute1(), shibbolethModule.getAttribute1Values(), shibbolethAttibutes); } if(StringHelper.containsNonWhitespace(shibbolethModule.getAttribute2()) && StringHelper.containsNonWhitespace(shibbolethModule.getAttribute2Values())) { - authorized |= authorization(shibbolethModule.getAttribute2(), shibbolethModule.getAttribute2Values(), attributesMap); + authorized |= authorization(shibbolethModule.getAttribute2(), shibbolethModule.getAttribute2Values(), shibbolethAttibutes); } } else { authorized = true; } - + if(!authorized) { UserRequest ureq = new UserRequestImpl(ShibbolethDispatcher.PATH_SHIBBOLETH, req, resp); - String userMsg = translator.translate("error.shibboleth.not.authorized"); + String userMsg = translator.translate("error.shibboleth.not.authorized"); ChiefController msgcc = MessageWindowController.createMessageChiefController(ureq, null, userMsg, null); msgcc.getWindow().dispatchRequest(ureq, true); } return authorized; } - - private boolean authorization(String attribute, String allowedValues, Map<String,String> attributesMap) { - String val = attributesMap.get(attribute); + + private boolean authorization(String attributeName, String allowedValues, ShibbolethAttributes shibbolethAttributes) { + String val = shibbolethAttributes.getValueForAttributeName(attributeName); if(StringHelper.containsNonWhitespace(val)) { val = val.trim(); for(StringTokenizer tokenizer = new StringTokenizer(allowedValues, "\n\r,;", false); tokenizer.hasMoreTokens(); ) { String allowedValue = tokenizer.nextToken().trim(); if(val.equalsIgnoreCase(allowedValue)) { return true; - } - // Could be multi-field attribute. Check for semi-colon delimited encodings - String[] multiValues = val.split(";"); - for (String singleValue : multiValues) { - singleValue = singleValue.trim(); - if(singleValue.equalsIgnoreCase(allowedValue)) { - return true; - } } - } + } } return false; } /** * It first tries to catch the frequent SAMLExceptions and to ask the user to login again. - * It basically lets the user to login again without getting a RedScreen if one of the most + * It basically lets the user to login again without getting a RedScreen if one of the most * frequent shibboleth error occurs. Else a RedScreen is the last option. * @param e * @param req @@ -375,19 +311,18 @@ public class ShibbolethDispatcher implements Dispatcher{ */ private void handleException(Throwable e, HttpServletRequest req, HttpServletResponse resp, Translator translator) { UserRequest ureq = new UserRequestImpl(ShibbolethDispatcher.PATH_SHIBBOLETH, req, resp); - if(e instanceof ShibbolethException) { + if(e instanceof ShibbolethException) { String userMsg = ""; int errorCode = ((ShibbolethException)e).getErrorCode(); switch (errorCode) { - case ShibbolethException.GENERAL_SAML_ERROR: userMsg = translator.translate("error.shibboleth.generic"); break; + case ShibbolethException.GENERAL_SAML_ERROR: userMsg = translator.translate("error.shibboleth.generic"); break; case ShibbolethException.UNIQUE_ID_NOT_FOUND: userMsg = translator.translate("error.unqueid.notfound"); break; - case ShibbolethException.INSUFFICIENT_ATTRIBUTES: userMsg = translator.translate("error.insufficieant.attributes"); break; default: userMsg = translator.translate("error.shibboleth.generic"); break; - } + } showMessage(ureq,"org.opensaml.SAMLException: " + e.getMessage(), e, userMsg, ((ShibbolethException)e).getContactPersonEmail()); - return; + return; } else { - try { + try { ChiefController msgcc = MsgFactory.createMessageChiefController(ureq, new OLATRuntimeException("Error processing Shibboleth request: " + e.getMessage(), e), false); msgcc.getWindow().dispatchRequest(ureq, true); @@ -396,13 +331,13 @@ public class ShibbolethDispatcher implements Dispatcher{ } } } - + /** - * + * * @param ureq * @param exceptionLogMessage will be recorded into the log file * @param cause - * @param userMessage gets shown to the user + * @param userMessage gets shown to the user * @param supportEmail if any available, else null */ private void showMessage(UserRequest ureq, String exceptionLogMessage, Throwable cause, String userMessage, String supportEmail) { diff --git a/src/main/java/org/olat/shibboleth/ShibbolethException.java b/src/main/java/org/olat/shibboleth/ShibbolethException.java index 8f65951b474027b2a139694e110cebe1e6e166a2..3a1afa418b14d18f359481331ca4b58e99c955d7 100644 --- a/src/main/java/org/olat/shibboleth/ShibbolethException.java +++ b/src/main/java/org/olat/shibboleth/ShibbolethException.java @@ -27,7 +27,7 @@ package org.olat.shibboleth; /** * Description:<br> * TODO: Lavinia Dumitrescu Class Description for ShibbolethException - * + * * <P> * Initial Date: 31.10.2007 <br> * @author Lavinia Dumitrescu @@ -36,23 +36,22 @@ public class ShibbolethException extends Exception { private static final long serialVersionUID = 9055605164344300611L; //error codes - public static final int GENERAL_SAML_ERROR = 0; + public static final int GENERAL_SAML_ERROR = 0; public static final int UNIQUE_ID_NOT_FOUND = 1; - public static final int INSUFFICIENT_ATTRIBUTES = 2; - + private int errorCode; private String contactPersonEmail; - + public ShibbolethException(int errorCode, String msg) { super(msg); this.errorCode = errorCode; } - + public ShibbolethException(int errorCode, Throwable throwable) { super(throwable.getMessage()); this.errorCode = errorCode; } - + public ShibbolethException(int errorCode, String contactPersonEmail, Throwable throwable) { this(errorCode, throwable); this.contactPersonEmail = contactPersonEmail; diff --git a/src/main/java/org/olat/shibboleth/ShibbolethManager.java b/src/main/java/org/olat/shibboleth/ShibbolethManager.java new file mode 100644 index 0000000000000000000000000000000000000000..66b396526119f506c1a1542f43793864517c0de1 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/ShibbolethManager.java @@ -0,0 +1,60 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth; + +import org.olat.core.id.Identity; +import org.olat.shibboleth.manager.ShibbolethAttributes; + +/** + * This manager handles the interaction between Shibboleth and OpenOLAT. + * + * Initial date: 19.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface ShibbolethManager { + + /** + * Create and persist an OpenOLAT user and synchronize the Shibboleth user + * attribute with the OpenOLAT user properties. The new user is added with + * the role user. The new user is added to the role authors if this function + * is enabled. If the auto access control is enabled the access orders are + * created. Required Attributes have to be checked before this method. + * + * @param username + * @param shibbolethUniqueID + * @param language + * @param shibbolethAttributes + * @return + */ + public Identity createUser(String username, String shibbolethUniqueID, String language, ShibbolethAttributes shibbolethAttributes); + + /** + * Synchronize the Shibboleth user attributes to the OpenOLAT user + * properties and persist the user in the database. The new user is added to + * the role authors if this function is enabled. If the auto access control + * is enabled the access orders are created. + * + * @param identity + * @param shibbolethAttributes + */ + public void syncUser(Identity identity, ShibbolethAttributes shibbolethAttributes); + +} diff --git a/src/main/java/org/olat/shibboleth/ShibbolethModule.java b/src/main/java/org/olat/shibboleth/ShibbolethModule.java index bce4593435b188be5b6010cac0cf556afc5452a6..b773358efb0694b526cd2ee22d86e90b94374afc 100644 --- a/src/main/java/org/olat/shibboleth/ShibbolethModule.java +++ b/src/main/java/org/olat/shibboleth/ShibbolethModule.java @@ -26,15 +26,26 @@ package org.olat.shibboleth; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; import org.olat.core.configuration.AbstractSpringModule; import org.olat.core.configuration.ConfigOnOff; +import org.olat.core.id.UserConstants; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; import org.olat.shibboleth.util.AttributeTranslator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -45,40 +56,28 @@ import org.springframework.stereotype.Service; * Initial Date: 16.07.2004 * * @author Mike Stock - * - * Comment: - * */ @Service("shibbolethModule") public class ShibbolethModule extends AbstractSpringModule implements ConfigOnOff { - + private static final OLog log = Tracing.createLoggerFor(ShibbolethModule.class); - + + private static final String AUTHOR_CONTAINS_SPLIT_VALUE = ","; + /** * Path identifier for shibboleth registration workflows. */ - static final String PATH_REGISTER_SHIBBOLETH = "shibregister"; - - private static final String CONF_OLATUSERMAPPING_FIRSTNAME = "FirstName"; - private static final String CONF_OLATUSERMAPPING_LASTNAME = "LastName"; - private static final String CONF_OLATUSERMAPPING_EMAIL = "EMail"; - public static final String CONF_OLATUSERMAPPING_INSTITUTIONALNAME = "InstitutionalName"; - private static final String CONF_OLATUSERMAPPING_INSTITUTIONALEMAIL = "InstitutionalEMail"; - private static final String CONF_OLATUSERMAPPING_INSTITUTIONALUSERIDENTIFIER = "InstitutionalUserIdentifier"; - private static final String CONF_OLATUSERMAPPING_PREFERED_LANGUAGE = "PreferedLanguage"; - private static final String CONF_OLATUSERMAPPING_ORGUNIT = "OrgUnit"; - + static final String PATH_REGISTER_SHIBBOLETH = "shibregister"; + + private static final List<String> MANDATORY_USER_PROPERTIES + = java.util.Arrays.asList(UserConstants.EMAIL, UserConstants.FIRSTNAME, UserConstants.LASTNAME); + @Value("${shibboleth.enable}") private boolean enableShibbolethLogins = false; - - @Autowired + + @Resource(name="${shibboleth.attribute.translator}") private AttributeTranslator attributeTranslator; - @Value("${language.enable}") - private boolean useLanguageInReq = false; - @Value("${language.param:en}") - private String languageParamName; - @Autowired @Qualifier("shibbolethOperators") private ArrayList<String> operators; @@ -87,13 +86,25 @@ public class ShibbolethModule extends AbstractSpringModule implements ConfigOnOf @Value("${shibboleth.template.login.default:default_shibbolethlogin}") private String loginTemplateDefault; - public final String MULTIVALUE_SEPARATOR = ";"; - - @Value("${shibboleth.defaultUID:Shib-SwissEP-UniqueID}") - private String defaultUIDAttribute; + public static final String MULTIVALUE_SEPARATOR = ";"; + + @Value("${shibboleth.preferred.language.shib}") + private String preferredLanguageAttribute; + @Value("${shibboleth.uid.shib}") + private String uidAttributeName; @Autowired @Qualifier("shibbolethUserMapping") private HashMap<String, String> userMapping; + @Autowired @Qualifier("shibbolethAttributeHandler") + private HashMap<String, String> attributeHandler; + @Autowired @Qualifier("shibbolethDeleteIfNull") + private HashMap<String, Boolean> deleteIfNull; + @Value("${shibboleth.role.mapping.author.enable:false}") + private boolean authorMappingEnabled; + @Value("${shibboleth.role.mapping.author.shib}") + private String authorMappingAttributeName; + @Value("${shibboleth.role.mapping.author.contains}") + private String authorMappingContains; @Value("${shibboleth.ac.byAttributes:false}") private boolean accessControlByAttributes; @Value("${shibboleth.ac.attribute1:#{null}}") @@ -104,159 +115,130 @@ public class ShibbolethModule extends AbstractSpringModule implements ConfigOnOf private String attribute2; @Value("${shibboleth.ac.attribute2Values:#{null}}") private String attribute2Values; - + + @Value("${method.auto.shib.identifiers}") + private String acAutoIdentifiersString; + private Set<IdentifierKey> acAutoIdentifiers; + @Value("${method.auto.shib.shib}") + private String acAutoAttributeName; + @Value("${method.auto.shib.splitter}") + private String acAutoSplitter; + @Autowired public ShibbolethModule(CoordinatorManager coordinatorManager) { super(coordinatorManager); } - + @Override public void init() { if (enableShibbolethLogins) { log.info("Shibboleth logins enabled."); - - if(useLanguageInReq) { - log.info("Language code is sent as parameter in the AAI request with lang: "+languageParamName); - } else { - log.info("Language code is not sent with AAI request."); - } } else { log.info("Shibboleth logins disabled."); } - + //module enabled/disabled String accessControlByAttributesObj = getStringPropertyValue("accessControlByAttributes", true); if(StringHelper.containsNonWhitespace(accessControlByAttributesObj)) { accessControlByAttributes = "true".equals(accessControlByAttributesObj); } - + + ensureDefaultsForMandatoryUserProperties(); + String attribute1Obj = getStringPropertyValue("attribute1", true); if(StringHelper.containsNonWhitespace(attribute1Obj)) { attribute1 = attribute1Obj; } - + String attribute1ValuesObj = getStringPropertyValue("attribute1Values", true); if(StringHelper.containsNonWhitespace(attribute1ValuesObj)) { attribute1Values = attribute1ValuesObj; } - + String attribute2Obj = getStringPropertyValue("attribute2", true); if(StringHelper.containsNonWhitespace(attribute2Obj)) { attribute2 = attribute2Obj; } - + String attribute2ValuesObj = getStringPropertyValue("attribute2Values", true); if(StringHelper.containsNonWhitespace(attribute2ValuesObj)) { attribute2Values = attribute2ValuesObj; } + + acAutoIdentifiers = parseAcIdentifiers(acAutoIdentifiersString); } - + + private Set<IdentifierKey> parseAcIdentifiers(String raw) { + Set<IdentifierKey> keys = new HashSet<>(); + List<String> keyStrings = Arrays.asList(raw.split(AUTHOR_CONTAINS_SPLIT_VALUE)); + for (String keyString : keyStrings) { + try { + keys.add(IdentifierKey.valueOf(keyString)); + } catch (Exception e) { + log.warn("The value '" + keyString + "' for the property 'shib.ac.auto.identifiers' is not valid."); + } + } + return keys; + } + @Override protected void initFromChangedProperties() { init(); } - - /** - * @return True if shibboleth logins are allowed. - */ - public boolean isEnableShibbolethLogins() { - return enableShibbolethLogins; - } - - @Override - public boolean isEnabled() { - return isEnableShibbolethLogins(); - } - /** - * @return true if the language should be sent in the aai request - */ - public boolean useLanguageInReq() { - return useLanguageInReq; + private void ensureDefaultsForMandatoryUserProperties() { + ensureMandatoryPropertesAreInUserMapping(); + ensureMandatoryPropertiesAreNeverDeleted(); } - /** - * @return the get request parameter name to be used sending the language code. - */ - public String getLanguageParamName() { - return languageParamName; + private void ensureMandatoryPropertesAreInUserMapping() { + MANDATORY_USER_PROPERTIES.forEach(userPropertyName -> addToUserMappingWithDefault(userPropertyName)); } - public AttributeTranslator getAttributeTranslator() { - return attributeTranslator; + private void addToUserMappingWithDefault(String userProperty) { + String attributeName = getShibbolethAttributeName(userProperty); + if (!StringHelper.containsNonWhitespace(attributeName)) { + userMapping.put("oo" + userProperty, userProperty); + } } - public String[] getRegisteredOperatorKeys() { - return null; - } - - public List<String> getOperatorKeys() { - return operators; + private void ensureMandatoryPropertiesAreNeverDeleted() { + MANDATORY_USER_PROPERTIES.forEach(userPropertyName -> addToDeleteIfNullFalse(userPropertyName)); } - /** - * - * @return the shib. default attribute which identifies an user by an unique key - */ - public String getDefaultUIDAttribute() { - return defaultUIDAttribute; - } - - /** - * @param attributesMap - * @return First Name value from shibboleth attributes. - */ - public String getFirstName() { - return userMapping.get(CONF_OLATUSERMAPPING_FIRSTNAME); - } - - /** - * @return Last Name value from shibboleth attributes. - */ - public String getLastName() { - return userMapping.get(CONF_OLATUSERMAPPING_LASTNAME); + private void addToDeleteIfNullFalse(String userPropertyName) { + String attributeName = getShibbolethAttributeName(userPropertyName); + deleteIfNull.put(attributeName, false); } - - /** - * @return EMail value from shibboleth attributes. - */ - public String getEMail() { - return userMapping.get(CONF_OLATUSERMAPPING_EMAIL); + + public boolean isEnableShibbolethLogins() { + return enableShibbolethLogins; } /** - * @return Institutional EMail value from shibboleth attributes. + * @return true: use the attribute configurator in the course editor based + * on the attribute translator; false: don's use the attribute + * configurator */ - public String getInstitutionalEMail() { - return userMapping.get(CONF_OLATUSERMAPPING_INSTITUTIONALEMAIL); + public boolean isEnableShibbolethCourseEasyConfig() { + return isEnableShibbolethLogins() && getAttributeTranslator().getTranslateableAttributes().size() > 0; } - - /** - * @return Institutional Name value from shibboleth attributes. - */ - public String getInstitutionalName() { - return userMapping.get(CONF_OLATUSERMAPPING_INSTITUTIONALNAME); + + @Override + public boolean isEnabled() { + return isEnableShibbolethLogins(); } - - /** - * @return Institutional User Identifyer value from shibboleth attributes. - */ - public String getInstitutionalUserIdentifier() { - return userMapping.get(CONF_OLATUSERMAPPING_INSTITUTIONALUSERIDENTIFIER); + + public AttributeTranslator getAttributeTranslator() { + return attributeTranslator; } - - /** - * @return OrgUnit User Identifyer value from shibboleth attributes or NULL if not defined. - */ - public String getOrgUnit() { - return userMapping.get(CONF_OLATUSERMAPPING_ORGUNIT); + + public List<String> getOperatorKeys() { + return operators; } - - /** - * @return Prefered language value from shibboleth attributes. - */ - public String getPreferedLanguage() { - return userMapping.get(CONF_OLATUSERMAPPING_PREFERED_LANGUAGE); + + public String getUIDAttributeName() { + return uidAttributeName; } public String getLoginTemplate() { @@ -324,4 +306,99 @@ public class ShibbolethModule extends AbstractSpringModule implements ConfigOnOf this.attribute2Values = attribute2Values; setStringProperty("attribute2Values", attribute2Values, true); } + + public String getPreferredLanguageAttributeName() { + return preferredLanguageAttribute; + } + + /** + * Returns the mapping of a Shibboleth user to an OpenOLAT user. The key + * is the Shibboleth attribute name. The value is the user property. + * + * @return + */ + public Map<String, String> getUserMapping() { + return userMapping; + } + + public Map<String, String> getAttributeHandlerNames() { + return attributeHandler; + } + + public HashMap<String, Boolean> getDeleteIfNull() { + return deleteIfNull; + } + + /** + * Returns the name of a Shibboleth attribute for a given user property name + * of null if not found. + * + * @param userProperty + * @return + */ + public String getShibbolethAttributeName(String userProperty) { + for (Entry<String, String> mapping : userMapping.entrySet()) { + if (userProperty != null && userProperty.equals(mapping.getValue())) { + return mapping.getKey(); + } + } + return null; + } + + public boolean isAuthorMappingEnabled() { + return authorMappingEnabled; + } + + public String getAuthorMappingAttributeName() { + return authorMappingAttributeName; + } + + public Collection<String> getAuthorMappingContains() { + Collection<String> containsValues = Collections.<String>emptyList(); + if (StringHelper.containsNonWhitespace(authorMappingContains)) { + containsValues = Arrays.asList(authorMappingContains.split(AUTHOR_CONTAINS_SPLIT_VALUE)); + } + return containsValues; + } + + /** + * Get the names of all Shibboleth attributes which are configured either in + * the context.xml or in olat.local.properties + */ + public Collection<String> getShibbolethAttributeNames() { + Set<String> attributeNames = new HashSet<>(); + for (String userMappingKey : attributeTranslator.getTranslateableAttributes()) { + addAttributeNameIfDefined(userMappingKey, attributeNames); + } + for (String userMappingKey : userMapping.keySet()) { + addAttributeNameIfDefined(userMappingKey, attributeNames); + } + addAttributeNameIfDefined(uidAttributeName, attributeNames); + addAttributeNameIfDefined(preferredLanguageAttribute, attributeNames); + addAttributeNameIfDefined(authorMappingAttributeName, attributeNames); + addAttributeNameIfDefined(attribute1, attributeNames); + addAttributeNameIfDefined(attribute2, attributeNames); + addAttributeNameIfDefined(acAutoAttributeName, attributeNames); + return attributeNames; + } + + private void addAttributeNameIfDefined(String attributeName, Set<String> attributeNames) { + if (StringHelper.containsNonWhitespace(attributeName)) { + attributeNames.add(attributeName); + } + } + + + public Set<IdentifierKey> getAcAutoIdentifiers() { + return acAutoIdentifiers; + } + + public String getAcAutoAttributeName() { + return acAutoAttributeName; + } + + public String getAcAutoSplitter() { + return acAutoSplitter; + } + } \ No newline at end of file diff --git a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java index 388ba45ecddf26412db04b86235c7a4360596619..91d688b797e8e01bf97cb7c33aa58b17fadbea4d 100644 --- a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java +++ b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java @@ -26,7 +26,6 @@ package org.olat.shibboleth; import java.util.Locale; -import java.util.Map; import javax.servlet.http.HttpServletRequest; @@ -35,8 +34,6 @@ import org.olat.basesecurity.Authentication; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.BaseSecurityModule; -import org.olat.basesecurity.Constants; -import org.olat.basesecurity.SecurityGroup; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.chiefcontrollers.LanguageChangedEvent; import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; @@ -56,6 +53,7 @@ import org.olat.core.id.Identity; import org.olat.core.id.User; import org.olat.core.id.UserConstants; import org.olat.core.logging.AssertException; +import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.WebappHelper; import org.olat.core.util.i18n.I18nManager; @@ -66,7 +64,7 @@ import org.olat.registration.LanguageChooserController; import org.olat.registration.RegistrationManager; import org.olat.registration.RegistrationModule; import org.olat.registration.UserNameCreationInterceptor; -import org.olat.shibboleth.util.ShibbolethHelper; +import org.olat.shibboleth.manager.ShibbolethAttributes; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; @@ -74,17 +72,17 @@ import org.springframework.beans.factory.annotation.Autowired; * Initial Date: 09.08.2004 * * @author Mike Stock - * + * * Comment: * User wants ShibbolethAuthentication * - Basic flow: * System asks User for username and create olataccount with ShibbolethAuthentication * Branches: - * 1. no email in shibbolethAttributesMap + * 1. no email in shibbolethAttributes * - System asks for emailaddress (no institutionalEmail is set !!!) - * 2. no email in shibbolethAttributesMap and User already exists in System + * 2. no email in shibbolethAttributes and User already exists in System * - System asks for password (no institutionalEmail is set !!!) - * + * */ public class ShibbolethRegistrationController extends DefaultController implements ControllerEventListener { @@ -92,58 +90,54 @@ public class ShibbolethRegistrationController extends DefaultController implemen private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(ShibbolethModule.class); private static final String KEY_SHIBATTRIBUTES = "shibattr"; private static final String KEY_SHIBUNIQUEID = "shibuid"; - + private VelocityContainer mainContainer; private ShibbolethRegistrationForm regForm; private ShibbolethMigrationForm migrationForm; - private ShibbolethRegistrationWithEmailForm regWithEmailForm; + private ShibbolethRegistrationUserPropertiesFrom regWithUserPropForm; private DisclaimerController dclController; private LanguageChooserController languageChooserController; - + private Translator translator; - private Map<String,String> shibbolethAttributesMap; + private ShibbolethAttributes shibbolethAttributes; private String shibbolethUniqueID; - + private int state = STATE_UNDEFINED; private static final int STATE_UNDEFINED = 0; private static final int STATE_NEW_SHIB_USER = 1; private static final int STATE_MIGRATED_SHIB_USER = 2; private String proposedUsername; - - private boolean hasEmailInShibAttr; - + Locale locale; + @Autowired private ShibbolethModule shibbolethModule; @Autowired + private ShibbolethManager shibbolethManager; + @Autowired private RegistrationModule registrationModule; - + /** * Implements the shibboleth registration workflow. * @param ureq - * @param wControl + * @param wControl */ public ShibbolethRegistrationController(UserRequest ureq, WindowControl wControl) { super(wControl); translator = Util.createPackageTranslator(ShibbolethModule.class, ureq.getLocale()); - shibbolethAttributesMap = (Map<String,String>)ureq.getUserSession().getEntry(KEY_SHIBATTRIBUTES); + shibbolethAttributes = (ShibbolethAttributes)ureq.getUserSession().getEntry(KEY_SHIBATTRIBUTES); shibbolethUniqueID = (String)ureq.getUserSession().getEntry(KEY_SHIBUNIQUEID); - - if (shibbolethUniqueID == null) { + + if (shibbolethUniqueID == null) { ChiefController msgcc = MessageWindowController.createMessageChiefController(ureq, new AssertException("ShibbolethRegistrationController was unable to fetch ShibbolethUniqueID from session."), translator.translate("error.shibboleth.generic"), null); msgcc.getWindow().dispatchRequest(ureq, true); return; } - if (shibbolethAttributesMap == null) - throw new AssertException("ShibbolethRegistrationController was unable to fetch ShibbolethAttribuitesMap from session."); - - hasEmailInShibAttr = (shibbolethModule.getEMail() == null) ? false : true; - - Locale locale = (Locale)ureq.getUserSession().getEntry(LocaleNegotiator.NEGOTIATED_LOCALE); + locale = (Locale)ureq.getUserSession().getEntry(LocaleNegotiator.NEGOTIATED_LOCALE); if(locale == null) { - String preferedLanguage = shibbolethModule.getPreferedLanguage(); + String preferedLanguage = shibbolethAttributes.getPreferredLanguage(); if(preferedLanguage == null) { locale = LocaleNegotiator.getPreferedLocale(ureq); } else { @@ -156,18 +150,18 @@ public class ShibbolethRegistrationController extends DefaultController implemen ureq.getUserSession().setLocale(locale); I18nManager.updateLocaleInfoToThread(ureq.getUserSession()); ureq.getUserSession().putEntry(LocaleNegotiator.NEGOTIATED_LOCALE, locale); - + translator = Util.createPackageTranslator(ShibbolethModule.class, ureq.getLocale()); mainContainer = new VelocityContainer("main", VELOCITY_ROOT + "/langchooser.html", translator, this); - + languageChooserController = new LanguageChooserController(ureq, wControl, false); languageChooserController.addControllerListener(this); mainContainer.put("select.language", languageChooserController.getInitialComponent()); mainContainer.contextPut("languageCode", locale.getLanguage()); - + if(registrationModule.getUsernamePresetBean() != null) { UserNameCreationInterceptor interceptor = registrationModule.getUsernamePresetBean(); - proposedUsername = interceptor.getUsernameFor(shibbolethAttributesMap); + proposedUsername = interceptor.getUsernameFor(shibbolethAttributes.toMap()); if(proposedUsername == null) { if(interceptor.allowChangeOfUsername()) { setRegistrationForm(ureq, wControl, proposedUsername); @@ -185,15 +179,15 @@ public class ShibbolethRegistrationController extends DefaultController implemen } else if(interceptor.allowChangeOfUsername()) { setRegistrationForm(ureq, wControl, proposedUsername); } else { - if(hasEmailInShibAttr) { + if(areMandatoryUserPropertiesAvaible()) { state = STATE_NEW_SHIB_USER; mainContainer.setPage(VELOCITY_ROOT + "/disclaimer.html"); } else { - regWithEmailForm = new ShibbolethRegistrationWithEmailForm(ureq, wControl, proposedUsername); - regWithEmailForm.addControllerListener(this); - //mainContainer.put("regWithEmailForm", regWithEmailForm); - mainContainer.setPage(VELOCITY_ROOT + "/registerwithemail.html"); - } + regWithUserPropForm = new ShibbolethRegistrationUserPropertiesFrom(ureq, wControl, shibbolethAttributes); + regWithUserPropForm.addControllerListener(this); + mainContainer.put("getUserPropsForm", regWithUserPropForm.getInitialComponent()); + mainContainer.setPage(VELOCITY_ROOT + "/register_user_props.html"); + } } } } else { @@ -203,34 +197,34 @@ public class ShibbolethRegistrationController extends DefaultController implemen dclController = new DisclaimerController(ureq, getWindowControl()); dclController.addControllerListener(this); mainContainer.put("dclComp", dclController.getInitialComponent()); - + // load view in layout LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), null, mainContainer, null); setInitialComponent(layoutCtr.getInitialComponent()); } - + private void setErrorPage(String errorKey, WindowControl wControl) { String error = translator.translate(errorKey); wControl.setError(error); mainContainer.contextPut("error_msg", error); mainContainer.setPage(VELOCITY_ROOT + "/error.html"); } - + private void setRegistrationForm(UserRequest ureq, WindowControl wControl, String proposedUsername) { regForm = new ShibbolethRegistrationForm(ureq, wControl, proposedUsername); regForm.addControllerListener(this); mainContainer.put("regForm", regForm.getInitialComponent()); } - + /** * Put shibboleth attributes map in reqest for later usage. * @param req * @param attributes */ - public static final void putShibAttributes(HttpServletRequest req, Map<String,String> attributes) { + public static final void putShibAttributes(HttpServletRequest req, ShibbolethAttributes attributes) { CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(req).putEntry(KEY_SHIBATTRIBUTES, attributes); } - + /** * Put shibboleth unique identifier in request for later usage. * @param req @@ -240,9 +234,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(req).putEntry(KEY_SHIBUNIQUEID, uniqueID); } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ + @Override public void event(UserRequest ureq, Component source, Event event) { if (event instanceof LocaleChangedEvent) { LocaleChangedEvent lce = (LocaleChangedEvent)event; @@ -252,9 +244,6 @@ public class ShibbolethRegistrationController extends DefaultController implemen } } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) - */ @Override public void event(UserRequest ureq, Controller source, Event event) { if (source == migrationForm) { @@ -264,32 +253,32 @@ public class ShibbolethRegistrationController extends DefaultController implemen state = STATE_MIGRATED_SHIB_USER; mainContainer.setPage(VELOCITY_ROOT + "/disclaimer.html"); } - } else if (source == regWithEmailForm){ + } else if (source == regWithUserPropForm){ if (event == Event.CANCELLED_EVENT) { mainContainer.setPage(VELOCITY_ROOT + "/register.html"); } else if (event == Event.DONE_EVENT) { state = STATE_NEW_SHIB_USER; mainContainer.setPage(VELOCITY_ROOT + "/disclaimer.html"); - } + } } else if (source == regForm) { if (event == Event.DONE_EVENT) { String choosenLogin = regForm.getLogin(); BaseSecurity secMgr = BaseSecurityManager.getInstance(); Identity identity = secMgr.findIdentityByName(choosenLogin); - + if (identity == null) { // ok, create new user - if (!hasEmailInShibAttr){ - regWithEmailForm = new ShibbolethRegistrationWithEmailForm(ureq, getWindowControl(), choosenLogin); - regWithEmailForm.addControllerListener(this); - mainContainer.put("regWithEmailForm", regWithEmailForm.getInitialComponent()); - mainContainer.setPage(VELOCITY_ROOT + "/registerwithemail.html"); - } else { // there is an emailaddress + if (isMandatoryUserPropertyMissing()){ + regWithUserPropForm = new ShibbolethRegistrationUserPropertiesFrom(ureq, getWindowControl(), shibbolethAttributes); + regWithUserPropForm.addControllerListener(this); + mainContainer.put("getUserPropsForm", regWithUserPropForm.getInitialComponent()); + mainContainer.setPage(VELOCITY_ROOT + "/register_user_props.html"); + } else { state = STATE_NEW_SHIB_USER; mainContainer.setPage(VELOCITY_ROOT + "/disclaimer.html"); } } else { // offer identity migration, if OLAT provider exists - Authentication auth = secMgr.findAuthentication(identity, BaseSecurityModule.getDefaultAuthProviderIdentifier()); + Authentication auth = secMgr.findAuthentication(identity, BaseSecurityModule.getDefaultAuthProviderIdentifier()); if (auth == null) { // no OLAT provider, migration not possible... getWindowControl().setError(translator.translate("sr.error.loginexists", new String[] {WebappHelper.getMailConfig("mailSupport")})); } else { // OLAT provider exists, offer migration... @@ -318,7 +307,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen } else { choosenLogin = regForm.getLogin(); } - + // check if login has been taken by another user in the meantime... BaseSecurity secMgr = BaseSecurityManager.getInstance(); @@ -331,19 +320,13 @@ public class ShibbolethRegistrationController extends DefaultController implemen return; } - String email; - if(!hasEmailInShibAttr){ - email = regWithEmailForm.getEmail(); - } else { - email = ShibbolethHelper.getFirstValueOf(shibbolethModule.getEMail(), shibbolethAttributesMap); - } - User user = null; + String email = shibbolethAttributes.getValueForUserPropertyName(UserConstants.EMAIL); Identity id = UserManager.getInstance().findIdentityByEmail(email); if (id != null) { user = id.getUser(); } - + if (user != null) { // error, email already exists. should actually not happen if OLAT Authenticator has // been set after removing shibboleth authenticator @@ -353,25 +336,8 @@ public class ShibbolethRegistrationController extends DefaultController implemen return; } - String firstName = shibbolethAttributesMap.get(shibbolethModule.getFirstName()); - String lastName = shibbolethAttributesMap.get(shibbolethModule.getLastName()); - user = UserManager.getInstance().createUser(firstName, lastName, email); - user.setProperty(UserConstants.INSTITUTIONALNAME, shibbolethAttributesMap.get(shibbolethModule.getInstitutionalName())); - if(hasEmailInShibAttr){ - String institutionalEmail = ShibbolethHelper.getFirstValueOf(shibbolethModule.getInstitutionalEMail(), shibbolethAttributesMap); - user.setProperty(UserConstants.INSTITUTIONALEMAIL, institutionalEmail); - } - user.setProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, shibbolethAttributesMap.get(shibbolethModule.getInstitutionalUserIdentifier())); - // Optional organization unit property - String orgUnitIdent = shibbolethModule.getOrgUnit(); - if(orgUnitIdent != null) { - String s = ShibbolethHelper.getFirstValueOf(orgUnitIdent, shibbolethAttributesMap); - if (s != null) user.setProperty(UserConstants.ORGUNIT, s); - } + identity = shibbolethManager.createUser(choosenLogin, shibbolethUniqueID, locale.getLanguage(), shibbolethAttributes); - identity = secMgr.createAndPersistIdentityAndUser(choosenLogin, null, user, ShibbolethDispatcher.PROVIDER_SHIB, shibbolethUniqueID); - SecurityGroup olatUserGroup = secMgr.findSecurityGroupByName(Constants.GROUP_OLATUSERS); - secMgr.addIdentityToSecurityGroup(identity, olatUserGroup); // tell system that this user did accept the disclaimer CoreSpringFactory.getImpl(RegistrationManager.class).setHasConfirmedDislaimer(identity); doLogin(identity, ureq); @@ -382,27 +348,10 @@ public class ShibbolethRegistrationController extends DefaultController implemen Identity authenticationedIdentity = auth.getIdentity(); BaseSecurity secMgr = BaseSecurityManager.getInstance(); secMgr.createAndPersistAuthentication(authenticationedIdentity, ShibbolethDispatcher.PROVIDER_SHIB, shibbolethUniqueID, null, null); - + // update user profile - User user = authenticationedIdentity.getUser(); - String s = shibbolethAttributesMap.get(shibbolethModule.getFirstName()); - if (s != null) user.setProperty(UserConstants.FIRSTNAME, s); - s = shibbolethAttributesMap.get(shibbolethModule.getLastName()); - if (s != null) user.setProperty(UserConstants.LASTNAME, s); - s = shibbolethAttributesMap.get(shibbolethModule.getInstitutionalName()); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALNAME, s); - s = ShibbolethHelper.getFirstValueOf(shibbolethModule.getInstitutionalEMail(), shibbolethAttributesMap); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALEMAIL, s); - s = shibbolethAttributesMap.get(shibbolethModule.getInstitutionalUserIdentifier()); - if (s != null) user.setProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, s); - // Optional organization unit property - String orgUnitIdent = shibbolethModule.getOrgUnit(); - if(orgUnitIdent != null) { - s = ShibbolethHelper.getFirstValueOf(orgUnitIdent, shibbolethAttributesMap); - if (s != null) user.setProperty(UserConstants.ORGUNIT, s); - } - - UserManager.getInstance().updateUser(user); + shibbolethManager.syncUser(authenticationedIdentity, shibbolethAttributes); + doLogin(authenticationedIdentity, ureq); return; } @@ -413,6 +362,22 @@ public class ShibbolethRegistrationController extends DefaultController implemen } } + private boolean isMandatoryUserPropertyMissing() { + return !areMandatoryUserPropertiesAvaible(); + } + + private boolean areMandatoryUserPropertiesAvaible() { + String lastname = shibbolethAttributes.getValueForUserPropertyName(UserConstants.LASTNAME); + String firstname = shibbolethAttributes.getValueForUserPropertyName(UserConstants.FIRSTNAME); + String email = shibbolethAttributes.getValueForUserPropertyName(UserConstants.EMAIL); + if (StringHelper.containsNonWhitespace(lastname) + && StringHelper.containsNonWhitespace(firstname) + && StringHelper.containsNonWhitespace(email)) { + return true; + } + return false; + } + private void doLogin(Identity identity, UserRequest ureq) { int loginStatus = AuthHelper.doLogin(identity, ShibbolethDispatcher.PROVIDER_SHIB, ureq); if (loginStatus != AuthHelper.LOGIN_OK) { @@ -426,19 +391,20 @@ public class ShibbolethRegistrationController extends DefaultController implemen } // successfull login ureq.getUserSession().getIdentityEnvironment().addAttributes( - shibbolethModule.getAttributeTranslator().translateAttributesMap(shibbolethAttributesMap)); + shibbolethModule.getAttributeTranslator().translateAttributesMap(shibbolethAttributes.toMap())); } - + /** - * + * * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) */ + @Override protected void doDispose() { if (dclController != null) { dclController.dispose(); dclController = null; } - + if (languageChooserController != null) { languageChooserController.dispose(); languageChooserController = null; diff --git a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationUserPropertiesFrom.java b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationUserPropertiesFrom.java new file mode 100644 index 0000000000000000000000000000000000000000..46da7cddfd2f41d59492be25bd88adfcdd680108 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationUserPropertiesFrom.java @@ -0,0 +1,132 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.TextElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +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.registration.RegistrationForm2; +import org.olat.shibboleth.manager.ShibbolethAttributes; +import org.olat.user.UserManager; +import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 09.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class ShibbolethRegistrationUserPropertiesFrom extends FormBasicController { + + public static final String USERPROPERTIES_FORM_IDENTIFIER = ShibbolethRegistrationUserPropertiesFrom.class.getCanonicalName(); + + private final ShibbolethAttributes shibbolethAttributes; + private final List<UserPropertyHandler> userPropertyHandlers; + + private Map<String,FormItem> propFormItems = new HashMap<>(); + + @Autowired + private UserManager userManager; + + public ShibbolethRegistrationUserPropertiesFrom(UserRequest ureq, WindowControl wControl, ShibbolethAttributes shibbolethAttributes) { + super(ureq, wControl); + setTranslator(Util.createPackageTranslator(RegistrationForm2.class, getLocale(), getTranslator())); + setTranslator(Util.createPackageTranslator(UserPropertyHandler.class, getLocale(), getTranslator())); + userPropertyHandlers = userManager.getUserPropertyHandlersFor(USERPROPERTIES_FORM_IDENTIFIER, false); + + this.shibbolethAttributes = shibbolethAttributes; + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + // Add all available user fields to this form + for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { + if (userPropertyHandler != null) { + FormItem fi = userPropertyHandler.addFormItem(getLocale(), null, USERPROPERTIES_FORM_IDENTIFIER, false, formLayout); + propFormItems.put(userPropertyHandler.getName(), fi); + if(fi instanceof TextElement) { + String value = shibbolethAttributes.getValueForUserPropertyName( userPropertyHandler.getName()); + if(StringHelper.containsNonWhitespace(value)) { + TextElement formElement = (TextElement)fi; + formElement.setValue(value); + formElement.setEnabled(false); + } + } + } + } + + FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator()); + formLayout.add(buttonLayout); + uifactory.addFormSubmitButton("save", buttonLayout); + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + // validate each user field + for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { + FormItem fi = propFormItems.get(userPropertyHandler.getName()); + if (!userPropertyHandler.isValid(null, fi, null)) { + allOk &= false; + } + } + + return allOk & super.validateFormLogic(ureq); + } + + @Override + protected void formOK(UserRequest ureq) { + for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { + updateShibboletAttribute(userPropertyHandler); + } + + fireEvent (ureq, Event.DONE_EVENT); + } + + private void updateShibboletAttribute(UserPropertyHandler userPropertyHandler) { + String propertyName = userPropertyHandler.getName(); + FormItem propertyItem = this.flc.getFormComponent(propertyName); + String propertyValue = userPropertyHandler.getStringValue(propertyItem); + shibbolethAttributes.setValueForUserPropertyName(propertyName, propertyValue); + } + + @Override + protected void doDispose() { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationWithEmailForm.java b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationWithEmailForm.java deleted file mode 100644 index fd8fe08c207fc84ec510955beb17d5dd96608b4c..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationWithEmailForm.java +++ /dev/null @@ -1,131 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ - -package org.olat.shibboleth; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.form.flexible.FormItemContainer; -import org.olat.core.gui.components.form.flexible.elements.TextElement; -import org.olat.core.gui.components.form.flexible.impl.FormBasicController; -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.id.Identity; -import org.olat.core.util.mail.MailHelper; -import org.olat.user.UserManager; - -/** - * Initial Date: 01.02.2006 - * - * @author Alexander Schneider - * - * Comment: - * - */ - -public class ShibbolethRegistrationWithEmailForm extends FormBasicController { - - private TextElement login; - private TextElement eMail; - private String userName; - - /** - * @param name - * @param translator - */ - public ShibbolethRegistrationWithEmailForm(UserRequest ureq, WindowControl wControl, String userName) { - super(ureq, wControl); - this.userName = userName; - initForm(ureq); - } - - - @Override - protected boolean validateFormLogic(UserRequest ureq) { - - if (eMail.isEmpty("srf.error.email.empty")) { - return false; - } - - if (!MailHelper.isValidEmailAddress(getEmail())){ - eMail.setErrorKey("srf.error.email.valid", null); - return false; - } - - // check if email is already used by another useraccount - Identity foundIdentity = UserManager.getInstance().findIdentityByEmail(eMail.getValue()); - if (foundIdentity != null) { - eMail.setErrorKey("srf.error.email.usedByOtherUser", null); - return false; - } - - return true; - } - - /** - * @return Login field. - */ - protected String getLogin() { - return login.getValue(); - } - - /** - * - * @return E-mail field - */ - protected String getEmail() { - return eMail.getValue().toLowerCase().trim(); - } - - @Override - protected void formOK(UserRequest ureq) { - fireEvent (ureq, Event.DONE_EVENT); - } - - @Override - protected void formCancelled(UserRequest ureq) { - fireEvent (ureq, Event.CANCELLED_EVENT); - } - - @Override - protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - login = uifactory.addTextElement("srf_login", "srf.login", 128, userName, formLayout); - login.setEnabled (false); - - - eMail = uifactory.addTextElement("srf_email", "srf.email", 128, "", formLayout); - - FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator()); - formLayout.add(buttonLayout); - uifactory.addFormSubmitButton("submit", buttonLayout); - uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl()); - } - - @Override - protected void doDispose() { - // - } -} diff --git a/src/main/java/org/olat/shibboleth/_content/registerwithemail.html b/src/main/java/org/olat/shibboleth/_content/register_user_props.html similarity index 72% rename from src/main/java/org/olat/shibboleth/_content/registerwithemail.html rename to src/main/java/org/olat/shibboleth/_content/register_user_props.html index a2b0103066614b6f721809284a832570d6d31ee1..9f3ed4905296f3cc6d28bc259659fd8b872fee7c 100644 --- a/src/main/java/org/olat/shibboleth/_content/registerwithemail.html +++ b/src/main/java/org/olat/shibboleth/_content/register_user_props.html @@ -3,4 +3,4 @@ $r.translate("we.intro") <br /><br /> -$r.render("regWithEmailForm") \ No newline at end of file +$r.render("getUserPropsForm") \ No newline at end of file diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_ar.properties index 6576fea6eda89b57ca82de266e8f87669cb27670..c23d21797954c4e563fe2093a17d7eb577087c40 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_ar.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_ar.properties @@ -19,7 +19,6 @@ eduPersonAffiliation.student=\u0627\u0644\u0637\u0627\u0644\u0628 eduPersonEntitlement=\u0627\u0644\u0645\u0635\u0627\u062F\u0642\u0629 eduPersonOrgUnitDN=DN \u0648\u062D\u062F\u0629 \u0627\u0644\u0645\u0646\u0638\u0645\u0629 employeeNumber=\u0631\u0642\u0645 \u0627\u0644\u0645\u0648\u0638\u0641 -error.insufficieant.attributes=\u0636\u0631\u0648\u0631\u064A\u0629 Shibboleth \u0635\u0641\u0627\u062A\: Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.generic=\u064A\u0631\u062C\u0649 \u0627\u0644\u062F\u062E\u0648\u0644 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649 \u060CShibboleth \u062E\u0637\u0623 \u0641\u0649 error.shibboleth.head=\u0623\u0648\u0644\u0627\u062A - \u0627\u0644\u062A\u0639\u0644\u064A\u0645 \u0648\u0627\u0644\u062A\u062F\u0631\u064A\u0628 \u0639\u0628\u0631 \u0627\u0644\u0627\u0646\u062A\u0631\u0646\u062A - \u062E\u0637\u0623 error.unqueid.notfound=\u0647\u0644 \u0644\u062F\u064A\u0643 \u0628\u064A\u0627\u0646\u0627\u062A \u062F\u062E\u0648\u0644 \u0625\u0644\u0649 \u0623\u0648\u0644\u0627\u062A\u061F \u0625\u0630\u0627 \u0643\u0627\u0646\u062A \u0627\u0644\u0627\u062C\u0627\u0628\u0629 \u0646\u0639\u0645 \u0641\u0625\u0646\u0647 \u064A\u0631\u062C\u0649 \u0645\u062D\u0627\u0648\u0644\u0629 \u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649. @@ -480,4 +479,3 @@ wayf.password.back=\u0627\u0644\u0631\u062C\u0648\u0639 \u0625\u0644\u0649 \u062 wayf.password.text=\u0644\u0642\u062F \u0646\u0633\u064A\u062A \u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u062F\u062E\u0648\u0644 \u0627\u0644\u062E\u0627\u0635\u0629 \u0628\u062C\u0627\u0645\u0639\u062A\u0643\u060C \u064A\u0631\u062C\u0649 \u0627\u0644\u0627\u062A\u0635\u0627\u0644 \u0628\u0627\u0644\u0642\u0633\u0645 \u0627\u0644\u0645\u062E\u062A\u0635 \u0641\u0649 \u062C\u0627\u0645\u0639\u062A\u0643. wayf.pleasechoose=...\u064A\u0631\u062C\u0649 \u062A\u062D\u062F\u064A\u062F \u062C\u0627\u0645\u0639\u062A\u0643 wayf.submit=\u062F\u062E\u0648\u0644 -we.intro=\u0627\u0644\u0647\u0648\u064A\u0629 \u0627\u0644\u062E\u0627\u0635 \u0628\u0643 \u0644\u0627 \u062A\u062A\u0636\u0645\u0646 \u0639\u0646\u0648\u0627\u0646 \u0628\u0631\u064A\u062F \u0627\u0644\u0643\u062A\u0631\u0648\u0646\u0649\u060C \u064A\u0631\u062C\u0649 \u062A\u062D\u062F\u064A\u062F \u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0628\u0631\u064A\u062F \u0627\u0644\u0627\u0644\u0643\u062A\u0631\u0648\u0646\u0649 \u0627\u0644\u062E\u0627\u0635 \u0628\u0643. diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_bg.properties index 071ec0e196bebeebfb263debaeea7608d9fe0ad6..b46b350f80cabae2849d217880f040901020464e 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_bg.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_bg.properties @@ -19,7 +19,6 @@ eduPersonAffiliation.student=\u0421\u0442\u0443\u0434\u0435\u043D\u0442 eduPersonEntitlement=\u0423\u043F\u044A\u043B\u043D\u043E\u043C\u043E\u0449\u0430\u0432\u0430\u043D\u0435 eduPersonOrgUnitDN=\u041E\u0440\u0433\u0430\u043D\u0438\u0437\u0430\u0446\u0438\u043E\u043D\u043D\u0430 \u0435\u0434\u0438\u043D\u0438\u0446\u0430 DN employeeNumber=\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u043E\u043D\u0435\u043D \u043D\u043E\u043C\u0435\u0440 \u043D\u0430 \u0441\u043B\u0443\u0436\u0438\u0442\u0435\u043B -error.insufficieant.attributes=\u0417\u0430\u0434\u044A\u043B\u0436\u0438\u0442\u0435\u043B\u043D\u0438 Shibboleth \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0438\: Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.generic=\u041F\u043E\u043B\u0443\u0447\u0438 \u0441\u0435 Shibboleth \u0433\u0440\u0435\u0448\u043A\u0430. \u041C\u043E\u043B\u044F, \u0432\u043B\u0435\u0437\u0442\u0435 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430 \u043E\u0442\u043D\u043E\u0432\u043E\! error.shibboleth.head=\u0421\u0438\u0441\u0442\u0435\u043C\u0430 \u0437\u0430 \u043E\u043D\u043B\u0430\u0439\u043D \u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435 - \u0413\u0440\u0435\u0448\u043A\u0430 error.unqueid.notfound=\u041D\u0430\u0438\u0441\u0442\u0438\u043D\u0430 \u043B\u0438 \u0438\u043C\u0430\u0442\u0435 \u043F\u0440\u0430\u0432\u043E \u0434\u0430 \u0432\u043B\u0438\u0437\u0430\u0442\u0435 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430? \u0410\u043A\u043E \u0435 \u0442\u0430\u043A\u0430, \u043C\u043E\u043B\u044F, \u043E\u043F\u0438\u0442\u0430\u0439\u0442\u0435 \u043E\u0442\u043D\u043E\u0432\u043E. @@ -40,7 +39,7 @@ sr.error.disclaimer=\u0422\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u043F\u04 sr.error.emailexists=\u041F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B \u0441 \u0442\u043E\u0437\u0438 \u0438-\u043C\u0435\u0439\u043B \u0430\u0434\u0440\u0435\u0441 \u0432\u0435\u0447\u0435 \u0441\u044A\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430. \u041C\u043E\u043B\u044F, \u0441\u0432\u044A\u0440\u0436\u0435\u0442\u0435 \u0441\u0435 \u0441 {0}. sr.error.loginexists=\u041F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E\u0442\u043E \u0438\u043C\u0435 \u0432\u0435\u0447\u0435 \u0441\u044A\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430. <br>\u0410\u043A\u043E \u0441\u0442\u0435 \u0441\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043B\u0438 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430 \u0441 \u0442\u043E\u0432\u0430 \u043F\u043E\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E \u0438\u043C\u0435 \u043F\u0440\u0435\u0434\u0438, \u043C\u043E\u043B\u044F, \u0441\u0432\u044A\u0440\u0436\u0435\u0442\u0435 \u0441\u0435 \u0441 {0}. sr.header=\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F -sr.intro=\u041C\u043E\u043B\u044F, \u0438\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E \u0438\u043C\u0435 \u0437\u0430 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430. <b>\u0412\u043D\u0438\u043C\u0430\u043D\u0438\u0435\:</b> \u0422\u043E\u0432\u0430 \u0438\u043C\u0435 \u043D\u0435 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043F\u0440\u043E\u043C\u0435\u043D\u044F \u043D\u0430 \u043F\u043E-\u043A\u044A\u0441\u0435\u043D \u0435\u0442\u0430\u043F\! +sr.intro=\u041C\u043E\u043B\u044F, \u0438\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E \u0438\u043C\u0435 \u0437\u0430 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430. <b>\u0412\u043D\u0438\u043C\u0430\u043D\u0438\u0435\:</b> \u0422\u043E\u0432\u0430 \u0438\u043C\u0435 \u043D\u0435 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043F\u0440\u043E\u043C\u0435\u043D\u044F \u043D\u0430 \u043F\u043E-\u043A\u044A\u0441\u0435\u043D \u0435\u0442\u0430\u043F\! sr.login.meantimetaken=\u0422\u043E\u0432\u0430 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E \u0438\u043C\u0435 \u0435 \u0432\u0435\u0447\u0435 \u0437\u0430\u0435\u0442\u043E. \u041C\u043E\u043B\u044F, \u0438\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0434\u0440\u0443\u0433\u043E. srf.email=\u0418-\u043C\u0435\u0439\u043B \u0430\u0434\u0440\u0435\u0441 srf.error.blacklist=\u0418\u0437\u0431\u0440\u0430\u043D\u043E\u0442\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E \u0438\u043C\u0435 \u043D\u0435 \u0435 \u043F\u0440\u0438\u0435\u0442\u043E. @@ -170,7 +169,7 @@ swissEduPersonStudyBranch2.140199=UAS\:\u0417\u0434\u0440\u0430\u0432\u043D\u043 swissEduPersonStudyBranch2.140201=UAS\:\u0424\u0438\u0437\u0438\u043E\u0442\u0435\u0440\u0430\u043F\u0438\u044F swissEduPersonStudyBranch2.140202=UAS\:\u0415\u0440\u0433\u043E\u0442\u0435\u0440\u0430\u043F\u0438\u044F swissEduPersonStudyBranch2.140203=UAS\:\u041F\u0441\u0438\u0445\u043E\u043C\u043E\u0442\u043E\u0440\u043D\u0430 \u0442\u0435\u0440\u0430\u043F\u0438\u044F -swissEduPersonStudyBranch2.140204=UAS\:\u0414\u0438\u0435\u0442\u043E\u043B\u043E\u0433\u0438\u044F +swissEduPersonStudyBranch2.140204=UAS\:\u0414\u0438\u0435\u0442\u043E\u043B\u043E\u0433\u0438\u044F swissEduPersonStudyBranch2.140299=UAS\:\u0422\u0435\u0440\u0430\u043F\u0438\u044F \u0438 \u0440\u0435\u0445\u0430\u0431\u0438\u043B\u0438\u0442\u0430\u0446\u0438\u044F (\u043E\u0431\u0449\u043E) swissEduPersonStudyBranch2.140301=UAS\:\u041C\u0435\u0434\u0438\u0446\u0438\u043D\u0441\u043A\u0430 \u0440\u0430\u0434\u0438\u043E\u043B\u043E\u0433\u0438\u044F swissEduPersonStudyBranch2.140399=UAS\:\u0414\u0438\u0430\u0433\u043D\u043E\u0441\u0442\u0438\u0447\u043D\u0430/\u0442\u0435\u0440\u0430\u043F\u0435\u0432\u0442\u0438\u0447\u043D\u0430 \u0442\u0435\u0445\u043D\u043E\u043B\u043E\u0433\u0438\u044F (\u043E\u0431\u0449\u043E) @@ -179,7 +178,7 @@ swissEduPersonStudyBranch2.15=U\:\u0425\u0443\u043C\u0430\u043D\u0438\u0442\u043 swissEduPersonStudyBranch2.150101=UAS\:\u0414\u0435\u0442\u0441\u043A\u0430 \u0433\u0440\u0430\u0434\u0438\u043D\u0430 \u0438 \u043D\u0430\u0447\u0430\u043B\u043D\u043E \u0443\u0447\u0438\u043B\u0438\u0449\u0435 (\u043E\u0431\u0449\u043E) swissEduPersonStudyBranch2.150201=UAS\:\u0413\u0438\u043C\u043D\u0430\u0437\u0438\u044F I (\u043E\u0431\u0449\u043E) swissEduPersonStudyBranch2.150301=UAS\:\u0413\u0438\u043C\u043D\u0430\u0437\u0438\u044F II (\u043E\u0431\u0449\u043E)(\u0434\u0438\u043F\u043B\u043E\u043C\u0430) -swissEduPersonStudyBranch2.150302=UAS\:\u0413\u0438\u043C\u043D\u0430\u0437\u0438\u044F II (\u043E\u0431\u0449\u043E)(\u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435) +swissEduPersonStudyBranch2.150302=UAS\:\u0413\u0438\u043C\u043D\u0430\u0437\u0438\u044F II (\u043E\u0431\u0449\u043E)(\u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435) swissEduPersonStudyBranch2.150401=UAS\:\u041B\u043E\u0433\u043E\u043F\u0435\u0434\u0438\u044F swissEduPersonStudyBranch2.150402=UAS\:Psychomotricity swissEduPersonStudyBranch2.150499=UAS\:\u0422\u0435\u0440\u0430\u043F\u0435\u0432\u0442\u0438\u0447\u043D\u0430 \u043F\u0435\u0434\u0430\u0433\u043E\u0433\u0438\u043A\u0430 (\u043E\u0431\u0449\u043E) @@ -196,12 +195,12 @@ swissEduPersonStudyBranch2.20209=UAS\:\u0418\u043D\u0434\u0443\u0441\u0442\u0440 swissEduPersonStudyBranch2.20210=UAS\:\u041C\u0435\u0434\u0438\u0439\u043D\u043E \u0438\u043D\u0436\u0435\u043D\u0435\u0440\u0441\u0442\u0432\u043E swissEduPersonStudyBranch2.20211=UAS\:\u0418\u043D\u0436\u0435\u043D\u0435\u0440\u0441\u0442\u0432\u043E \u043F\u043E \u043F\u043E\u0434\u0434\u0440\u044A\u0436\u043A\u0430 \u043D\u0430 \u0441\u0433\u0440\u0430\u0434\u0438 swissEduPersonStudyBranch2.20212=UAS\:\u0418\u043D\u0436\u0435\u043D\u0435\u0440\u0435\u043D \u0434\u0438\u0437\u0430\u0439\u043D -swissEduPersonStudyBranch2.20213=UAS\:\u0410\u0432\u0438\u0430\u0442\u0438\u043A\u0430 +swissEduPersonStudyBranch2.20213=UAS\:\u0410\u0432\u0438\u0430\u0442\u0438\u043A\u0430 swissEduPersonStudyBranch2.20214=UAS\:\u041E\u043F\u0442\u043E\u043C\u0435\u0442\u0440\u0438\u044F swissEduPersonStudyBranch2.20999=UAS\:\u0422\u0435\u0445\u043D\u0438\u043A\u0430 swissEduPersonStudyBranch2.30301=UAS\:\u0411\u0438\u043E\u0442\u0435\u0445\u043D\u043E\u043B\u043E\u0433\u0438\u044F swissEduPersonStudyBranch2.30302=UAS\:\u0425\u0440\u0430\u043D\u0438\u0442\u0435\u043B\u043D\u0430 \u0442\u0435\u0445\u043D\u043E\u043B\u043E\u0433\u0438\u044F -swissEduPersonStudyBranch2.30303=UAS\:Life technologies +swissEduPersonStudyBranch2.30303=UAS\:Life technologies swissEduPersonStudyBranch2.30304=UAS\:\u0425\u0438\u043C\u0438\u044F swissEduPersonStudyBranch2.30305=UAS\:\u0415\u043D\u043E\u043B\u043E\u0433\u0438\u044F swissEduPersonStudyBranch2.30308=UAS\:\u0418\u043D\u0436\u0435\u043D\u0435\u0440\u0441\u0442\u0432\u043E \u043D\u0430 \u043F\u0440\u0438\u0440\u043E\u0434\u043D\u0430\u0442\u0430 \u0441\u0440\u0435\u0434\u0430 @@ -231,7 +230,7 @@ swissEduPersonStudyBranch2.53=U\:\u0412\u0435\u0442\u0438\u0440\u0438\u043D\u043 swissEduPersonStudyBranch2.54=U\:\u0424\u0430\u0440\u043C\u0430\u0446\u0438\u044F swissEduPersonStudyBranch2.55=U\:\u041C\u0435\u0434\u0438\u0446\u0438\u043D\u0430, \u0444\u0430\u0440\u043C\u0430\u0446\u0438\u044F \u0438 \u0434\u0440\u0443\u0433\u0438 swissEduPersonStudyBranch2.60601=U\:\u0412\u0438\u0437\u0443\u0430\u043B\u043D\u0430 \u043A\u043E\u043C\u0443\u043D\u0438\u043A\u0430\u0446\u0438\u044F -swissEduPersonStudyBranch2.60602=UAS\:HyperWerk +swissEduPersonStudyBranch2.60602=UAS\:HyperWerk swissEduPersonStudyBranch2.60603=UAS\:\u041F\u0440\u043E\u0434\u0443\u043A\u0442\u043E\u0432 \u0438 \u0438\u043D\u0434\u0443\u0441\u0442\u0440\u0438\u0430\u043B\u0435\u043D \u0434\u0438\u0437\u0430\u0439\u043D swissEduPersonStudyBranch2.60604=UAS\:\u0418\u043D\u0442\u0435\u0440\u0438\u043E\u0440\u0435\u043D \u0434\u0438\u0437\u0430\u0439\u043D swissEduPersonStudyBranch2.60605=UAS\:\u0417\u0430\u043F\u0430\u0437\u0432\u0430\u043D\u0435 \u0438 \u0432\u044A\u0437\u0441\u0442\u0430\u043D\u043E\u0432\u044F\u0432\u0430\u043D\u0435 @@ -357,10 +356,10 @@ swissEduPersonStudyBranch3.3689=UAS\:\u0414\u0438\u0430\u0433\u043D\u043E\u0441\ swissEduPersonStudyBranch3.3699=UAS\:\u0417\u0434\u0440\u0430\u0432\u0435\u043E\u043F\u0430\u0437\u0432\u0430\u043D\u0435 (\u043E\u0431\u0449\u043E) swissEduPersonStudyBranch3.3701=UAS\:\u0414\u0435\u0442\u0441\u043A\u0430 \u0433\u0440\u0430\u0434\u0438\u043D\u0430 \u0438 \u043D\u0430\u0447\u0430\u043B\u043D\u043E \u0443\u0447\u0438\u043B\u0438\u0449\u0435 (\u043E\u0431\u0449\u043E) swissEduPersonStudyBranch3.3710=UAS\:\u0413\u0438\u043C\u043D\u0430\u0437\u0438\u044F I (\u043E\u0431\u0449\u043E) -swissEduPersonStudyBranch3.3720=UAS\:\u0413\u0438\u043C\u043D\u0430\u0437\u0438\u044F II (\u043E\u0431\u0449\u043E)(\u0434\u0438\u043F\u043B\u043E\u043C\u0430) -swissEduPersonStudyBranch3.3725=UAS\:\u0413\u0438\u043C\u043D\u0430\u0437\u0438\u044F II (\u043E\u0431\u0449\u043E)(\u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435) +swissEduPersonStudyBranch3.3720=UAS\:\u0413\u0438\u043C\u043D\u0430\u0437\u0438\u044F II (\u043E\u0431\u0449\u043E)(\u0434\u0438\u043F\u043B\u043E\u043C\u0430) +swissEduPersonStudyBranch3.3725=UAS\:\u0413\u0438\u043C\u043D\u0430\u0437\u0438\u044F II (\u043E\u0431\u0449\u043E)(\u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435) swissEduPersonStudyBranch3.3730=UAS\:\u041B\u043E\u0433\u043E\u043F\u0435\u0434\u0438\u044F -swissEduPersonStudyBranch3.3731=UAS\:Psychomotricity +swissEduPersonStudyBranch3.3731=UAS\:Psychomotricity swissEduPersonStudyBranch3.3739=UAS\:\u0422\u0435\u0440\u0430\u043F\u0435\u0432\u0442\u0438\u0447\u043D\u0430 \u043F\u0435\u0434\u0430\u0433\u043E\u0433\u0438\u043A\u0430 (\u043E\u0431\u0449\u043E) swissEduPersonStudyBranch3.3799=UAS\:\u041E\u0431\u0443\u0447\u0435\u043D\u0438\u0435 \u043D\u0430 \u0443\u0447\u0438\u0442\u0435\u043B\u0438 (\u043E\u0431\u0449\u043E) swissEduPersonStudyBranch3.3801=UAS\:\u0410\u0440\u0445\u0438\u0442\u0435\u043A\u0442\u0443\u0440\u0430 @@ -466,7 +465,7 @@ swissEduPersonStudyLevel.31=\u0414\u043E\u043A\u0442\u043E\u0440\u0430\u0442 swissEduPersonStudyLevel.32=\u041F\u0440\u043E\u0434\u044A\u043B\u0436\u0430\u0432\u0430\u0449\u043E \u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435 swissEduPersonStudyLevel.33=\u0420\u0430\u0437\u0448\u0438\u0440\u0435\u043D\u043E \u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435 swissEduPersonStudyLevel.34=\u041C\u043E\u0434\u0443\u043B\u043D\u043E \u0440\u0430\u0437\u0448\u0438\u0440\u0435\u043D\u043E \u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435 -swissEduPersonStudyLevel.35=\u041F\u0440\u043E\u0444\u0435\u0441\u0438\u043E\u043D\u0430\u043B\u043D\u043E \u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435 +swissEduPersonStudyLevel.35=\u041F\u0440\u043E\u0444\u0435\u0441\u0438\u043E\u043D\u0430\u043B\u043D\u043E \u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435 swissEduPersonStudyLevel.39=\u0418\u043D\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043B\u043D\u043E \u043F\u0440\u043E\u0434\u044A\u043B\u0436\u0430\u0432\u0430\u0449\u043E \u043E\u0431\u0443\u0447\u0435\u043D\u0438\u0435 swissEduPersonUniqueID=\u041B\u0438\u0447\u0435\u043D \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u043E\u043D\u0435\u043D \u043D\u043E\u043C\u0435\u0440 \u043D\u0430 SwissEdu wayf.homesite=\u0423\u043D\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442 @@ -476,4 +475,3 @@ wayf.password.back=\u041D\u0430\u0437\u0430\u0434 \u043A\u044A\u043C \u0432\u043 wayf.password.text=\u0412\u0438\u0435 \u0437\u0430\u0431\u0440\u0430\u0432\u0438\u0445\u0442\u0435 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F\u0442\u0430 \u0437\u0430 \u0434\u043E\u0441\u0442\u044A\u043F \u043D\u0430 \u0432\u0430\u0448\u0430\u0442\u0430 \u0438\u043D\u0441\u0442\u0438\u0442\u0443\u0446\u0438\u044F. \u041C\u043E\u043B\u044F, \u0441\u0432\u044A\u0440\u0436\u0435\u0442\u0435 \u0441\u0435 \u0441\u044A\u0441 \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u0438\u044F \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440. wayf.pleasechoose=\u041C\u043E\u043B\u044F, \u0438\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0432\u0430\u0448\u0430\u0442\u0430 \u0438\u043D\u0441\u0442\u0438\u0442\u0443\u0446\u0438\u044F wayf.submit=\u0412\u043B\u0438\u0437\u0430\u043D\u0435 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430 -we.intro=\u0414\u043E\u0441\u0442\u0430\u0432\u0447\u0438\u043A\u044A\u0442 \u043D\u0430 \u0432\u0430\u0448\u0430\u0442\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0447\u043D\u043E\u0441\u0442 \u043D\u0435 \u0432\u043A\u043B\u044E\u0447\u0432\u0430 \u0438-\u043C\u0435\u0439\u043B \u0430\u0434\u0440\u0435\u0441. \u041C\u043E\u043B\u044F, \u043D\u0430\u043F\u0438\u0448\u0435\u0442\u0435 \u0438-\u043C\u0435\u0439\u043B \u0430\u0434\u0440\u0435\u0441. diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_de.properties index 45770f9f68e307f54ace36d827ec0394527738c4..e71e3fa2e373cdad9816e123851050945062cfdb 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_de.properties @@ -5,13 +5,13 @@ admin.ac.attribute.2=Shibboleth Attribut 2 admin.ac.url=Direktlink f\u00fcr SSO Zugang admin.ac.value.1=G\u00fcltige Werte f\u00fcr Attribut 1 admin.ac.value.2=G\u00fcltige Werte f\u00fcr Attribut 2 -admin.description=Die Shibboleth Basiskonfiguration muss in der OpenOLAT Konfigurationsdatei vorgenommen werden. Mittels des untenstehenden Formulars k\u00f6nnen Sie die optionale Autorisierung der Benutzer mitels Pr\u00fcfung von Shibboleth Attributen einschalten. Es k\u00f6nnen maximal zwei Attribute mit den jeweils zugelassenen Werten festgelegt werden. Eine Person gilt als Autorisiert wenn 1) die Person erfolgreich sich bei seinem IDP authentifizieren kann und 2) eines der beiden konfigurierten Attribute in der jeweiligen Werteliste gefunden werden kann. +admin.description=Die Shibboleth Basiskonfiguration muss in der OpenOLAT Konfigurationsdatei vorgenommen werden. Mittels des untenstehenden Formulars k\u00f6nnen Sie die optionale Autorisierung der Benutzer mitels Pr\u00fcfung von Shibboleth Attributen einschalten. Es k\u00f6nnen maximal zwei Attribute mit den jeweils zugelassenen Werten festgelegt werden. Eine Person gilt als Autorisiert wenn 1) die Person erfolgreich sich bei seinem IDP authentifizieren kann und 2) eines der beiden konfigurierten Attribute in der jeweiligen Werteliste gefunden werden kann. admin.menu.shibboleth=Shibboleth admin.menu.shibboleth.desc=Konfiguration Shibboleth Modul admin.title=Shibboleth auhorization authentication.provider.description=Sind Sie Mitglied einer Institution mit Shibboleth Loginverfahren? authentication.provider.linkText=Anmelden mit Shibboleth Konto - +auto.shib.method=Shibboleth @@ -31,7 +31,6 @@ eduPersonAffiliation.student=Student eduPersonEntitlement=Berechtigung eduPersonOrgUnitDN=Organisationsheinheit DN employeeNumber=Mitarbeiternummer -error.insufficieant.attributes=Erforderliche Shibboleth Attribute\: Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.not.authorized=Sie d\u00FCrfen nicht auf OpenOLAT einloggen. error.shibboleth.generic=Shibboleth Fehler. Melden Sie sich nochmals an\! error.shibboleth.head=OLAT - Online Learning And Training - Error @@ -116,375 +115,375 @@ swissEduPersonHomeOrganizationType.vho=Virtual Home Organization swissEduPersonStaffCategory=Mitarbeiterkategorie swissEduPersonStaffCategory.101=Teaching\: Professors swissEduPersonStaffCategory.102=Teaching\: Oberer Mittelbau -swissEduPersonStaffCategory.103=Teaching\: Unterer Mittelbau +swissEduPersonStaffCategory.103=Teaching\: Unterer Mittelbau swissEduPersonStaffCategory.201=Research\: Permanent Researchers Ordinary Professors -swissEduPersonStaffCategory.202=Research\: Oberer Mittelbau -swissEduPersonStaffCategory.203=Research\: Unterer Mittelbau +swissEduPersonStaffCategory.202=Research\: Oberer Mittelbau +swissEduPersonStaffCategory.203=Research\: Unterer Mittelbau swissEduPersonStaffCategory.301=Administrative Personnel swissEduPersonStaffCategory.302=Administrative Personnel\: Apprentices and Interns swissEduPersonStaffCategory.303=Technical Personnel swissEduPersonStaffCategory.304=Technical Personnel\: Apprentices and Interns swissEduPersonStaffCategory.305=Janitors, Building Managers swissEduPersonStaffCategory.306=Social and Wellness Personnel -swissEduPersonStaffCategory.307=Library Personnel -swissEduPersonStaffCategory.308=Safety Personnel Radiation, Firefighters, Guards +swissEduPersonStaffCategory.307=Library Personnel +swissEduPersonStaffCategory.308=Safety Personnel Radiation, Firefighters, Guards swissEduPersonStudyBranch1=Studienrichtung swissEduPersonStudyBranch1.1=U\:Geistes- + Sozialwiss. -swissEduPersonStudyBranch1.10000=FH\:Architektur, Bau- und Planungswesen -swissEduPersonStudyBranch1.110000=FH\:Angewandte Linguistik -swissEduPersonStudyBranch1.120000=FH\:Soziale Arbeit -swissEduPersonStudyBranch1.130000=FH\:Angewandte Psychologie -swissEduPersonStudyBranch1.140000=FH\:Gesundheit -swissEduPersonStudyBranch1.150000=FH\:Lehrkr\u00E4fteausbildung +swissEduPersonStudyBranch1.10000=FH\:Architektur, Bau- und Planungswesen +swissEduPersonStudyBranch1.110000=FH\:Angewandte Linguistik +swissEduPersonStudyBranch1.120000=FH\:Soziale Arbeit +swissEduPersonStudyBranch1.130000=FH\:Angewandte Psychologie +swissEduPersonStudyBranch1.140000=FH\:Gesundheit +swissEduPersonStudyBranch1.150000=FH\:Lehrkr\u00E4fteausbildung swissEduPersonStudyBranch1.2=U\:Wirtschaftswissenschaften -swissEduPersonStudyBranch1.20000=FH\:Technik und IT +swissEduPersonStudyBranch1.20000=FH\:Technik und IT swissEduPersonStudyBranch1.3=U\:Recht \t -swissEduPersonStudyBranch1.30000=FH\:Chemie und Life Sciences +swissEduPersonStudyBranch1.30000=FH\:Chemie und Life Sciences swissEduPersonStudyBranch1.4=U\:Exakte + Naturwiss. -swissEduPersonStudyBranch1.40000=FH\:Land- und Forstwirtschaft -swissEduPersonStudyBranch1.5=U\:Medizin + Pharmazie -swissEduPersonStudyBranch1.50000=FH\:Wirtschaft und Dienstleistungen +swissEduPersonStudyBranch1.40000=FH\:Land- und Forstwirtschaft +swissEduPersonStudyBranch1.5=U\:Medizin + Pharmazie +swissEduPersonStudyBranch1.50000=FH\:Wirtschaft und Dienstleistungen swissEduPersonStudyBranch1.6=U\:Technische Wissenschaften -swissEduPersonStudyBranch1.60000=FH\:Design +swissEduPersonStudyBranch1.60000=FH\:Design swissEduPersonStudyBranch1.7=U\:Interdisziplin\u00E4re + andere \t -swissEduPersonStudyBranch1.70000=FH\:Sport +swissEduPersonStudyBranch1.70000=FH\:Sport swissEduPersonStudyBranch1.8=U\:Zentralbereich -swissEduPersonStudyBranch1.80000=FH\:Musik, Theater und andere K\u00FCnste -swissEduPersonStudyBranch1.990000=FH\:Weiterbildung nicht zuteilbar +swissEduPersonStudyBranch1.80000=FH\:Musik, Theater und andere K\u00FCnste +swissEduPersonStudyBranch1.990000=FH\:Weiterbildung nicht zuteilbar swissEduPersonStudyBranch1.999000=FH\:Nicht zuteilbar swissEduPersonStudyBranch2=Studienrichtung 2 -swissEduPersonStudyBranch2.100101=FH\:Theaterschaffen in darstellenden K\u00FCnsten -swissEduPersonStudyBranch2.100201=FH\:Bewegungs-, Sprech- und Stimmerziehung -swissEduPersonStudyBranch2.100301=FH\:Szenelehrkr\u00E4fte -swissEduPersonStudyBranch2.100401=FH\:Spezialausbildungen in Theater -swissEduPersonStudyBranch2.100999=FH\:Theater allgemein -swissEduPersonStudyBranch2.10101=FH\:Architektur -swissEduPersonStudyBranch2.10102=FH\:Bauingenieurwesen -swissEduPersonStudyBranch2.10103=FH\:Bauprozessmanagement -swissEduPersonStudyBranch2.10104=FH\:Raumplanung -swissEduPersonStudyBranch2.10105=FH\:Landschaftsarchitektur -swissEduPersonStudyBranch2.10106=FH\:Geomatik -swissEduPersonStudyBranch2.10107=FH\:Holztechnik +swissEduPersonStudyBranch2.100101=FH\:Theaterschaffen in darstellenden K\u00FCnsten +swissEduPersonStudyBranch2.100201=FH\:Bewegungs-, Sprech- und Stimmerziehung +swissEduPersonStudyBranch2.100301=FH\:Szenelehrkr\u00E4fte +swissEduPersonStudyBranch2.100401=FH\:Spezialausbildungen in Theater +swissEduPersonStudyBranch2.100999=FH\:Theater allgemein +swissEduPersonStudyBranch2.10101=FH\:Architektur +swissEduPersonStudyBranch2.10102=FH\:Bauingenieurwesen +swissEduPersonStudyBranch2.10103=FH\:Bauprozessmanagement +swissEduPersonStudyBranch2.10104=FH\:Raumplanung +swissEduPersonStudyBranch2.10105=FH\:Landschaftsarchitektur +swissEduPersonStudyBranch2.10106=FH\:Geomatik +swissEduPersonStudyBranch2.10107=FH\:Holztechnik swissEduPersonStudyBranch2.10999=FH\:Weiterbildung im Bereich Architektur, Bau- und Planungswesen swissEduPersonStudyBranch2.11=U\:Theologie -swissEduPersonStudyBranch2.110199=FH\:\u00DCbersetzen -swissEduPersonStudyBranch2.110299=FH\:Dolmetschen -swissEduPersonStudyBranch2.110999=FH\:Angewandte Linguistik allgemein +swissEduPersonStudyBranch2.110199=FH\:\u00DCbersetzen +swissEduPersonStudyBranch2.110299=FH\:Dolmetschen +swissEduPersonStudyBranch2.110999=FH\:Angewandte Linguistik allgemein swissEduPersonStudyBranch2.12=U\:Sprach- + Literaturw. (SLW) -swissEduPersonStudyBranch2.120199=FH\:Sozialarbeit -swissEduPersonStudyBranch2.120299=FH\:Sozialp\u00E4dagogik -swissEduPersonStudyBranch2.120399=FH\:Soziokulturelle Animation -swissEduPersonStudyBranch2.120999=FH\:Allgemeine soziale Arbeit +swissEduPersonStudyBranch2.120199=FH\:Sozialarbeit +swissEduPersonStudyBranch2.120299=FH\:Sozialp\u00E4dagogik +swissEduPersonStudyBranch2.120399=FH\:Soziokulturelle Animation +swissEduPersonStudyBranch2.120999=FH\:Allgemeine soziale Arbeit swissEduPersonStudyBranch2.13=U\:Historische + Kulturw. -swissEduPersonStudyBranch2.130101=FH\:Psychologische Diagnostik und Beratung -swissEduPersonStudyBranch2.130102=FH\:Berufsberatung -swissEduPersonStudyBranch2.130103=FH\:Arbeits- und Organisationspsychologie -swissEduPersonStudyBranch2.130999=FH\:Angewandte Psychologie allgemein +swissEduPersonStudyBranch2.130101=FH\:Psychologische Diagnostik und Beratung +swissEduPersonStudyBranch2.130102=FH\:Berufsberatung +swissEduPersonStudyBranch2.130103=FH\:Arbeits- und Organisationspsychologie +swissEduPersonStudyBranch2.130999=FH\:Angewandte Psychologie allgemein swissEduPersonStudyBranch2.14=U\:Sozialwissenschaften -swissEduPersonStudyBranch2.140101=FH\:Pflege -swissEduPersonStudyBranch2.140102=FH\:Hebamme -swissEduPersonStudyBranch2.140199=FH\:Pflege + Gesundheitserziehung allgemein -swissEduPersonStudyBranch2.140201=FH\:Physiotherapie -swissEduPersonStudyBranch2.140202=FH\:Ergotherapie -swissEduPersonStudyBranch2.140203=FH\:Psychomotorische Therapie -swissEduPersonStudyBranch2.140204=FH\:Ern\u00E4hrungsberatung -swissEduPersonStudyBranch2.140299=FH\:Therapie und Rehabilitation allgemein -swissEduPersonStudyBranch2.140301=FH\:Medizinische Radiologie -swissEduPersonStudyBranch2.140399=FH\:Diagnostische/Therapeutische Technik allgemein -swissEduPersonStudyBranch2.140999=FH\:Gesundheit allgemein +swissEduPersonStudyBranch2.140101=FH\:Pflege +swissEduPersonStudyBranch2.140102=FH\:Hebamme +swissEduPersonStudyBranch2.140199=FH\:Pflege + Gesundheitserziehung allgemein +swissEduPersonStudyBranch2.140201=FH\:Physiotherapie +swissEduPersonStudyBranch2.140202=FH\:Ergotherapie +swissEduPersonStudyBranch2.140203=FH\:Psychomotorische Therapie +swissEduPersonStudyBranch2.140204=FH\:Ern\u00E4hrungsberatung +swissEduPersonStudyBranch2.140299=FH\:Therapie und Rehabilitation allgemein +swissEduPersonStudyBranch2.140301=FH\:Medizinische Radiologie +swissEduPersonStudyBranch2.140399=FH\:Diagnostische/Therapeutische Technik allgemein +swissEduPersonStudyBranch2.140999=FH\:Gesundheit allgemein swissEduPersonStudyBranch2.15=U\:Geist./Soz.w. f\u00E4cher\u00FCbergr./\u00FCbrige -swissEduPersonStudyBranch2.150101=FH\:Vorschul- und Primarstufe allgemein -swissEduPersonStudyBranch2.150201=FH\:Sekundarstufe I allgemein -swissEduPersonStudyBranch2.150301=FH\:Sekundarstufe II allgemein (Maturit\u00E4tsschulen) -swissEduPersonStudyBranch2.150302=FH\:Sekundarstufe II allgemein (Berufsbildung) -swissEduPersonStudyBranch2.150401=FH\:Logop\u00E4die -swissEduPersonStudyBranch2.150402=FH\:Psychomotorik -swissEduPersonStudyBranch2.150499=FH\:Heilp\u00E4dagogik allgemein -swissEduPersonStudyBranch2.150999=FH\:Lehrkr\u00E4fteausbildung allgemein -swissEduPersonStudyBranch2.20201=FH\:Elektrotechnik -swissEduPersonStudyBranch2.20202=FH\:Informatik -swissEduPersonStudyBranch2.20203=FH\:Telekommunikation -swissEduPersonStudyBranch2.20204=FH\:Mikrotechnik -swissEduPersonStudyBranch2.20205=FH\:Systemtechnik -swissEduPersonStudyBranch2.20206=FH\:Maschineningenieurwesen -swissEduPersonStudyBranch2.20207=FH\:Techn. Projektmanagement in Mechatronik -swissEduPersonStudyBranch2.20208=FH\:Automobiltechnik -swissEduPersonStudyBranch2.20209=FH\:Wirtschaftsingenieurwesen -swissEduPersonStudyBranch2.20210=FH\:Medieningenieurwesen -swissEduPersonStudyBranch2.20211=FH\:Geb\u00E4udetechnik -swissEduPersonStudyBranch2.20212=FH\:Ingenieur-Designer -swissEduPersonStudyBranch2.20213=FH\:Aviatik -swissEduPersonStudyBranch2.20214=FH\:Optometrie -swissEduPersonStudyBranch2.20999=FH\:Technik -swissEduPersonStudyBranch2.30301=FH\:Biotechnologie -swissEduPersonStudyBranch2.30302=FH\:Lebensmitteltechnologie -swissEduPersonStudyBranch2.30303=FH\:Life Technologies -swissEduPersonStudyBranch2.30304=FH\:Chemie -swissEduPersonStudyBranch2.30305=FH\:Oenologie -swissEduPersonStudyBranch2.30308=FH\:Umweltingenieurwesen -swissEduPersonStudyBranch2.30309=FH\:Molecular Life Sciences -swissEduPersonStudyBranch2.30310=FH\:Life Science Technologies -swissEduPersonStudyBranch2.30999=FH\:Weiterbildung im Bereich Chemie und Life Sciences -swissEduPersonStudyBranch2.40401=FH\:Landwirtschaft -swissEduPersonStudyBranch2.40402=FH\:Forstwirtschaft -swissEduPersonStudyBranch2.40999=FH\:Weiterbildung im Bereich Land- und Forstwirtschaft +swissEduPersonStudyBranch2.150101=FH\:Vorschul- und Primarstufe allgemein +swissEduPersonStudyBranch2.150201=FH\:Sekundarstufe I allgemein +swissEduPersonStudyBranch2.150301=FH\:Sekundarstufe II allgemein (Maturit\u00E4tsschulen) +swissEduPersonStudyBranch2.150302=FH\:Sekundarstufe II allgemein (Berufsbildung) +swissEduPersonStudyBranch2.150401=FH\:Logop\u00E4die +swissEduPersonStudyBranch2.150402=FH\:Psychomotorik +swissEduPersonStudyBranch2.150499=FH\:Heilp\u00E4dagogik allgemein +swissEduPersonStudyBranch2.150999=FH\:Lehrkr\u00E4fteausbildung allgemein +swissEduPersonStudyBranch2.20201=FH\:Elektrotechnik +swissEduPersonStudyBranch2.20202=FH\:Informatik +swissEduPersonStudyBranch2.20203=FH\:Telekommunikation +swissEduPersonStudyBranch2.20204=FH\:Mikrotechnik +swissEduPersonStudyBranch2.20205=FH\:Systemtechnik +swissEduPersonStudyBranch2.20206=FH\:Maschineningenieurwesen +swissEduPersonStudyBranch2.20207=FH\:Techn. Projektmanagement in Mechatronik +swissEduPersonStudyBranch2.20208=FH\:Automobiltechnik +swissEduPersonStudyBranch2.20209=FH\:Wirtschaftsingenieurwesen +swissEduPersonStudyBranch2.20210=FH\:Medieningenieurwesen +swissEduPersonStudyBranch2.20211=FH\:Geb\u00E4udetechnik +swissEduPersonStudyBranch2.20212=FH\:Ingenieur-Designer +swissEduPersonStudyBranch2.20213=FH\:Aviatik +swissEduPersonStudyBranch2.20214=FH\:Optometrie +swissEduPersonStudyBranch2.20999=FH\:Technik +swissEduPersonStudyBranch2.30301=FH\:Biotechnologie +swissEduPersonStudyBranch2.30302=FH\:Lebensmitteltechnologie +swissEduPersonStudyBranch2.30303=FH\:Life Technologies +swissEduPersonStudyBranch2.30304=FH\:Chemie +swissEduPersonStudyBranch2.30305=FH\:Oenologie +swissEduPersonStudyBranch2.30308=FH\:Umweltingenieurwesen +swissEduPersonStudyBranch2.30309=FH\:Molecular Life Sciences +swissEduPersonStudyBranch2.30310=FH\:Life Science Technologies +swissEduPersonStudyBranch2.30999=FH\:Weiterbildung im Bereich Chemie und Life Sciences +swissEduPersonStudyBranch2.40401=FH\:Landwirtschaft +swissEduPersonStudyBranch2.40402=FH\:Forstwirtschaft +swissEduPersonStudyBranch2.40999=FH\:Weiterbildung im Bereich Land- und Forstwirtschaft swissEduPersonStudyBranch2.41=U\:Exakte Wissenschaften swissEduPersonStudyBranch2.42=U\:Naturwissenschaften swissEduPersonStudyBranch2.43=U\:Exakte + Naturw., \u00FCbrige \tSci. -swissEduPersonStudyBranch2.50501=FH\:Betriebs\u00F6konomie -swissEduPersonStudyBranch2.50502=FH\:Europ\u00E4ischer Studiengang f\u00FCr Betriebswirtschaft -swissEduPersonStudyBranch2.50503=FH\:International Business Management -swissEduPersonStudyBranch2.50504=FH\:Wirtschaftsinformatik -swissEduPersonStudyBranch2.50505=FH\:Facility Management -swissEduPersonStudyBranch2.50506=FH\:Hotellerie -swissEduPersonStudyBranch2.50507=FH\:Tourismus -swissEduPersonStudyBranch2.50508=FH\:Information und Dokumentation -swissEduPersonStudyBranch2.50509=FH\:Kommunikation -swissEduPersonStudyBranch2.50510=FH\:Wirtschaftsrecht -swissEduPersonStudyBranch2.50999=FH\:Weiterbildung im Bereich Wirtschaft und Dienstleistungen +swissEduPersonStudyBranch2.50501=FH\:Betriebs\u00F6konomie +swissEduPersonStudyBranch2.50502=FH\:Europ\u00E4ischer Studiengang f\u00FCr Betriebswirtschaft +swissEduPersonStudyBranch2.50503=FH\:International Business Management +swissEduPersonStudyBranch2.50504=FH\:Wirtschaftsinformatik +swissEduPersonStudyBranch2.50505=FH\:Facility Management +swissEduPersonStudyBranch2.50506=FH\:Hotellerie +swissEduPersonStudyBranch2.50507=FH\:Tourismus +swissEduPersonStudyBranch2.50508=FH\:Information und Dokumentation +swissEduPersonStudyBranch2.50509=FH\:Kommunikation +swissEduPersonStudyBranch2.50510=FH\:Wirtschaftsrecht +swissEduPersonStudyBranch2.50999=FH\:Weiterbildung im Bereich Wirtschaft und Dienstleistungen swissEduPersonStudyBranch2.51=U\:Humanmedizin swissEduPersonStudyBranch2.52=U\:Zahnmedizin swissEduPersonStudyBranch2.53=U\:Veterin\u00E4rmedizin -swissEduPersonStudyBranch2.54=U\:Pharmazie -swissEduPersonStudyBranch2.55=U\:Medizin + Pharm. f\u00E4cher\u00FCb./\u00FCbrige -swissEduPersonStudyBranch2.60601=FH\:Visuelle Kommunikation -swissEduPersonStudyBranch2.60602=FH\:Hyperwerk -swissEduPersonStudyBranch2.60603=FH\:Produkte- und Industriedesign -swissEduPersonStudyBranch2.60604=FH\:Innenarchitektur -swissEduPersonStudyBranch2.60605=FH\:Konservierung-Restaurierung -swissEduPersonStudyBranch2.60606=FH\:Film -swissEduPersonStudyBranch2.60607=FH\:Filmrealisation -swissEduPersonStudyBranch2.60999=FH\:Weiterbildung im Bereich Design +swissEduPersonStudyBranch2.54=U\:Pharmazie +swissEduPersonStudyBranch2.55=U\:Medizin + Pharm. f\u00E4cher\u00FCb./\u00FCbrige +swissEduPersonStudyBranch2.60601=FH\:Visuelle Kommunikation +swissEduPersonStudyBranch2.60602=FH\:Hyperwerk +swissEduPersonStudyBranch2.60603=FH\:Produkte- und Industriedesign +swissEduPersonStudyBranch2.60604=FH\:Innenarchitektur +swissEduPersonStudyBranch2.60605=FH\:Konservierung-Restaurierung +swissEduPersonStudyBranch2.60606=FH\:Film +swissEduPersonStudyBranch2.60607=FH\:Filmrealisation +swissEduPersonStudyBranch2.60999=FH\:Weiterbildung im Bereich Design swissEduPersonStudyBranch2.61=U\:Bauwesen + Geod\u00E4sie -swissEduPersonStudyBranch2.62=U\:Maschinen- + Elektroingenieurw. +swissEduPersonStudyBranch2.62=U\:Maschinen- + Elektroingenieurw. swissEduPersonStudyBranch2.63=U\:Agrar- + Forstwissenschaften swissEduPersonStudyBranch2.64=U\:Techn. Wiss. F\u00E4cher\u00FCbergr./\u00FCbrige -swissEduPersonStudyBranch2.70701=FH\:Sport -swissEduPersonStudyBranch2.80199=FH\:Bildende Kunst allgemein -swissEduPersonStudyBranch2.80201=FH\:Bildnerisches Gestalten -swissEduPersonStudyBranch2.80202=FH\:Werklehrer/Werklehrerin -swissEduPersonStudyBranch2.80203=FH\:Aesthetische Erziehung -swissEduPersonStudyBranch2.80299=FH\:Lehrerbildung f\u00FCr Kunstf\u00E4cher allgemein -swissEduPersonStudyBranch2.80301=FH\:Literarisches Schreiben -swissEduPersonStudyBranch2.81=U\:Zentrale Verwaltung -swissEduPersonStudyBranch2.82=U\:Zentrale Bibliotheken +swissEduPersonStudyBranch2.70701=FH\:Sport +swissEduPersonStudyBranch2.80199=FH\:Bildende Kunst allgemein +swissEduPersonStudyBranch2.80201=FH\:Bildnerisches Gestalten +swissEduPersonStudyBranch2.80202=FH\:Werklehrer/Werklehrerin +swissEduPersonStudyBranch2.80203=FH\:Aesthetische Erziehung +swissEduPersonStudyBranch2.80299=FH\:Lehrerbildung f\u00FCr Kunstf\u00E4cher allgemein +swissEduPersonStudyBranch2.80301=FH\:Literarisches Schreiben +swissEduPersonStudyBranch2.81=U\:Zentrale Verwaltung +swissEduPersonStudyBranch2.82=U\:Zentrale Bibliotheken swissEduPersonStudyBranch2.83=U\:Technische Dienste und Logistik swissEduPersonStudyBranch2.84=U\:Dienstleistungen f\u00FCr Mitarbeitende und Studierende -swissEduPersonStudyBranch2.90101=FH\:Musikp\u00E4dagogik (instrumental und vokal) -swissEduPersonStudyBranch2.90201=FH\:Interpretation/Performance -swissEduPersonStudyBranch2.90301=FH\:Schul- und Kirchenmusik -swissEduPersonStudyBranch2.90401=FH\:Dirigieren -swissEduPersonStudyBranch2.90501=FH\:Spezialausbildungen in Musik -swissEduPersonStudyBranch2.90999=FH\:Musik allgemein +swissEduPersonStudyBranch2.90101=FH\:Musikp\u00E4dagogik (instrumental und vokal) +swissEduPersonStudyBranch2.90201=FH\:Interpretation/Performance +swissEduPersonStudyBranch2.90301=FH\:Schul- und Kirchenmusik +swissEduPersonStudyBranch2.90401=FH\:Dirigieren +swissEduPersonStudyBranch2.90501=FH\:Spezialausbildungen in Musik +swissEduPersonStudyBranch2.90999=FH\:Musik allgemein swissEduPersonStudyBranch2.999000=FH\:Nicht zuteilbar -swissEduPersonStudyBranch2.999999=FH\:Weiterbildung nicht zuteilbar +swissEduPersonStudyBranch2.999999=FH\:Weiterbildung nicht zuteilbar swissEduPersonStudyBranch3=Studienrichtung 3 -swissEduPersonStudyBranch3.1000=U\:Oekologie -swissEduPersonStudyBranch3.1100=U\:Geist./Sozialwiss., \u00FCbrige -swissEduPersonStudyBranch3.1190=U\:Lehrkr\u00E4fteausb. Sekundarstufe I (Phil. I) -swissEduPersonStudyBranch3.1201=U\:Theologie f\u00E4cher\u00FCbergr./\u00FCbrige -swissEduPersonStudyBranch3.1205=U\:Protestantische Theologie -swissEduPersonStudyBranch3.1210=U\:R\u00F6misch-katholische Theologie -swissEduPersonStudyBranch3.1215=U\:Christkatholische Theologie -swissEduPersonStudyBranch3.1300=U\:Philosophie -swissEduPersonStudyBranch3.1401=U\:SLW f\u00E4cher\u00FCbergr./\u00FCbrige -swissEduPersonStudyBranch3.1405=U\:Linguistik -swissEduPersonStudyBranch3.1410=U\:Deutsche SLW -swissEduPersonStudyBranch3.1415=U\:Franz\u00F6sische SLW -swissEduPersonStudyBranch3.1420=U\:Italienische SLW -swissEduPersonStudyBranch3.1425=U\:R\u00E4toromanische SLW -swissEduPersonStudyBranch3.1429=U\:Andere mod. Sprachen Europas -swissEduPersonStudyBranch3.1430=U\:Iberische SLW -swissEduPersonStudyBranch3.1431=U\:Neugriechische SLW -swissEduPersonStudyBranch3.1435=U\:Englische SLW -swissEduPersonStudyBranch3.1440=U\:Slawische SLW -swissEduPersonStudyBranch3.1445=U\:Nordische SLW -swissEduPersonStudyBranch3.1449=U\:Klass. Sprachen Europas -swissEduPersonStudyBranch3.1450=U\:Klass. SLW -swissEduPersonStudyBranch3.1454=U\:Andere nichteurop. Sprachen -swissEduPersonStudyBranch3.1455=U\:Asiatische SKW -swissEduPersonStudyBranch3.1460=U\:Vorderorientalische SKW -swissEduPersonStudyBranch3.1465=U\:Afrikanische SKW -swissEduPersonStudyBranch3.1470=U\:Dolmetschen + Uebersetzung -swissEduPersonStudyBranch3.1500=U\:Arch\u00E4ologie, Ur- + Fr\u00FChgesch. -swissEduPersonStudyBranch3.1600=U\:Geschichte -swissEduPersonStudyBranch3.1700=U\:Kunstgeschichte -swissEduPersonStudyBranch3.1800=U\:Musikwissenschaft -swissEduPersonStudyBranch3.1850=U\:Theater- + Filmwissenschaft -swissEduPersonStudyBranch3.1900=U\:Ethnologie + Volkskunde -swissEduPersonStudyBranch3.1990=U\:Hist. + Kulturwiss. f\u00E4cher\u00FCb./\u00FCbrige -swissEduPersonStudyBranch3.2000=U\:Psychologie -swissEduPersonStudyBranch3.2100=U\:Erziehungswissenschaften -swissEduPersonStudyBranch3.2120=U\:Sonderp\u00E4dagogik -swissEduPersonStudyBranch3.2130=U\:Sport -swissEduPersonStudyBranch3.2200=U\:Soziologie -swissEduPersonStudyBranch3.2205=U\:Sozialarbeit -swissEduPersonStudyBranch3.2300=U\:Politikwissenschaft -swissEduPersonStudyBranch3.2400=U\:Kommunikations- + Medienw. -swissEduPersonStudyBranch3.2450=U\:Sozialwiss. f\u00E4cher\u00FCbergr./\u00FCbrige -swissEduPersonStudyBranch3.2505=U\:Volkswirtschaftslehre -swissEduPersonStudyBranch3.2520=U\:Betriebswirtschaftslehre -swissEduPersonStudyBranch3.2530=U\:Betriebsinformatik -swissEduPersonStudyBranch3.2540=U\:Wirtschaftsw. f\u00E4cher\u00FCb./\u00FCbrige -swissEduPersonStudyBranch3.2600=U\:Recht +swissEduPersonStudyBranch3.1000=U\:Oekologie +swissEduPersonStudyBranch3.1100=U\:Geist./Sozialwiss., \u00FCbrige +swissEduPersonStudyBranch3.1190=U\:Lehrkr\u00E4fteausb. Sekundarstufe I (Phil. I) +swissEduPersonStudyBranch3.1201=U\:Theologie f\u00E4cher\u00FCbergr./\u00FCbrige +swissEduPersonStudyBranch3.1205=U\:Protestantische Theologie +swissEduPersonStudyBranch3.1210=U\:R\u00F6misch-katholische Theologie +swissEduPersonStudyBranch3.1215=U\:Christkatholische Theologie +swissEduPersonStudyBranch3.1300=U\:Philosophie +swissEduPersonStudyBranch3.1401=U\:SLW f\u00E4cher\u00FCbergr./\u00FCbrige +swissEduPersonStudyBranch3.1405=U\:Linguistik +swissEduPersonStudyBranch3.1410=U\:Deutsche SLW +swissEduPersonStudyBranch3.1415=U\:Franz\u00F6sische SLW +swissEduPersonStudyBranch3.1420=U\:Italienische SLW +swissEduPersonStudyBranch3.1425=U\:R\u00E4toromanische SLW +swissEduPersonStudyBranch3.1429=U\:Andere mod. Sprachen Europas +swissEduPersonStudyBranch3.1430=U\:Iberische SLW +swissEduPersonStudyBranch3.1431=U\:Neugriechische SLW +swissEduPersonStudyBranch3.1435=U\:Englische SLW +swissEduPersonStudyBranch3.1440=U\:Slawische SLW +swissEduPersonStudyBranch3.1445=U\:Nordische SLW +swissEduPersonStudyBranch3.1449=U\:Klass. Sprachen Europas +swissEduPersonStudyBranch3.1450=U\:Klass. SLW +swissEduPersonStudyBranch3.1454=U\:Andere nichteurop. Sprachen +swissEduPersonStudyBranch3.1455=U\:Asiatische SKW +swissEduPersonStudyBranch3.1460=U\:Vorderorientalische SKW +swissEduPersonStudyBranch3.1465=U\:Afrikanische SKW +swissEduPersonStudyBranch3.1470=U\:Dolmetschen + Uebersetzung +swissEduPersonStudyBranch3.1500=U\:Arch\u00E4ologie, Ur- + Fr\u00FChgesch. +swissEduPersonStudyBranch3.1600=U\:Geschichte +swissEduPersonStudyBranch3.1700=U\:Kunstgeschichte +swissEduPersonStudyBranch3.1800=U\:Musikwissenschaft +swissEduPersonStudyBranch3.1850=U\:Theater- + Filmwissenschaft +swissEduPersonStudyBranch3.1900=U\:Ethnologie + Volkskunde +swissEduPersonStudyBranch3.1990=U\:Hist. + Kulturwiss. f\u00E4cher\u00FCb./\u00FCbrige +swissEduPersonStudyBranch3.2000=U\:Psychologie +swissEduPersonStudyBranch3.2100=U\:Erziehungswissenschaften +swissEduPersonStudyBranch3.2120=U\:Sonderp\u00E4dagogik +swissEduPersonStudyBranch3.2130=U\:Sport +swissEduPersonStudyBranch3.2200=U\:Soziologie +swissEduPersonStudyBranch3.2205=U\:Sozialarbeit +swissEduPersonStudyBranch3.2300=U\:Politikwissenschaft +swissEduPersonStudyBranch3.2400=U\:Kommunikations- + Medienw. +swissEduPersonStudyBranch3.2450=U\:Sozialwiss. f\u00E4cher\u00FCbergr./\u00FCbrige +swissEduPersonStudyBranch3.2505=U\:Volkswirtschaftslehre +swissEduPersonStudyBranch3.2520=U\:Betriebswirtschaftslehre +swissEduPersonStudyBranch3.2530=U\:Betriebsinformatik +swissEduPersonStudyBranch3.2540=U\:Wirtschaftsw. f\u00E4cher\u00FCb./\u00FCbrige +swissEduPersonStudyBranch3.2600=U\:Recht swissEduPersonStudyBranch3.3099=FH\:Weiterbildung im Bereich Architektur, Bau- und Planungswesen swissEduPersonStudyBranch3.3200=FH\:Weiterbildung im Bereich Technik und IT -swissEduPersonStudyBranch3.3229=FH\:Weiterbildung im Bereich Chemie und Life Sciences +swissEduPersonStudyBranch3.3229=FH\:Weiterbildung im Bereich Chemie und Life Sciences swissEduPersonStudyBranch3.3299=FH\:Weiterbildung im Bereich Land- und Forstwirtschaft swissEduPersonStudyBranch3.3399=FH\:Weiterbildung im Bereich Wirtschaft und Dienstleistungen swissEduPersonStudyBranch3.3500=FH\:Weiterbildung im Bereich Design -swissEduPersonStudyBranch3.3529=FH\:Bildende Kunst allgemein -swissEduPersonStudyBranch3.3531=FH\:Bildnerisches Gestalten -swissEduPersonStudyBranch3.3532=FH\:Werklehrer/Werklehrerin -swissEduPersonStudyBranch3.3533=FH\:Aesthetische Erziehung -swissEduPersonStudyBranch3.3539=FH\:Lehrerbildung f\u00FCr Kunstf\u00E4cher allgemein -swissEduPersonStudyBranch3.3540=FH\:Literarisches Schreiben -swissEduPersonStudyBranch3.3551=FH\:Musikp\u00E4dagogik (instrumental und vokal) -swissEduPersonStudyBranch3.3552=FH\:Interpretation/Performance -swissEduPersonStudyBranch3.3553=FH\:Schul- und Kirchenmusik -swissEduPersonStudyBranch3.3554=FH\:Dirigieren -swissEduPersonStudyBranch3.3555=FH\:Spezialausbildungen in Musik -swissEduPersonStudyBranch3.3569=FH\:Musik allgemein -swissEduPersonStudyBranch3.3571=FH\:Theaterschaffen in darstellenden K\u00FCnsten -swissEduPersonStudyBranch3.3572=FH\:Bewegungs-, Sprech- und Stimmerziehung -swissEduPersonStudyBranch3.3573=FH\:Szenelehrkr\u00E4fte -swissEduPersonStudyBranch3.3574=FH\:Spezialausbildungen in Theater -swissEduPersonStudyBranch3.3579=FH\:Theater allgemein -swissEduPersonStudyBranch3.3589=FH\:\u00DCbersetzen -swissEduPersonStudyBranch3.3599=FH\:Dolmetschen -swissEduPersonStudyBranch3.3600=FH\:Angewandte Linguistik allgemein -swissEduPersonStudyBranch3.3609=FH\:Sozialarbeit -swissEduPersonStudyBranch3.3619=FH\:Sozialp\u00E4dagogik -swissEduPersonStudyBranch3.3629=FH\:Soziokulturelle Animation -swissEduPersonStudyBranch3.3639=FH\:Allgemeine soziale Arbeit -swissEduPersonStudyBranch3.3651=FH\:Psychologische Diagnostik und Beratung -swissEduPersonStudyBranch3.3652=FH\:Berufsberatung -swissEduPersonStudyBranch3.3653=FH\:Arbeits- und Organisationspsychologie -swissEduPersonStudyBranch3.3659=FH\:Angewandte Psychologie allgemein -swissEduPersonStudyBranch3.3661=FH\:Pflege -swissEduPersonStudyBranch3.3662=FH\:Hebamme -swissEduPersonStudyBranch3.3669=FH\:Pflege + Gesundheitserziehung allgemein -swissEduPersonStudyBranch3.3671=FH\:Physiotherapie -swissEduPersonStudyBranch3.3672=FH\:Ergotherapie -swissEduPersonStudyBranch3.3673=FH\:Psychomotorische Therapie -swissEduPersonStudyBranch3.3674=FH\:Ern\u00E4hrungsberatung -swissEduPersonStudyBranch3.3679=FH\:Therapie und Rehabilitation allgemein -swissEduPersonStudyBranch3.3681=FH\:Medizinische Radiologie -swissEduPersonStudyBranch3.3689=FH\:Diagnostische/Therapeutische Technik allgemein -swissEduPersonStudyBranch3.3699=FH\:Gesundheit allgemein -swissEduPersonStudyBranch3.3701=FH\:Vorschul- und Primarstufe allgemein -swissEduPersonStudyBranch3.3710=FH\:Sekundarstufe I allgemein -swissEduPersonStudyBranch3.3720=FH\:Sekundarstufe II allgemein (Maturit\u00E4tsschulen) -swissEduPersonStudyBranch3.3725=FH\:Sekundarstufe II allgemein (Berufsbildung) -swissEduPersonStudyBranch3.3730=FH\:Logop\u00E4die -swissEduPersonStudyBranch3.3731=FH\:Psychomotorik -swissEduPersonStudyBranch3.3739=FH\:Heilp\u00E4dagogik allgemein -swissEduPersonStudyBranch3.3799=FH\:Lehrkr\u00E4fteausbildung allgemein -swissEduPersonStudyBranch3.3801=FH\:Architektur -swissEduPersonStudyBranch3.3802=FH\:Bauingenieurwesen -swissEduPersonStudyBranch3.3803=FH\:Bauprozessmanagement -swissEduPersonStudyBranch3.3804=FH\:Raumplanung -swissEduPersonStudyBranch3.3805=FH\:Landschaftsarchitektur -swissEduPersonStudyBranch3.3806=FH\:Geomatik -swissEduPersonStudyBranch3.3807=FH\:Holztechnik -swissEduPersonStudyBranch3.3808=FH\:Elektrotechnik -swissEduPersonStudyBranch3.3809=FH\:Informatik -swissEduPersonStudyBranch3.3810=FH\:Telekommunikation -swissEduPersonStudyBranch3.3811=FH\:Mikrotechnik -swissEduPersonStudyBranch3.3812=FH\:Systemtechnik -swissEduPersonStudyBranch3.3813=FH\:Maschinentechnik -swissEduPersonStudyBranch3.3814=FH\:Techn. Projektmanagement in Mechatronik -swissEduPersonStudyBranch3.3815=FH\:Automobiltechnik -swissEduPersonStudyBranch3.3816=FH\:Wirtschaftsingenieurwesen -swissEduPersonStudyBranch3.3817=FH\:Medieningenieurwesen -swissEduPersonStudyBranch3.3818=FH\:Geb\u00E4udetechnik -swissEduPersonStudyBranch3.3819=FH\:Biotechnologie -swissEduPersonStudyBranch3.3820=FH\:Lebensmitteltechnologie -swissEduPersonStudyBranch3.3821=FH\:Life Technologies -swissEduPersonStudyBranch3.3822=FH\:Chemie -swissEduPersonStudyBranch3.3823=FH\:Oenologie -swissEduPersonStudyBranch3.3824=FH\:Landwirtschaft -swissEduPersonStudyBranch3.3825=FH\:Forstwirtschaft -swissEduPersonStudyBranch3.3826=FH\:Umweltingenieurwesen -swissEduPersonStudyBranch3.3827=FH\:Betriebs\u00F6konomie -swissEduPersonStudyBranch3.3828=FH\:Europ\u00E4ischer Studiengang f\u00FCr Betriebswirtschaft -swissEduPersonStudyBranch3.3829=FH\:International Business Management -swissEduPersonStudyBranch3.3830=FH\:Wirtschaftsinformatik -swissEduPersonStudyBranch3.3831=FH\:Facility Management -swissEduPersonStudyBranch3.3832=FH\:Hotellerie -swissEduPersonStudyBranch3.3833=FH\:Tourismus -swissEduPersonStudyBranch3.3834=FH\:Information und Dokumentation -swissEduPersonStudyBranch3.3835=FH\:Kommunikation -swissEduPersonStudyBranch3.3836=FH\:Visuelle Kommunikation -swissEduPersonStudyBranch3.3837=FH\:Hyperwerk -swissEduPersonStudyBranch3.3838=FH\:Produkt- und Industriedesign -swissEduPersonStudyBranch3.3839=FH\:Innenarchitektur -swissEduPersonStudyBranch3.3840=FH\:Konservierung-Restaurierung -swissEduPersonStudyBranch3.3841=FH\:Sport -swissEduPersonStudyBranch3.3842=FH\:Wirtschaftsrecht -swissEduPersonStudyBranch3.3843=FH\:Ingenieur-Designer -swissEduPersonStudyBranch3.3844=FH\:Aviatik -swissEduPersonStudyBranch3.3845=FH\:Optometrie -swissEduPersonStudyBranch3.3846=FH\:Molecular Life Sciences -swissEduPersonStudyBranch3.3847=FH\:Life Science Technologies -swissEduPersonStudyBranch3.3848=FH\:Film -swissEduPersonStudyBranch3.3849=FH\:Filmrealisation -swissEduPersonStudyBranch3.3999=FH\:Weiterbildung nicht zuteilbar -swissEduPersonStudyBranch3.4100=U\:Ex. + Naturw. f\u00E4cher\u00FCbergr./\u00FCbrige -swissEduPersonStudyBranch3.4103=U\:Lehrkr\u00E4fteausb. Sekundarstufe I (Phil. II) -swissEduPersonStudyBranch3.4200=U\:Mathematik -swissEduPersonStudyBranch3.4300=U\:Informatik -swissEduPersonStudyBranch3.4400=U\:Astronomie -swissEduPersonStudyBranch3.4500=U\:Physik -swissEduPersonStudyBranch3.4590=U\:Exakte Wiss. f\u00E4cher\u00FCbergr./\u00FCbrige -swissEduPersonStudyBranch3.4600=U\:Chemie -swissEduPersonStudyBranch3.4700=U\:Biologie -swissEduPersonStudyBranch3.4800=U\:Erdwissenschaften -swissEduPersonStudyBranch3.4900=U\:Geographie -swissEduPersonStudyBranch3.4905=U\:Humangeographie -swissEduPersonStudyBranch3.4990=U\:Naturwiss. f\u00E4cher\u00FCbergr./\u00FCbrige -swissEduPersonStudyBranch3.6100=U\:Medizin + Pharm. f\u00E4cher\u00FCb./\u00FCbrige -swissEduPersonStudyBranch3.6150=U\:Pflegewissenschaften -swissEduPersonStudyBranch3.6200=U\:Humanmedizin -swissEduPersonStudyBranch3.6300=U\:Zahnmedizin -swissEduPersonStudyBranch3.6400=U\:Veterin\u00E4rmedizin -swissEduPersonStudyBranch3.650=U\:Zentrale Bibliotheken -swissEduPersonStudyBranch3.6500=U\:Pharmazie -swissEduPersonStudyBranch3.660=U\:Technische Dienste und Logistik -swissEduPersonStudyBranch3.7100=U\:Techn. Wiss., \u00FCbrige -swissEduPersonStudyBranch3.7200=U\:Bauingenieurwesen -swissEduPersonStudyBranch3.7300=U\:Architektur + Planung -swissEduPersonStudyBranch3.7400=U\:Chemieingenieurwesen -swissEduPersonStudyBranch3.7450=U\:Mikrotechnik -swissEduPersonStudyBranch3.750=U\:Dienstleistungen f\u00FCr Mitarbeitende und Studierende -swissEduPersonStudyBranch3.7500=U\:Elektroingenieurwesen -swissEduPersonStudyBranch3.7550=U\:Kommunikationssysteme -swissEduPersonStudyBranch3.7600=U\:Maschineningenieurwesen -swissEduPersonStudyBranch3.7650=U\:Betriebs- + Produktionsw. -swissEduPersonStudyBranch3.7700=U\:Materialwissenschaften -swissEduPersonStudyBranch3.7800=U\:Kulturtechnik + Vermessung -swissEduPersonStudyBranch3.7905=U\:Forstwirtschaft -swissEduPersonStudyBranch3.7910=U\:Agrarwirtschaft -swissEduPersonStudyBranch3.7915=U\:Lebensmittelwissenschaft -swissEduPersonStudyBranch3.8000=U\:Milit\u00E4rwissenschaften -swissEduPersonStudyBranch3.850=U\:Zentrale Verwaltung -swissEduPersonStudyBranch3.9000=U\:Interdisziplin\u00E4re / interfakult\u00E4re -swissEduPersonStudyBranch3.9001=U\:Frauen- / Geschlechterforschung -swissEduPersonStudyBranch3.9002=U\:Interfakult\u00E4re Weiterbildung +swissEduPersonStudyBranch3.3529=FH\:Bildende Kunst allgemein +swissEduPersonStudyBranch3.3531=FH\:Bildnerisches Gestalten +swissEduPersonStudyBranch3.3532=FH\:Werklehrer/Werklehrerin +swissEduPersonStudyBranch3.3533=FH\:Aesthetische Erziehung +swissEduPersonStudyBranch3.3539=FH\:Lehrerbildung f\u00FCr Kunstf\u00E4cher allgemein +swissEduPersonStudyBranch3.3540=FH\:Literarisches Schreiben +swissEduPersonStudyBranch3.3551=FH\:Musikp\u00E4dagogik (instrumental und vokal) +swissEduPersonStudyBranch3.3552=FH\:Interpretation/Performance +swissEduPersonStudyBranch3.3553=FH\:Schul- und Kirchenmusik +swissEduPersonStudyBranch3.3554=FH\:Dirigieren +swissEduPersonStudyBranch3.3555=FH\:Spezialausbildungen in Musik +swissEduPersonStudyBranch3.3569=FH\:Musik allgemein +swissEduPersonStudyBranch3.3571=FH\:Theaterschaffen in darstellenden K\u00FCnsten +swissEduPersonStudyBranch3.3572=FH\:Bewegungs-, Sprech- und Stimmerziehung +swissEduPersonStudyBranch3.3573=FH\:Szenelehrkr\u00E4fte +swissEduPersonStudyBranch3.3574=FH\:Spezialausbildungen in Theater +swissEduPersonStudyBranch3.3579=FH\:Theater allgemein +swissEduPersonStudyBranch3.3589=FH\:\u00DCbersetzen +swissEduPersonStudyBranch3.3599=FH\:Dolmetschen +swissEduPersonStudyBranch3.3600=FH\:Angewandte Linguistik allgemein +swissEduPersonStudyBranch3.3609=FH\:Sozialarbeit +swissEduPersonStudyBranch3.3619=FH\:Sozialp\u00E4dagogik +swissEduPersonStudyBranch3.3629=FH\:Soziokulturelle Animation +swissEduPersonStudyBranch3.3639=FH\:Allgemeine soziale Arbeit +swissEduPersonStudyBranch3.3651=FH\:Psychologische Diagnostik und Beratung +swissEduPersonStudyBranch3.3652=FH\:Berufsberatung +swissEduPersonStudyBranch3.3653=FH\:Arbeits- und Organisationspsychologie +swissEduPersonStudyBranch3.3659=FH\:Angewandte Psychologie allgemein +swissEduPersonStudyBranch3.3661=FH\:Pflege +swissEduPersonStudyBranch3.3662=FH\:Hebamme +swissEduPersonStudyBranch3.3669=FH\:Pflege + Gesundheitserziehung allgemein +swissEduPersonStudyBranch3.3671=FH\:Physiotherapie +swissEduPersonStudyBranch3.3672=FH\:Ergotherapie +swissEduPersonStudyBranch3.3673=FH\:Psychomotorische Therapie +swissEduPersonStudyBranch3.3674=FH\:Ern\u00E4hrungsberatung +swissEduPersonStudyBranch3.3679=FH\:Therapie und Rehabilitation allgemein +swissEduPersonStudyBranch3.3681=FH\:Medizinische Radiologie +swissEduPersonStudyBranch3.3689=FH\:Diagnostische/Therapeutische Technik allgemein +swissEduPersonStudyBranch3.3699=FH\:Gesundheit allgemein +swissEduPersonStudyBranch3.3701=FH\:Vorschul- und Primarstufe allgemein +swissEduPersonStudyBranch3.3710=FH\:Sekundarstufe I allgemein +swissEduPersonStudyBranch3.3720=FH\:Sekundarstufe II allgemein (Maturit\u00E4tsschulen) +swissEduPersonStudyBranch3.3725=FH\:Sekundarstufe II allgemein (Berufsbildung) +swissEduPersonStudyBranch3.3730=FH\:Logop\u00E4die +swissEduPersonStudyBranch3.3731=FH\:Psychomotorik +swissEduPersonStudyBranch3.3739=FH\:Heilp\u00E4dagogik allgemein +swissEduPersonStudyBranch3.3799=FH\:Lehrkr\u00E4fteausbildung allgemein +swissEduPersonStudyBranch3.3801=FH\:Architektur +swissEduPersonStudyBranch3.3802=FH\:Bauingenieurwesen +swissEduPersonStudyBranch3.3803=FH\:Bauprozessmanagement +swissEduPersonStudyBranch3.3804=FH\:Raumplanung +swissEduPersonStudyBranch3.3805=FH\:Landschaftsarchitektur +swissEduPersonStudyBranch3.3806=FH\:Geomatik +swissEduPersonStudyBranch3.3807=FH\:Holztechnik +swissEduPersonStudyBranch3.3808=FH\:Elektrotechnik +swissEduPersonStudyBranch3.3809=FH\:Informatik +swissEduPersonStudyBranch3.3810=FH\:Telekommunikation +swissEduPersonStudyBranch3.3811=FH\:Mikrotechnik +swissEduPersonStudyBranch3.3812=FH\:Systemtechnik +swissEduPersonStudyBranch3.3813=FH\:Maschinentechnik +swissEduPersonStudyBranch3.3814=FH\:Techn. Projektmanagement in Mechatronik +swissEduPersonStudyBranch3.3815=FH\:Automobiltechnik +swissEduPersonStudyBranch3.3816=FH\:Wirtschaftsingenieurwesen +swissEduPersonStudyBranch3.3817=FH\:Medieningenieurwesen +swissEduPersonStudyBranch3.3818=FH\:Geb\u00E4udetechnik +swissEduPersonStudyBranch3.3819=FH\:Biotechnologie +swissEduPersonStudyBranch3.3820=FH\:Lebensmitteltechnologie +swissEduPersonStudyBranch3.3821=FH\:Life Technologies +swissEduPersonStudyBranch3.3822=FH\:Chemie +swissEduPersonStudyBranch3.3823=FH\:Oenologie +swissEduPersonStudyBranch3.3824=FH\:Landwirtschaft +swissEduPersonStudyBranch3.3825=FH\:Forstwirtschaft +swissEduPersonStudyBranch3.3826=FH\:Umweltingenieurwesen +swissEduPersonStudyBranch3.3827=FH\:Betriebs\u00F6konomie +swissEduPersonStudyBranch3.3828=FH\:Europ\u00E4ischer Studiengang f\u00FCr Betriebswirtschaft +swissEduPersonStudyBranch3.3829=FH\:International Business Management +swissEduPersonStudyBranch3.3830=FH\:Wirtschaftsinformatik +swissEduPersonStudyBranch3.3831=FH\:Facility Management +swissEduPersonStudyBranch3.3832=FH\:Hotellerie +swissEduPersonStudyBranch3.3833=FH\:Tourismus +swissEduPersonStudyBranch3.3834=FH\:Information und Dokumentation +swissEduPersonStudyBranch3.3835=FH\:Kommunikation +swissEduPersonStudyBranch3.3836=FH\:Visuelle Kommunikation +swissEduPersonStudyBranch3.3837=FH\:Hyperwerk +swissEduPersonStudyBranch3.3838=FH\:Produkt- und Industriedesign +swissEduPersonStudyBranch3.3839=FH\:Innenarchitektur +swissEduPersonStudyBranch3.3840=FH\:Konservierung-Restaurierung +swissEduPersonStudyBranch3.3841=FH\:Sport +swissEduPersonStudyBranch3.3842=FH\:Wirtschaftsrecht +swissEduPersonStudyBranch3.3843=FH\:Ingenieur-Designer +swissEduPersonStudyBranch3.3844=FH\:Aviatik +swissEduPersonStudyBranch3.3845=FH\:Optometrie +swissEduPersonStudyBranch3.3846=FH\:Molecular Life Sciences +swissEduPersonStudyBranch3.3847=FH\:Life Science Technologies +swissEduPersonStudyBranch3.3848=FH\:Film +swissEduPersonStudyBranch3.3849=FH\:Filmrealisation +swissEduPersonStudyBranch3.3999=FH\:Weiterbildung nicht zuteilbar +swissEduPersonStudyBranch3.4100=U\:Ex. + Naturw. f\u00E4cher\u00FCbergr./\u00FCbrige +swissEduPersonStudyBranch3.4103=U\:Lehrkr\u00E4fteausb. Sekundarstufe I (Phil. II) +swissEduPersonStudyBranch3.4200=U\:Mathematik +swissEduPersonStudyBranch3.4300=U\:Informatik +swissEduPersonStudyBranch3.4400=U\:Astronomie +swissEduPersonStudyBranch3.4500=U\:Physik +swissEduPersonStudyBranch3.4590=U\:Exakte Wiss. f\u00E4cher\u00FCbergr./\u00FCbrige +swissEduPersonStudyBranch3.4600=U\:Chemie +swissEduPersonStudyBranch3.4700=U\:Biologie +swissEduPersonStudyBranch3.4800=U\:Erdwissenschaften +swissEduPersonStudyBranch3.4900=U\:Geographie +swissEduPersonStudyBranch3.4905=U\:Humangeographie +swissEduPersonStudyBranch3.4990=U\:Naturwiss. f\u00E4cher\u00FCbergr./\u00FCbrige +swissEduPersonStudyBranch3.6100=U\:Medizin + Pharm. f\u00E4cher\u00FCb./\u00FCbrige +swissEduPersonStudyBranch3.6150=U\:Pflegewissenschaften +swissEduPersonStudyBranch3.6200=U\:Humanmedizin +swissEduPersonStudyBranch3.6300=U\:Zahnmedizin +swissEduPersonStudyBranch3.6400=U\:Veterin\u00E4rmedizin +swissEduPersonStudyBranch3.650=U\:Zentrale Bibliotheken +swissEduPersonStudyBranch3.6500=U\:Pharmazie +swissEduPersonStudyBranch3.660=U\:Technische Dienste und Logistik +swissEduPersonStudyBranch3.7100=U\:Techn. Wiss., \u00FCbrige +swissEduPersonStudyBranch3.7200=U\:Bauingenieurwesen +swissEduPersonStudyBranch3.7300=U\:Architektur + Planung +swissEduPersonStudyBranch3.7400=U\:Chemieingenieurwesen +swissEduPersonStudyBranch3.7450=U\:Mikrotechnik +swissEduPersonStudyBranch3.750=U\:Dienstleistungen f\u00FCr Mitarbeitende und Studierende +swissEduPersonStudyBranch3.7500=U\:Elektroingenieurwesen +swissEduPersonStudyBranch3.7550=U\:Kommunikationssysteme +swissEduPersonStudyBranch3.7600=U\:Maschineningenieurwesen +swissEduPersonStudyBranch3.7650=U\:Betriebs- + Produktionsw. +swissEduPersonStudyBranch3.7700=U\:Materialwissenschaften +swissEduPersonStudyBranch3.7800=U\:Kulturtechnik + Vermessung +swissEduPersonStudyBranch3.7905=U\:Forstwirtschaft +swissEduPersonStudyBranch3.7910=U\:Agrarwirtschaft +swissEduPersonStudyBranch3.7915=U\:Lebensmittelwissenschaft +swissEduPersonStudyBranch3.8000=U\:Milit\u00E4rwissenschaften +swissEduPersonStudyBranch3.850=U\:Zentrale Verwaltung +swissEduPersonStudyBranch3.9000=U\:Interdisziplin\u00E4re / interfakult\u00E4re +swissEduPersonStudyBranch3.9001=U\:Frauen- / Geschlechterforschung +swissEduPersonStudyBranch3.9002=U\:Interfakult\u00E4re Weiterbildung swissEduPersonStudyBranch3.9999=FH\:Nicht zuteilbar swissEduPersonStudyLevel=Studienfortschritt -swissEduPersonStudyLevel.00=Vorbereitungs- oder Fortbildungskurs, Gaststudierende -swissEduPersonStudyLevel.10=Lizentiats- oder Diplomstudium -swissEduPersonStudyLevel.15=Bachelor-Studium -swissEduPersonStudyLevel.20=Zweite Studienh\u00E4lfte -swissEduPersonStudyLevel.25=Master-Studium mit Bachelor -swissEduPersonStudyLevel.26=Master-Studium ohne Bachelor -swissEduPersonStudyLevel.31=Doktoratsstudium -swissEduPersonStudyLevel.32=Nachdiplomstudium -swissEduPersonStudyLevel.33=Weiterbildung -swissEduPersonStudyLevel.34=Modulare Weiterbildung -swissEduPersonStudyLevel.35=Universit\u00E4re Aufbau- und Vertiefungsstudien -swissEduPersonStudyLevel.39=Individuelles Nachdiplomstudium, Weiterbildung +swissEduPersonStudyLevel.00=Vorbereitungs- oder Fortbildungskurs, Gaststudierende +swissEduPersonStudyLevel.10=Lizentiats- oder Diplomstudium +swissEduPersonStudyLevel.15=Bachelor-Studium +swissEduPersonStudyLevel.20=Zweite Studienh\u00E4lfte +swissEduPersonStudyLevel.25=Master-Studium mit Bachelor +swissEduPersonStudyLevel.26=Master-Studium ohne Bachelor +swissEduPersonStudyLevel.31=Doktoratsstudium +swissEduPersonStudyLevel.32=Nachdiplomstudium +swissEduPersonStudyLevel.33=Weiterbildung +swissEduPersonStudyLevel.34=Modulare Weiterbildung +swissEduPersonStudyLevel.35=Universit\u00E4re Aufbau- und Vertiefungsstudien +swissEduPersonStudyLevel.39=Individuelles Nachdiplomstudium, Weiterbildung swissEduPersonUniqueID=SwissEdu Person-ID wayf.homesite=Hochschule wayf.intro=Bitte w\u00E4hlen Sie Ihre Hochschule. <br>F\u00FCr die Authentifizierung werden Sie weitergeleitet. @@ -493,4 +492,4 @@ wayf.password.back=Zur\u00FCck zum Login wayf.password.text=Sie haben die Zugangsdaten f\u00FCr Ihre Hochschule vergessen. Kontaktieren Sie bitte die entsprechende Stelle an Ihrer Hochschule. wayf.pleasechoose=Bitte w\u00E4hlen Sie Ihre Hochschule... wayf.submit=Login -we.intro=Ihr Identity Provider liefert keine E-Mail-Adresse mit. Bitte geben Sie Ihre E-Mail-Adresse an. +we.intro=Bitte vervollst\u00E4ndigen Sie Ihre Benutzerangaben. diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_el.properties index 566e9d7d7495b40721eaa5ab8b3296a0496deb8d..ec33b868ddd8f987152eba32c252027f163aec52 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_el.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_el.properties @@ -15,7 +15,6 @@ eduPersonAffiliation.student=\u03A6\u03BF\u03B9\u03C4\u03B7\u03C4\u03AE\u03C2 eduPersonEntitlement=\u0395\u03BE\u03BF\u03C5\u03C3\u03B9\u03BF\u03B4\u03CC\u03C4\u03B7\u03C3\u03B7 eduPersonOrgUnitDN=\u039C\u03BF\u03BD\u03AC\u03B4\u03B1 \u03BF\u03C1\u03B3\u03AC\u03BD\u03C9\u03C3\u03B7\u03C2 DN employeeNumber=\u0391\u03C1\u03B9\u03B8\u03BC\u03CC\u03C2 \u03C4\u03B1\u03C5\u03C4\u03BF\u03C0\u03BF\u03AF\u03B7\u03C3\u03B7\u03C2 \u03C5\u03C0\u03B1\u03BB\u03BB\u03AE\u03BB\u03BF\u03C5 -error.insufficieant.attributes=\u03A5\u03C0\u03BF\u03C7\u03C1\u03B5\u03C9\u03C4\u03B9\u03BA\u03AC \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03B7\u03C1\u03B9\u03C3\u03C4\u03B9\u03BA\u03AC Shibboleth\:Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.generic=\u03A0\u03B1\u03C1\u03BF\u03C5\u03C3\u03B9\u03AC\u03C3\u03C4\u03B7\u03BA\u03B5 \u03C3\u03C6\u03AC\u03BB\u03BC\u03B1 \u03C3\u03C4\u03BF Shibboleth. \u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B5\u03B9\u03C3\u03B1\u03C7\u03B8\u03B5\u03AF\u03C4\u03B5 \u03B1\u03C1\u03B3\u03CC\u03C4\u03B5\u03C1\u03B1\! error.shibboleth.head=OLAT - Online Learning And Training - \u03A3\u03C6\u03AC\u03BB\u03BC\u03B1 error.unqueid.notfound=\u0388\u03C7\u03B5\u03C4\u03B5 \u03C0\u03C1\u03B1\u03B3\u03BC\u03B1\u03C4\u03B9\u03BA\u03AC \u03C4\u03B7 \u03B4\u03B9\u03BA\u03B1\u03B9\u03BF\u03B4\u03BF\u03C3\u03AF\u03B1 \u03BD\u03B1 \u03AD\u03C7\u03B5\u03C4\u03B5 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7 \u03C3\u03C4\u03BF OLAT; \u0391\u03BD \u03BD\u03B1\u03B9, \u03C0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B5\u03B9\u03C3\u03B1\u03C7\u03B8\u03B5\u03AF\u03C4\u03B5 \u03B1\u03C1\u03B3\u03CC\u03C4\u03B5\u03C1\u03B1. @@ -110,4 +109,3 @@ wayf.password.back=\u03A0\u03AF\u03C3\u03C9 \u03C3\u03C4\u03B7 \u03C3\u03CD\u03B wayf.password.text=\u039E\u03B5\u03C7\u03AC\u03C3\u03B1\u03C4\u03B5 \u03C4\u03B9\u03C2 \u03C0\u03BB\u03B7\u03C1\u03BF\u03C6\u03BF\u03C1\u03AF\u03B5\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03AE\u03C2 \u03C3\u03C4\u03BF \u03C0\u03B1\u03BD\u03B5\u03C0\u03B9\u03C3\u03C4\u03AE\u03BC\u03B9\u03CC \u03C3\u03B1\u03C2. \u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B5\u03C0\u03B9\u03BA\u03BF\u03B9\u03BD\u03C9\u03BD\u03AE\u03C3\u03C4\u03B5 \u03BC\u03B5 \u03C4\u03BF \u03C3\u03C7\u03B5\u03C4\u03B9\u03BA\u03CC \u03C4\u03BC\u03AE\u03BC\u03B1 \u03C4\u03BF\u03C5 \u03C0\u03B1\u03BD\u03B5\u03C0\u03B9\u03C3\u03C4\u03B7\u03BC\u03AF\u03BF\u03C5 \u03C3\u03B1\u03C2. wayf.pleasechoose=\u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B5\u03C0\u03B9\u03BB\u03AD\u03BE\u03C4\u03B5 \u03C0\u03B1\u03BD\u03B5\u03C0\u03B9\u03C3\u03C4\u03AE\u03BC\u03B9\u03BF\u2026 wayf.submit=\u0395\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2 -we.intro=\u039F \u03C6\u03BF\u03C1\u03AD\u03B1\u03C2 \u03C4\u03B1\u03C5\u03C4\u03BF\u03C0\u03BF\u03AF\u03B7\u03C3\u03B7\u03C2 \u03C3\u03B1\u03C2 \u03B4\u03B5\u03BD \u03C0\u03B5\u03C1\u03B9\u03BB\u03B1\u03BC\u03B2\u03AC\u03BD\u03B5\u03B9 \u03B4\u03B9\u03B5\u03CD\u03B8\u03C5\u03BD\u03C3\u03B7 e-mail. \u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B4\u03B9\u03B5\u03C5\u03BA\u03C1\u03B9\u03BD\u03AF\u03C3\u03C4\u03B5 \u03C4\u03B7\u03BD e-mail \u03B4\u03B9\u03B5\u03CD\u03B8\u03C5\u03BD\u03C3\u03AE \u03C3\u03B1\u03C2. diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_en.properties index e54b927c83f7c6bf6ed7a2e6e8a37e5ec570b8c7..9fce210c9cd92a716ea95a2afa0f1ddcdbc29dc6 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_en.properties @@ -11,7 +11,7 @@ admin.menu.shibboleth.desc=Configuration Shibboleth module admin.title=Shibboleth auhorization authentication.provider.description=Are you a member of an institutions that uses Shibboleth authentication? authentication.provider.linkText=Login with Shibboleth account - +auto.shib.method=Shibboleth @@ -31,9 +31,8 @@ eduPersonAffiliation.student=Student eduPersonEntitlement=Authorization eduPersonOrgUnitDN=Organization unit DN employeeNumber=Employee identification number -error.insufficieant.attributes=Mandatory Shibboleth attributes\: Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.not.authorized=You are not authorized to log in OpenOLAT. -error.shibboleth.generic=A Shibboleth error occured. Please log in again\! +error.shibboleth.generic=A Shibboleth error occurred. Please log in again\! error.shibboleth.head=OLAT - Online Learning And Training - Error error.unqueid.notfound=Are you really entitled to access OLAT? If so, please log in again. givenName=Last name @@ -56,7 +55,7 @@ sr.error.disclaimer=You have to accept the terms of use in order to finish this sr.error.emailexists=A user with this e-mail address already exists. Please contact {0}. sr.error.loginexists=User name already exists. <br>If you have registered using this name in OLAT before, please get in touch with {0}. sr.header=Registration -sr.intro=Please choose a user name to work with OLAT. <b>Attention\:</b> This name cannot be changed afterwards\! +sr.intro=Please choose a user name to work with OLAT. <b>Attention\:</b> This name cannot be changed afterwards\! sr.login.meantimetaken=This user name is already in use. Please choose another one. sr.select_language=Please select a language for your OLAT registration and user account. Later you can still adapt your language in your user profile. You will then be guided through the registration process. srf.email=E-mail address @@ -106,8 +105,8 @@ swissEduPersonHomeOrganization.vho-switchaai.ch=Virtual Home Organization @SWITC swissEduPersonHomeOrganization.zhbluzern.ch=Zentral- und Hochschulbibliothek Luzern swissEduPersonHomeOrganization.zhdk.ch=ZHdK - Zurich University of the Arts swissEduPersonHomeOrganization.zhwin.ch=Zurich University of Applied Sciences -swissEduPersonHomeOrganizationType=Type of organization -swissEduPersonHomeOrganizationType.hospital=Hospital +swissEduPersonHomeOrganizationType=Type of organization +swissEduPersonHomeOrganizationType.hospital=Hospital swissEduPersonHomeOrganizationType.library=Library swissEduPersonHomeOrganizationType.others=Other swissEduPersonHomeOrganizationType.uas=University of Applied Sciences @@ -118,214 +117,214 @@ swissEduPersonStaffCategory.101=Teaching\: Professors swissEduPersonStaffCategory.102=Teaching\: Assistant professors swissEduPersonStaffCategory.103=Teaching\: Ph.D. students swissEduPersonStaffCategory.201=Research\: Permanent researchers, ordinary professors -swissEduPersonStaffCategory.202=Research\: Assistant professors -swissEduPersonStaffCategory.203=Research\: Ph.D. students +swissEduPersonStaffCategory.202=Research\: Assistant professors +swissEduPersonStaffCategory.203=Research\: Ph.D. students swissEduPersonStaffCategory.301=Administrative personnel swissEduPersonStaffCategory.302=Administrative personnel\: Apprentices and interns swissEduPersonStaffCategory.303=Technical personnel swissEduPersonStaffCategory.304=Technical personnel\: Apprentices and interns swissEduPersonStaffCategory.305=Janitors, building managers swissEduPersonStaffCategory.306=Social and wellness personnel -swissEduPersonStaffCategory.307=Library personnel -swissEduPersonStaffCategory.308=Safety personnel, radiation, firefighters, guards +swissEduPersonStaffCategory.307=Library personnel +swissEduPersonStaffCategory.308=Safety personnel, radiation, firefighters, guards swissEduPersonStudyBranch1=Field of study swissEduPersonStudyBranch1.1=U\:Humanities and social science swissEduPersonStudyBranch1.10000=UAS\:Architecture, building, and planning swissEduPersonStudyBranch1.110000=UAS\:Applied linguistics swissEduPersonStudyBranch1.120000=UAS\:Social work -swissEduPersonStudyBranch1.130000=UAS\:Applied psychology +swissEduPersonStudyBranch1.130000=UAS\:Applied psychology swissEduPersonStudyBranch1.140000=UAS\:Health -swissEduPersonStudyBranch1.150000=UAS\:Educational science +swissEduPersonStudyBranch1.150000=UAS\:Educational science swissEduPersonStudyBranch1.2=U\:Economics swissEduPersonStudyBranch1.20000=UAS\:Engineering and IT swissEduPersonStudyBranch1.3=U\:Law -swissEduPersonStudyBranch1.30000=UAS\:Chemistry and Life Sciences +swissEduPersonStudyBranch1.30000=UAS\:Chemistry and Life Sciences swissEduPersonStudyBranch1.4=U\:Natural sciences -swissEduPersonStudyBranch1.40000=UAS\:Agriculture and forestry -swissEduPersonStudyBranch1.5=U\:Medical science and pharmaceutics -swissEduPersonStudyBranch1.50000=UAS\:Economy and services +swissEduPersonStudyBranch1.40000=UAS\:Agriculture and forestry +swissEduPersonStudyBranch1.5=U\:Medical science and pharmaceutics +swissEduPersonStudyBranch1.50000=UAS\:Economy and services swissEduPersonStudyBranch1.6=U\:Technical sciences -swissEduPersonStudyBranch1.60000=UAS\:Design +swissEduPersonStudyBranch1.60000=UAS\:Design swissEduPersonStudyBranch1.7=U\:Interdisciplinary sciences and others -swissEduPersonStudyBranch1.70000=UAS\:Sports +swissEduPersonStudyBranch1.70000=UAS\:Sports swissEduPersonStudyBranch1.8=U\:Central services -swissEduPersonStudyBranch1.80000=UAS\:Music, theater, arts -swissEduPersonStudyBranch1.990000=UAS\:Other +swissEduPersonStudyBranch1.80000=UAS\:Music, theater, arts +swissEduPersonStudyBranch1.990000=UAS\:Other swissEduPersonStudyBranch1.999000=UAS\:Other swissEduPersonStudyBranch2=Field of study 2 -swissEduPersonStudyBranch2.100101=UAS\:Theater (performing arts) -swissEduPersonStudyBranch2.100201=UAS\:Speech training, physical and vocal education -swissEduPersonStudyBranch2.100301=UAS\:Scenic education -swissEduPersonStudyBranch2.100401=UAS\:Special training (theater) +swissEduPersonStudyBranch2.100101=UAS\:Theater (performing arts) +swissEduPersonStudyBranch2.100201=UAS\:Speech training, physical and vocal education +swissEduPersonStudyBranch2.100301=UAS\:Scenic education +swissEduPersonStudyBranch2.100401=UAS\:Special training (theater) swissEduPersonStudyBranch2.100999=UAS\:Theater in general -swissEduPersonStudyBranch2.10101=UAS\:Architecture -swissEduPersonStudyBranch2.10102=UAS\:Civil engineering -swissEduPersonStudyBranch2.10103=UAS\:Management of civil engineering -swissEduPersonStudyBranch2.10104=UAS\:Urban and regional planning -swissEduPersonStudyBranch2.10105=UAS\:Landscaping -swissEduPersonStudyBranch2.10106=UAS\:Geomatics -swissEduPersonStudyBranch2.10107=UAS\:Wood technology +swissEduPersonStudyBranch2.10101=UAS\:Architecture +swissEduPersonStudyBranch2.10102=UAS\:Civil engineering +swissEduPersonStudyBranch2.10103=UAS\:Management of civil engineering +swissEduPersonStudyBranch2.10104=UAS\:Urban and regional planning +swissEduPersonStudyBranch2.10105=UAS\:Landscaping +swissEduPersonStudyBranch2.10106=UAS\:Geomatics +swissEduPersonStudyBranch2.10107=UAS\:Wood technology swissEduPersonStudyBranch2.10999=UAS\:Advanced training (architecture, civil engineering, zoning) swissEduPersonStudyBranch2.11=U\:Theology swissEduPersonStudyBranch2.110199=UAS\:Translation swissEduPersonStudyBranch2.110299=UAS\:Interpreting -swissEduPersonStudyBranch2.110999=UAS\:Applied linguistics in general +swissEduPersonStudyBranch2.110999=UAS\:Applied linguistics in general swissEduPersonStudyBranch2.12=U\:Languages -swissEduPersonStudyBranch2.120199=UAS\:Social work -swissEduPersonStudyBranch2.120299=UAS\:Social pedagogy -swissEduPersonStudyBranch2.120399=UAS\:Sociocultural animation -swissEduPersonStudyBranch2.120999=UAS\:General social work +swissEduPersonStudyBranch2.120199=UAS\:Social work +swissEduPersonStudyBranch2.120299=UAS\:Social pedagogy +swissEduPersonStudyBranch2.120399=UAS\:Sociocultural animation +swissEduPersonStudyBranch2.120999=UAS\:General social work swissEduPersonStudyBranch2.13=U\:History and cultural sciences -swissEduPersonStudyBranch2.130101=UAS\:Psychological diagnostics and counseling -swissEduPersonStudyBranch2.130102=UAS\:Career counseling -swissEduPersonStudyBranch2.130103=UAS\:Industrial and organizational psychology -swissEduPersonStudyBranch2.130999=UAS\:Applied psychology in general +swissEduPersonStudyBranch2.130101=UAS\:Psychological diagnostics and counseling +swissEduPersonStudyBranch2.130102=UAS\:Career counseling +swissEduPersonStudyBranch2.130103=UAS\:Industrial and organizational psychology +swissEduPersonStudyBranch2.130999=UAS\:Applied psychology in general swissEduPersonStudyBranch2.14=U\:Social sciences swissEduPersonStudyBranch2.140101=UAS\:Care swissEduPersonStudyBranch2.140102=UAS\:Midwife -swissEduPersonStudyBranch2.140199=UAS\:Health and care education in general -swissEduPersonStudyBranch2.140201=UAS\:Physiotherapy -swissEduPersonStudyBranch2.140202=UAS\:Ergotherapy -swissEduPersonStudyBranch2.140203=UAS\:Psychomotoric therapy -swissEduPersonStudyBranch2.140204=UAS\:Nutritional advice -swissEduPersonStudyBranch2.140299=UAS\:Therapy and rehabilitation in general -swissEduPersonStudyBranch2.140301=UAS\:Medical radiology -swissEduPersonStudyBranch2.140399=UAS\:Diagnostic/therapeutic technology in general -swissEduPersonStudyBranch2.140999=UAS\:Health in general +swissEduPersonStudyBranch2.140199=UAS\:Health and care education in general +swissEduPersonStudyBranch2.140201=UAS\:Physiotherapy +swissEduPersonStudyBranch2.140202=UAS\:Ergotherapy +swissEduPersonStudyBranch2.140203=UAS\:Psychomotoric therapy +swissEduPersonStudyBranch2.140204=UAS\:Nutritional advice +swissEduPersonStudyBranch2.140299=UAS\:Therapy and rehabilitation in general +swissEduPersonStudyBranch2.140301=UAS\:Medical radiology +swissEduPersonStudyBranch2.140399=UAS\:Diagnostic/therapeutic technology in general +swissEduPersonStudyBranch2.140999=UAS\:Health in general swissEduPersonStudyBranch2.15=U\:Humanities, social sciences and others -swissEduPersonStudyBranch2.150101=UAS\:Preschool and primary school in general +swissEduPersonStudyBranch2.150101=UAS\:Preschool and primary school in general swissEduPersonStudyBranch2.150201=UAS\:Secondary school I in general -swissEduPersonStudyBranch2.150301=UAS\:Secondary school II in general (diploma) -swissEduPersonStudyBranch2.150302=UAS\:Secondary school II in general (training) -swissEduPersonStudyBranch2.150401=UAS\:Logopedics +swissEduPersonStudyBranch2.150301=UAS\:Secondary school II in general (diploma) +swissEduPersonStudyBranch2.150302=UAS\:Secondary school II in general (training) +swissEduPersonStudyBranch2.150401=UAS\:Logopedics swissEduPersonStudyBranch2.150402=UAS\:Psychomotricity -swissEduPersonStudyBranch2.150499=UAS\:Therapeutic pedagogy in general -swissEduPersonStudyBranch2.150999=UAS\:Teacher-training in general -swissEduPersonStudyBranch2.20201=UAS\:Electrical engineering -swissEduPersonStudyBranch2.20202=UAS\:Computer sciences -swissEduPersonStudyBranch2.20203=UAS\:Telecommunications -swissEduPersonStudyBranch2.20204=UAS\:Microtechnology -swissEduPersonStudyBranch2.20205=UAS\:Systems engineering -swissEduPersonStudyBranch2.20206=UAS\:Mechanical engineering -swissEduPersonStudyBranch2.20207=UAS\:Technical project management (mechatronics) -swissEduPersonStudyBranch2.20208=UAS\:Automotive engineering -swissEduPersonStudyBranch2.20209=UAS\:Industrial engineering -swissEduPersonStudyBranch2.20210=UAS\:Media engineering -swissEduPersonStudyBranch2.20211=UAS\:Building services engineering -swissEduPersonStudyBranch2.20212=UAS\:Engineering design +swissEduPersonStudyBranch2.150499=UAS\:Therapeutic pedagogy in general +swissEduPersonStudyBranch2.150999=UAS\:Teacher-training in general +swissEduPersonStudyBranch2.20201=UAS\:Electrical engineering +swissEduPersonStudyBranch2.20202=UAS\:Computer sciences +swissEduPersonStudyBranch2.20203=UAS\:Telecommunications +swissEduPersonStudyBranch2.20204=UAS\:Microtechnology +swissEduPersonStudyBranch2.20205=UAS\:Systems engineering +swissEduPersonStudyBranch2.20206=UAS\:Mechanical engineering +swissEduPersonStudyBranch2.20207=UAS\:Technical project management (mechatronics) +swissEduPersonStudyBranch2.20208=UAS\:Automotive engineering +swissEduPersonStudyBranch2.20209=UAS\:Industrial engineering +swissEduPersonStudyBranch2.20210=UAS\:Media engineering +swissEduPersonStudyBranch2.20211=UAS\:Building services engineering +swissEduPersonStudyBranch2.20212=UAS\:Engineering design swissEduPersonStudyBranch2.20213=UAS\:Aviatics -swissEduPersonStudyBranch2.20214=UAS\:Optometry +swissEduPersonStudyBranch2.20214=UAS\:Optometry swissEduPersonStudyBranch2.20999=UAS\:Engineering -swissEduPersonStudyBranch2.30301=UAS\:Biotechnology -swissEduPersonStudyBranch2.30302=UAS\:Food technology -swissEduPersonStudyBranch2.30303=UAS\:Life technologies -swissEduPersonStudyBranch2.30304=UAS\:Chemistry -swissEduPersonStudyBranch2.30305=UAS\:Enology -swissEduPersonStudyBranch2.30308=UAS\:Environmental engineering -swissEduPersonStudyBranch2.30309=UAS\:Molecular life sciences -swissEduPersonStudyBranch2.30310=UAS\:Life science technologies +swissEduPersonStudyBranch2.30301=UAS\:Biotechnology +swissEduPersonStudyBranch2.30302=UAS\:Food technology +swissEduPersonStudyBranch2.30303=UAS\:Life technologies +swissEduPersonStudyBranch2.30304=UAS\:Chemistry +swissEduPersonStudyBranch2.30305=UAS\:Enology +swissEduPersonStudyBranch2.30308=UAS\:Environmental engineering +swissEduPersonStudyBranch2.30309=UAS\:Molecular life sciences +swissEduPersonStudyBranch2.30310=UAS\:Life science technologies swissEduPersonStudyBranch2.30999=UAS\:Advanced training (chemistry, life sciences) swissEduPersonStudyBranch2.40401=UAS\:Agriculture -swissEduPersonStudyBranch2.40402=UAS\:Forestry +swissEduPersonStudyBranch2.40402=UAS\:Forestry swissEduPersonStudyBranch2.40999=UAS\:Advanced training (agriculture, forestry) swissEduPersonStudyBranch2.41=U\:Exact sciences swissEduPersonStudyBranch2.42=U\:Natural sciences swissEduPersonStudyBranch2.43=U\:Exact, natural and other sciences -swissEduPersonStudyBranch2.50501=UAS\:Business administration -swissEduPersonStudyBranch2.50502=UAS\:European degree programme (business administration) -swissEduPersonStudyBranch2.50503=UAS\:International business management -swissEduPersonStudyBranch2.50504=UAS\:Business informatics -swissEduPersonStudyBranch2.50505=UAS\:Facility management -swissEduPersonStudyBranch2.50506=UAS\:Hotel business -swissEduPersonStudyBranch2.50507=UAS\:Tourism -swissEduPersonStudyBranch2.50508=UAS\:Information and documentation -swissEduPersonStudyBranch2.50509=UAS\:Communication -swissEduPersonStudyBranch2.50510=UAS\:Business law +swissEduPersonStudyBranch2.50501=UAS\:Business administration +swissEduPersonStudyBranch2.50502=UAS\:European degree programme (business administration) +swissEduPersonStudyBranch2.50503=UAS\:International business management +swissEduPersonStudyBranch2.50504=UAS\:Business informatics +swissEduPersonStudyBranch2.50505=UAS\:Facility management +swissEduPersonStudyBranch2.50506=UAS\:Hotel business +swissEduPersonStudyBranch2.50507=UAS\:Tourism +swissEduPersonStudyBranch2.50508=UAS\:Information and documentation +swissEduPersonStudyBranch2.50509=UAS\:Communication +swissEduPersonStudyBranch2.50510=UAS\:Business law swissEduPersonStudyBranch2.50999=UAS\:Advanced training (business services) swissEduPersonStudyBranch2.51=U\:Human medicin swissEduPersonStudyBranch2.52=U\:Dentistry swissEduPersonStudyBranch2.53=U\:Veterinary medicin -swissEduPersonStudyBranch2.54=U\:Pharmaceutics -swissEduPersonStudyBranch2.55=U\:Medicin, pharmaceutics and others -swissEduPersonStudyBranch2.60601=UAS\:Visual communication -swissEduPersonStudyBranch2.60602=UAS\:HyperWerk -swissEduPersonStudyBranch2.60603=UAS\:Product and industrial design -swissEduPersonStudyBranch2.60604=UAS\:Interior design -swissEduPersonStudyBranch2.60605=UAS\:Preservation and restoration -swissEduPersonStudyBranch2.60606=UAS\:Film -swissEduPersonStudyBranch2.60607=UAS\:Film realization +swissEduPersonStudyBranch2.54=U\:Pharmaceutics +swissEduPersonStudyBranch2.55=U\:Medicin, pharmaceutics and others +swissEduPersonStudyBranch2.60601=UAS\:Visual communication +swissEduPersonStudyBranch2.60602=UAS\:HyperWerk +swissEduPersonStudyBranch2.60603=UAS\:Product and industrial design +swissEduPersonStudyBranch2.60604=UAS\:Interior design +swissEduPersonStudyBranch2.60605=UAS\:Preservation and restoration +swissEduPersonStudyBranch2.60606=UAS\:Film +swissEduPersonStudyBranch2.60607=UAS\:Film realization swissEduPersonStudyBranch2.60999=UAS\:Advanced training (design) swissEduPersonStudyBranch2.61=U\:Architecture and geodesy -swissEduPersonStudyBranch2.62=U\:Mechanical and electrical engineering +swissEduPersonStudyBranch2.62=U\:Mechanical and electrical engineering swissEduPersonStudyBranch2.63=U\:Agriculture and forestry swissEduPersonStudyBranch2.64=U\:Technology, interdiscipliary and others -swissEduPersonStudyBranch2.70701=UAS\:Sports -swissEduPersonStudyBranch2.80199=UAS\:Fine arts in general -swissEduPersonStudyBranch2.80201=UAS\:Visual arts -swissEduPersonStudyBranch2.80202=UAS\:Handicrafts -swissEduPersonStudyBranch2.80203=UAS\:Esthetic education -swissEduPersonStudyBranch2.80299=UAS\:Teacher-training in general (fine arts) -swissEduPersonStudyBranch2.80301=UAS\:Writing -swissEduPersonStudyBranch2.81=U\:Head office -swissEduPersonStudyBranch2.82=U\:Central libraries +swissEduPersonStudyBranch2.70701=UAS\:Sports +swissEduPersonStudyBranch2.80199=UAS\:Fine arts in general +swissEduPersonStudyBranch2.80201=UAS\:Visual arts +swissEduPersonStudyBranch2.80202=UAS\:Handicrafts +swissEduPersonStudyBranch2.80203=UAS\:Esthetic education +swissEduPersonStudyBranch2.80299=UAS\:Teacher-training in general (fine arts) +swissEduPersonStudyBranch2.80301=UAS\:Writing +swissEduPersonStudyBranch2.81=U\:Head office +swissEduPersonStudyBranch2.82=U\:Central libraries swissEduPersonStudyBranch2.83=U\:Technical services and logistics swissEduPersonStudyBranch2.84=U\:Services for staff and students -swissEduPersonStudyBranch2.90101=UAS\:Musical education (instrumental and vocal) -swissEduPersonStudyBranch2.90201=UAS\:Interpretation/performance -swissEduPersonStudyBranch2.90301=UAS\:School and church music -swissEduPersonStudyBranch2.90401=UAS\:Conducting -swissEduPersonStudyBranch2.90501=UAS\:Special trainings (music) -swissEduPersonStudyBranch2.90999=UAS\:Music in general +swissEduPersonStudyBranch2.90101=UAS\:Musical education (instrumental and vocal) +swissEduPersonStudyBranch2.90201=UAS\:Interpretation/performance +swissEduPersonStudyBranch2.90301=UAS\:School and church music +swissEduPersonStudyBranch2.90401=UAS\:Conducting +swissEduPersonStudyBranch2.90501=UAS\:Special trainings (music) +swissEduPersonStudyBranch2.90999=UAS\:Music in general swissEduPersonStudyBranch2.999000=UAS\:Other -swissEduPersonStudyBranch2.999999=UAS\:Advanced training, other +swissEduPersonStudyBranch2.999999=UAS\:Advanced training, other swissEduPersonStudyBranch3=Field of study 3 swissEduPersonStudyBranch3.1000=U\:Ecology -swissEduPersonStudyBranch3.1100=U\:Humanities and social sciences (other) -swissEduPersonStudyBranch3.1190=U\:Teacher-training, secondary school I (Phil. I) +swissEduPersonStudyBranch3.1100=U\:Humanities and social sciences (other) +swissEduPersonStudyBranch3.1190=U\:Teacher-training, secondary school I (Phil. I) swissEduPersonStudyBranch3.1201=U\:Theology, interdisciplinary and others -swissEduPersonStudyBranch3.1205=U\:Protestant theology -swissEduPersonStudyBranch3.1210=U\:Roman Catholic theology -swissEduPersonStudyBranch3.1215=U\:Christ Catholic theology -swissEduPersonStudyBranch3.1300=U\:Philosophy -swissEduPersonStudyBranch3.1401=U\:Languages, interdisciplinary/others -swissEduPersonStudyBranch3.1405=U\:Linguistics -swissEduPersonStudyBranch3.1410=U\:German -swissEduPersonStudyBranch3.1415=U\:French -swissEduPersonStudyBranch3.1420=U\:Italian -swissEduPersonStudyBranch3.1425=U\:Rhaeto-Romanic -swissEduPersonStudyBranch3.1429=U\:Other European modern languages +swissEduPersonStudyBranch3.1205=U\:Protestant theology +swissEduPersonStudyBranch3.1210=U\:Roman Catholic theology +swissEduPersonStudyBranch3.1215=U\:Christ Catholic theology +swissEduPersonStudyBranch3.1300=U\:Philosophy +swissEduPersonStudyBranch3.1401=U\:Languages, interdisciplinary/others +swissEduPersonStudyBranch3.1405=U\:Linguistics +swissEduPersonStudyBranch3.1410=U\:German +swissEduPersonStudyBranch3.1415=U\:French +swissEduPersonStudyBranch3.1420=U\:Italian +swissEduPersonStudyBranch3.1425=U\:Rhaeto-Romanic +swissEduPersonStudyBranch3.1429=U\:Other European modern languages swissEduPersonStudyBranch3.1430=U\:Iberic languages -swissEduPersonStudyBranch3.1431=U\:Greek -swissEduPersonStudyBranch3.1435=U\:English +swissEduPersonStudyBranch3.1431=U\:Greek +swissEduPersonStudyBranch3.1435=U\:English swissEduPersonStudyBranch3.1440=U\:Slavic languages -swissEduPersonStudyBranch3.1445=U\:Nordic languages -swissEduPersonStudyBranch3.1449=U\:Classic European languages -swissEduPersonStudyBranch3.1450=U\:Classic languages -swissEduPersonStudyBranch3.1454=U\:Other non-European languages -swissEduPersonStudyBranch3.1455=U\:Asian languages -swissEduPersonStudyBranch3.1460=U\:Ancient Near Eastern languages -swissEduPersonStudyBranch3.1465=U\:African languages -swissEduPersonStudyBranch3.1470=U\:Interpreting and translation -swissEduPersonStudyBranch3.1500=U\:Archeology, early history +swissEduPersonStudyBranch3.1445=U\:Nordic languages +swissEduPersonStudyBranch3.1449=U\:Classic European languages +swissEduPersonStudyBranch3.1450=U\:Classic languages +swissEduPersonStudyBranch3.1454=U\:Other non-European languages +swissEduPersonStudyBranch3.1455=U\:Asian languages +swissEduPersonStudyBranch3.1460=U\:Ancient Near Eastern languages +swissEduPersonStudyBranch3.1465=U\:African languages +swissEduPersonStudyBranch3.1470=U\:Interpreting and translation +swissEduPersonStudyBranch3.1500=U\:Archeology, early history swissEduPersonStudyBranch3.1600=U\:History swissEduPersonStudyBranch3.1700=U\:History of art -swissEduPersonStudyBranch3.1800=U\:Musicology -swissEduPersonStudyBranch3.1850=U\:Theater and film sciences -swissEduPersonStudyBranch3.1900=U\:Ethnology and folklore -swissEduPersonStudyBranch3.1990=U\:History and cultural history (interdisciplinary) -swissEduPersonStudyBranch3.2000=U\:Psychology +swissEduPersonStudyBranch3.1800=U\:Musicology +swissEduPersonStudyBranch3.1850=U\:Theater and film sciences +swissEduPersonStudyBranch3.1900=U\:Ethnology and folklore +swissEduPersonStudyBranch3.1990=U\:History and cultural history (interdisciplinary) +swissEduPersonStudyBranch3.2000=U\:Psychology swissEduPersonStudyBranch3.2100=U\:Educational science swissEduPersonStudyBranch3.2120=U\:Orthopedagogy -swissEduPersonStudyBranch3.2130=U\:Sports -swissEduPersonStudyBranch3.2200=U\:Sociology +swissEduPersonStudyBranch3.2130=U\:Sports +swissEduPersonStudyBranch3.2200=U\:Sociology swissEduPersonStudyBranch3.2205=U\:Social work -swissEduPersonStudyBranch3.2300=U\:Politics -swissEduPersonStudyBranch3.2400=U\:Communication and media sciences -swissEduPersonStudyBranch3.2450=U\:Social science (interdisciplinary) -swissEduPersonStudyBranch3.2505=U\:Economics +swissEduPersonStudyBranch3.2300=U\:Politics +swissEduPersonStudyBranch3.2400=U\:Communication and media sciences +swissEduPersonStudyBranch3.2450=U\:Social science (interdisciplinary) +swissEduPersonStudyBranch3.2505=U\:Economics swissEduPersonStudyBranch3.2520=U\:Business studies swissEduPersonStudyBranch3.2530=U\:Business informatics -swissEduPersonStudyBranch3.2540=U\:Economics (interdisciplinary) +swissEduPersonStudyBranch3.2540=U\:Economics (interdisciplinary) swissEduPersonStudyBranch3.2600=U\:Law swissEduPersonStudyBranch3.3099=UAS\:Advanced training (architecture, civil engineering, planning) swissEduPersonStudyBranch3.3200=UAS\:Advanced training (technics, IT) @@ -333,158 +332,158 @@ swissEduPersonStudyBranch3.3229=UAS\:Advanced training (chemistry, life sciences swissEduPersonStudyBranch3.3299=UAS\:Advanced training (agriculture, forestry) swissEduPersonStudyBranch3.3399=UAS\:Advanced training (business administration) swissEduPersonStudyBranch3.3500=UAS\:Advanced training (design) -swissEduPersonStudyBranch3.3529=UAS\:Arts -swissEduPersonStudyBranch3.3531=UAS\:Visual arts -swissEduPersonStudyBranch3.3532=UAS\:Handicrafts -swissEduPersonStudyBranch3.3533=UAS\:Esthetic education -swissEduPersonStudyBranch3.3539=UAS\:Teacher-training in general (fine arts) -swissEduPersonStudyBranch3.3540=UAS\:Writing -swissEduPersonStudyBranch3.3551=UAS\:Musical education (instrumental and vocal) -swissEduPersonStudyBranch3.3552=UAS\:Interpretation/performance -swissEduPersonStudyBranch3.3553=UAS\:School and church music +swissEduPersonStudyBranch3.3529=UAS\:Arts +swissEduPersonStudyBranch3.3531=UAS\:Visual arts +swissEduPersonStudyBranch3.3532=UAS\:Handicrafts +swissEduPersonStudyBranch3.3533=UAS\:Esthetic education +swissEduPersonStudyBranch3.3539=UAS\:Teacher-training in general (fine arts) +swissEduPersonStudyBranch3.3540=UAS\:Writing +swissEduPersonStudyBranch3.3551=UAS\:Musical education (instrumental and vocal) +swissEduPersonStudyBranch3.3552=UAS\:Interpretation/performance +swissEduPersonStudyBranch3.3553=UAS\:School and church music swissEduPersonStudyBranch3.3554=UAS\:Conducting -swissEduPersonStudyBranch3.3555=UAS\:Special trainings (music) -swissEduPersonStudyBranch3.3569=UAS\:Music in general -swissEduPersonStudyBranch3.3571=UAS\:Theater (performing arts) -swissEduPersonStudyBranch3.3572=UAS\:Speech training, physical and vocal education +swissEduPersonStudyBranch3.3555=UAS\:Special trainings (music) +swissEduPersonStudyBranch3.3569=UAS\:Music in general +swissEduPersonStudyBranch3.3571=UAS\:Theater (performing arts) +swissEduPersonStudyBranch3.3572=UAS\:Speech training, physical and vocal education swissEduPersonStudyBranch3.3573=UAS\:Scenic education -swissEduPersonStudyBranch3.3574=UAS\:Special training (theater) +swissEduPersonStudyBranch3.3574=UAS\:Special training (theater) swissEduPersonStudyBranch3.3579=UAS\:Theater in general swissEduPersonStudyBranch3.3589=UAS\:Translation swissEduPersonStudyBranch3.3599=UAS\:Interpreting -swissEduPersonStudyBranch3.3600=UAS\:Applied linguistics in general -swissEduPersonStudyBranch3.3609=UAS\:Social work -swissEduPersonStudyBranch3.3619=UAS\:Social pedagogy -swissEduPersonStudyBranch3.3629=UAS\:Sociocultural animation -swissEduPersonStudyBranch3.3639=UAS\:General social work -swissEduPersonStudyBranch3.3651=UAS\:Psychological diagnostics and counseling +swissEduPersonStudyBranch3.3600=UAS\:Applied linguistics in general +swissEduPersonStudyBranch3.3609=UAS\:Social work +swissEduPersonStudyBranch3.3619=UAS\:Social pedagogy +swissEduPersonStudyBranch3.3629=UAS\:Sociocultural animation +swissEduPersonStudyBranch3.3639=UAS\:General social work +swissEduPersonStudyBranch3.3651=UAS\:Psychological diagnostics and counseling swissEduPersonStudyBranch3.3652=UAS\:Career counseling -swissEduPersonStudyBranch3.3653=UAS\:Industrial and organizational psychology -swissEduPersonStudyBranch3.3659=UAS\:Applied psychology in general +swissEduPersonStudyBranch3.3653=UAS\:Industrial and organizational psychology +swissEduPersonStudyBranch3.3659=UAS\:Applied psychology in general swissEduPersonStudyBranch3.3661=UAS\:Care swissEduPersonStudyBranch3.3662=UAS\:Midwife -swissEduPersonStudyBranch3.3669=UAS\:Health and care education in general -swissEduPersonStudyBranch3.3671=UAS\:Physiotherapy -swissEduPersonStudyBranch3.3672=UAS\:Ergotherapy -swissEduPersonStudyBranch3.3673=UAS\:Psychomotoric therapy +swissEduPersonStudyBranch3.3669=UAS\:Health and care education in general +swissEduPersonStudyBranch3.3671=UAS\:Physiotherapy +swissEduPersonStudyBranch3.3672=UAS\:Ergotherapy +swissEduPersonStudyBranch3.3673=UAS\:Psychomotoric therapy swissEduPersonStudyBranch3.3674=UAS\:Nutritional advice swissEduPersonStudyBranch3.3679=UAS\:Therapy and rehabilitation in general -swissEduPersonStudyBranch3.3681=UAS\:Medical radiology -swissEduPersonStudyBranch3.3689=UAS\:Diagnostic/therapeutic technology in general -swissEduPersonStudyBranch3.3699=UAS\:Health in general -swissEduPersonStudyBranch3.3701=UAS\:Preschool and primary school in general +swissEduPersonStudyBranch3.3681=UAS\:Medical radiology +swissEduPersonStudyBranch3.3689=UAS\:Diagnostic/therapeutic technology in general +swissEduPersonStudyBranch3.3699=UAS\:Health in general +swissEduPersonStudyBranch3.3701=UAS\:Preschool and primary school in general swissEduPersonStudyBranch3.3710=UAS\:Secondary school I in general -swissEduPersonStudyBranch3.3720=UAS\:Secondary school II in general (diploma) -swissEduPersonStudyBranch3.3725=UAS\:Secondary school II in general (training) -swissEduPersonStudyBranch3.3730=UAS\:Logopedics -swissEduPersonStudyBranch3.3731=UAS\:Psychomotricity -swissEduPersonStudyBranch3.3739=UAS\:Therapeutic pedagogy in general -swissEduPersonStudyBranch3.3799=UAS\:Teacher-training in general -swissEduPersonStudyBranch3.3801=UAS\:Architecture +swissEduPersonStudyBranch3.3720=UAS\:Secondary school II in general (diploma) +swissEduPersonStudyBranch3.3725=UAS\:Secondary school II in general (training) +swissEduPersonStudyBranch3.3730=UAS\:Logopedics +swissEduPersonStudyBranch3.3731=UAS\:Psychomotricity +swissEduPersonStudyBranch3.3739=UAS\:Therapeutic pedagogy in general +swissEduPersonStudyBranch3.3799=UAS\:Teacher-training in general +swissEduPersonStudyBranch3.3801=UAS\:Architecture swissEduPersonStudyBranch3.3802=UAS\:Civil engineering swissEduPersonStudyBranch3.3803=UAS\:Management of civil engineering swissEduPersonStudyBranch3.3804=UAS\:Urban and regional planning -swissEduPersonStudyBranch3.3805=UAS\:Landscaping -swissEduPersonStudyBranch3.3806=UAS\:Geomatics +swissEduPersonStudyBranch3.3805=UAS\:Landscaping +swissEduPersonStudyBranch3.3806=UAS\:Geomatics swissEduPersonStudyBranch3.3807=UAS\:Wood technnology -swissEduPersonStudyBranch3.3808=UAS\:Electrical engineering +swissEduPersonStudyBranch3.3808=UAS\:Electrical engineering swissEduPersonStudyBranch3.3809=UAS\:Computer sciences swissEduPersonStudyBranch3.3810=UAS\:Telecommunications -swissEduPersonStudyBranch3.3811=UAS\:Microtechnology -swissEduPersonStudyBranch3.3812=UAS\:Systems engineering +swissEduPersonStudyBranch3.3811=UAS\:Microtechnology +swissEduPersonStudyBranch3.3812=UAS\:Systems engineering swissEduPersonStudyBranch3.3813=UAS\:Mechanical engineering -swissEduPersonStudyBranch3.3814=UAS\:Technical project management (mechatronics) -swissEduPersonStudyBranch3.3815=UAS\:Automotive engineering +swissEduPersonStudyBranch3.3814=UAS\:Technical project management (mechatronics) +swissEduPersonStudyBranch3.3815=UAS\:Automotive engineering swissEduPersonStudyBranch3.3816=UAS\:Industrial engineering swissEduPersonStudyBranch3.3817=UAS\:Media engineering swissEduPersonStudyBranch3.3818=UAS\:Building services engineering -swissEduPersonStudyBranch3.3819=UAS\:Biotechnology +swissEduPersonStudyBranch3.3819=UAS\:Biotechnology swissEduPersonStudyBranch3.3820=UAS\:Food technology -swissEduPersonStudyBranch3.3821=UAS\:Life technologies -swissEduPersonStudyBranch3.3822=UAS\:Chemistry -swissEduPersonStudyBranch3.3823=UAS\:Enology +swissEduPersonStudyBranch3.3821=UAS\:Life technologies +swissEduPersonStudyBranch3.3822=UAS\:Chemistry +swissEduPersonStudyBranch3.3823=UAS\:Enology swissEduPersonStudyBranch3.3824=UAS\:Agriculture swissEduPersonStudyBranch3.3825=UAS\:Forestry swissEduPersonStudyBranch3.3826=UAS\:Environmental engineering swissEduPersonStudyBranch3.3827=UAS\:Business administration -swissEduPersonStudyBranch3.3828=UAS\:European degree programme (business administration) -swissEduPersonStudyBranch3.3829=UAS\:International business management +swissEduPersonStudyBranch3.3828=UAS\:European degree programme (business administration) +swissEduPersonStudyBranch3.3829=UAS\:International business management swissEduPersonStudyBranch3.3830=UAS\:Business informatics -swissEduPersonStudyBranch3.3831=UAS\:Facility management +swissEduPersonStudyBranch3.3831=UAS\:Facility management swissEduPersonStudyBranch3.3832=UAS\:Hotel business -swissEduPersonStudyBranch3.3833=UAS\:Tourism +swissEduPersonStudyBranch3.3833=UAS\:Tourism swissEduPersonStudyBranch3.3834=UAS\:Information and documentation -swissEduPersonStudyBranch3.3835=UAS\:Communication -swissEduPersonStudyBranch3.3836=UAS\:Visual communication -swissEduPersonStudyBranch3.3837=UAS\:HyperWerk -swissEduPersonStudyBranch3.3838=UAS\:Product and industrial design +swissEduPersonStudyBranch3.3835=UAS\:Communication +swissEduPersonStudyBranch3.3836=UAS\:Visual communication +swissEduPersonStudyBranch3.3837=UAS\:HyperWerk +swissEduPersonStudyBranch3.3838=UAS\:Product and industrial design swissEduPersonStudyBranch3.3839=UAS\:Interior design -swissEduPersonStudyBranch3.3840=UAS\:Preservation and restoration -swissEduPersonStudyBranch3.3841=UAS\:Sports +swissEduPersonStudyBranch3.3840=UAS\:Preservation and restoration +swissEduPersonStudyBranch3.3841=UAS\:Sports swissEduPersonStudyBranch3.3842=UAS\:Business law swissEduPersonStudyBranch3.3843=UAS\:Engineering design -swissEduPersonStudyBranch3.3844=UAS\:Aviatics -swissEduPersonStudyBranch3.3845=UAS\:Optometry -swissEduPersonStudyBranch3.3846=UAS\:Molecular life sciences -swissEduPersonStudyBranch3.3847=UAS\:Life science technologies -swissEduPersonStudyBranch3.3848=UAS\:Film -swissEduPersonStudyBranch3.3849=UAS\:Film realization -swissEduPersonStudyBranch3.3999=UAS\:Advanced training, other -swissEduPersonStudyBranch3.4100=U\:Exact and natural sciences (interdisciplinary) -swissEduPersonStudyBranch3.4103=U\:Teacher-training, secondary school I (Phil. II) -swissEduPersonStudyBranch3.4200=U\:Mathematics +swissEduPersonStudyBranch3.3844=UAS\:Aviatics +swissEduPersonStudyBranch3.3845=UAS\:Optometry +swissEduPersonStudyBranch3.3846=UAS\:Molecular life sciences +swissEduPersonStudyBranch3.3847=UAS\:Life science technologies +swissEduPersonStudyBranch3.3848=UAS\:Film +swissEduPersonStudyBranch3.3849=UAS\:Film realization +swissEduPersonStudyBranch3.3999=UAS\:Advanced training, other +swissEduPersonStudyBranch3.4100=U\:Exact and natural sciences (interdisciplinary) +swissEduPersonStudyBranch3.4103=U\:Teacher-training, secondary school I (Phil. II) +swissEduPersonStudyBranch3.4200=U\:Mathematics swissEduPersonStudyBranch3.4300=U\:Computer sciences -swissEduPersonStudyBranch3.4400=U\:Astronomy -swissEduPersonStudyBranch3.4500=U\:Physics -swissEduPersonStudyBranch3.4590=U\:Exact sciences (interdisciplinary) -swissEduPersonStudyBranch3.4600=U\:Chemistry -swissEduPersonStudyBranch3.4700=U\:Biology -swissEduPersonStudyBranch3.4800=U\:Earth science -swissEduPersonStudyBranch3.4900=U\:Geography -swissEduPersonStudyBranch3.4905=U\:Human geography -swissEduPersonStudyBranch3.4990=U\:Natural sciences (interdisciplinary) -swissEduPersonStudyBranch3.6100=U\:Medicin and pharmaceutics (interdisciplinary) +swissEduPersonStudyBranch3.4400=U\:Astronomy +swissEduPersonStudyBranch3.4500=U\:Physics +swissEduPersonStudyBranch3.4590=U\:Exact sciences (interdisciplinary) +swissEduPersonStudyBranch3.4600=U\:Chemistry +swissEduPersonStudyBranch3.4700=U\:Biology +swissEduPersonStudyBranch3.4800=U\:Earth science +swissEduPersonStudyBranch3.4900=U\:Geography +swissEduPersonStudyBranch3.4905=U\:Human geography +swissEduPersonStudyBranch3.4990=U\:Natural sciences (interdisciplinary) +swissEduPersonStudyBranch3.6100=U\:Medicin and pharmaceutics (interdisciplinary) swissEduPersonStudyBranch3.6150=U\:Care sciences -swissEduPersonStudyBranch3.6200=U\:Human medicin +swissEduPersonStudyBranch3.6200=U\:Human medicin swissEduPersonStudyBranch3.6300=U\:Dentistry -swissEduPersonStudyBranch3.6400=U\:Veterinary medicin -swissEduPersonStudyBranch3.650=U\:Central libraries -swissEduPersonStudyBranch3.6500=U\:Pharmaceutics -swissEduPersonStudyBranch3.660=U\:Technical services and logistics -swissEduPersonStudyBranch3.7100=U\:Technical sciences (other) +swissEduPersonStudyBranch3.6400=U\:Veterinary medicin +swissEduPersonStudyBranch3.650=U\:Central libraries +swissEduPersonStudyBranch3.6500=U\:Pharmaceutics +swissEduPersonStudyBranch3.660=U\:Technical services and logistics +swissEduPersonStudyBranch3.7100=U\:Technical sciences (other) swissEduPersonStudyBranch3.7200=U\:Civil engineering -swissEduPersonStudyBranch3.7300=U\:Architecture and planning -swissEduPersonStudyBranch3.7400=U\:Chemical engineering +swissEduPersonStudyBranch3.7300=U\:Architecture and planning +swissEduPersonStudyBranch3.7400=U\:Chemical engineering swissEduPersonStudyBranch3.7450=U\:Microtechnology -swissEduPersonStudyBranch3.750=U\:Services (staff and students) +swissEduPersonStudyBranch3.750=U\:Services (staff and students) swissEduPersonStudyBranch3.7500=U\:Electrical engineering swissEduPersonStudyBranch3.7550=U\:Communication systems swissEduPersonStudyBranch3.7600=U\:Mechanical engineering -swissEduPersonStudyBranch3.7650=U\:Business and production +swissEduPersonStudyBranch3.7650=U\:Business and production swissEduPersonStudyBranch3.7700=U\:Materials science -swissEduPersonStudyBranch3.7800=U\:Agricultural engineering and surveying +swissEduPersonStudyBranch3.7800=U\:Agricultural engineering and surveying swissEduPersonStudyBranch3.7905=U\:Forestry swissEduPersonStudyBranch3.7910=U\:Agriculture swissEduPersonStudyBranch3.7915=U\:Food technology swissEduPersonStudyBranch3.8000=U\:Military sciences -swissEduPersonStudyBranch3.850=U\:Central services -swissEduPersonStudyBranch3.9000=U\:Interdisciplinary sciences -swissEduPersonStudyBranch3.9001=U\:Gender studies +swissEduPersonStudyBranch3.850=U\:Central services +swissEduPersonStudyBranch3.9000=U\:Interdisciplinary sciences +swissEduPersonStudyBranch3.9001=U\:Gender studies swissEduPersonStudyBranch3.9002=U\:Advanced training (interfaculty) swissEduPersonStudyBranch3.9999=UAS\:Other swissEduPersonStudyLevel=Study level swissEduPersonStudyLevel.00=Preparation or advanced training, guest swissEduPersonStudyLevel.10=Licentiate or diploma -swissEduPersonStudyLevel.15=Bachelor -swissEduPersonStudyLevel.20=Advanced/graduate -swissEduPersonStudyLevel.25=Master (incl. Bachelor) -swissEduPersonStudyLevel.26=Master (excl. Bachelor) +swissEduPersonStudyLevel.15=Bachelor +swissEduPersonStudyLevel.20=Advanced/graduate +swissEduPersonStudyLevel.25=Master (incl. Bachelor) +swissEduPersonStudyLevel.26=Master (excl. Bachelor) swissEduPersonStudyLevel.31=Doctorate swissEduPersonStudyLevel.32=Continuing education swissEduPersonStudyLevel.33=Advanced training swissEduPersonStudyLevel.34=Modular advanced training -swissEduPersonStudyLevel.35=Continuing education (University) -swissEduPersonStudyLevel.39=Individual continuing education +swissEduPersonStudyLevel.35=Continuing education (University) +swissEduPersonStudyLevel.39=Individual continuing education swissEduPersonUniqueID=SwissEdu Personal ID wayf.homesite=University wayf.intro=Please select your university.<br>You will be redirected for authentication. @@ -493,4 +492,4 @@ wayf.password.back=Back to login wayf.password.text=You forgot your university's access information. Please contact the relevant department at your university. wayf.pleasechoose=Please select your university... wayf.submit=Login -we.intro=Your identity provider does not include an e-mail address. Please specify your e-mail address. +we.intro=Please complete your user properties. diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_fr.properties index 5e0cb75ccb1e4385d7bdce0e564461de6e9124d3..c6acd8dd021806aa9463685b936f15c537591b30 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Sun Nov 29 17:24:38 CET 2015 +#Tue Aug 15 17:12:21 CEST 2017 admin.ac.attribute=Activ\u00E9 le contr\u00F4le d'acc\u00E8s par attribut admin.ac.attribute.1=Attribut Shibboleth 1 admin.ac.attribute.2=Attribut Shibboleth 2 @@ -11,6 +11,7 @@ admin.menu.shibboleth.desc=Configuration du module Shibboleth admin.title=Autorisation Shibboleth authentication.provider.description=\u00CAtes-vous membre d'une institution qui utilise Shibboleth pour l'authentification? authentication.provider.linkText=Se connecter avec un compte Shibboleth +auto.shib.method=Shibboleth eduPersonAffiliation=Affiliation eduPersonAffiliation.affiliate=Affili\u00E9s eduPersonAffiliation.alum=Anciens @@ -21,7 +22,6 @@ eduPersonAffiliation.student=Etudiant eduPersonEntitlement=Autorisation eduPersonOrgUnitDN=Unit\u00E9 d'organisation DN employeeNumber=Num\u00E9ro personnel -error.insufficieant.attributes=Attributs Shibboleth n\u00E9cessaires\:Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.generic=Erreur Shibboleth. Reconnectez-vous, s.v.p.\! error.shibboleth.head=OLAT - Online Learning And Training - Error error.shibboleth.not.authorized=Vous n'\u00EAtes pas autoris\u00E9 \u00E0 vous connecter \u00E0 OpenOLAT. @@ -34,7 +34,7 @@ organizationalUnit=Unit\u00E9 d'organisation postalAddress=Adresse sm.error.no_username=Aucun nom d'utilisateur n'a \u00E9t\u00E9 cr\u00E9\u00E9 sm.error.username_in_use=Le nom d'utilisateur existe d\u00E9j\u00E0 -sm.header=Enregistrement +sm.header=Enregistrement sm.intro=Le nom d'utilisateur s\u00E9lectionn\u00E9 existe d\u00E9j\u00E0 dans OLAT. Si vous \u00EAtes sur que vous vous \u00EAtes donn\u00E9 ce nom d'utilisateur lors d'une inscription OLAT pr\u00E9c\u00E9dente, veuillez indiquer le mot de passe correspondant. Si l'identification est r\u00E9ussie, le nom d'utilisation est enregistr\u00E9 automatiquement.<br><br>Si vous n'avez pas cr\u00E9\u00E9 ce nom d'utilisateur, cliquez sur "abandonner" et choisissez un nouveau nom d'utilisation, s.v.p.. smf.error.blocked=Le nom d'utilisateur a \u00E9t\u00E9 bloqu\u00E9 pour des raisons de s\u00E9curit\u00E9. Vous pouvez r\u00E9essayer plus tard. smf.error.password=Le mot de passe n'est pas valide. @@ -116,8 +116,8 @@ swissEduPersonStaffCategory.303=Technical Personnel swissEduPersonStaffCategory.304=Technical Personnel\: Apprentices and Interns swissEduPersonStaffCategory.305=Janitors, Building Managers swissEduPersonStaffCategory.306=Social and Wellness Personnel -swissEduPersonStaffCategory.307=Library Personnel -swissEduPersonStaffCategory.308=Safety Personnel Radiation, Firefighters, Guards +swissEduPersonStaffCategory.307=Library Personnel +swissEduPersonStaffCategory.308=Safety Personnel Radiation, Firefighters, Guards swissEduPersonStudyBranch1=Branche d'\u00E9tude swissEduPersonStudyBranch1.1=U\: sciences humaines et sociales swissEduPersonStudyBranch1.10000=HEP\:architecture, ing\u00E9nierie, planification @@ -131,9 +131,9 @@ swissEduPersonStudyBranch1.20000=HEP\:technologie et informatique swissEduPersonStudyBranch1.3=U\:droit swissEduPersonStudyBranch1.30000=HEP\:chimie et sciences de la vie swissEduPersonStudyBranch1.4=HEP\:sciences naturelles et exactes -swissEduPersonStudyBranch1.40000=HEP\:agriculture e sylviculture -swissEduPersonStudyBranch1.5=U\: m\u00E9decine et pharmacie -swissEduPersonStudyBranch1.50000=HEP\:\u00E9conomie et services +swissEduPersonStudyBranch1.40000=HEP\:agriculture e sylviculture +swissEduPersonStudyBranch1.5=U\: m\u00E9decine et pharmacie +swissEduPersonStudyBranch1.50000=HEP\:\u00E9conomie et services swissEduPersonStudyBranch1.6=U\:sciences techniques swissEduPersonStudyBranch1.60000=HEP\:design swissEduPersonStudyBranch1.7=U\:interdisciplinaire et autres @@ -148,14 +148,14 @@ swissEduPersonStudyBranch2.100201=HEP\:\u00E9ducation physique, de diction, de c swissEduPersonStudyBranch2.100301=HEP\:sc\u00E9nographie swissEduPersonStudyBranch2.100401=HEP\:formation sp\u00E9ciale en th\u00E9\u00E2tre swissEduPersonStudyBranch2.100999=HEP\:th\u00E9\u00E2tre g\u00E9n\u00E9ral -swissEduPersonStudyBranch2.10101=HEP\:architecture +swissEduPersonStudyBranch2.10101=HEP\:architecture swissEduPersonStudyBranch2.10102=HEP\:ing\u00E9nierie civile swissEduPersonStudyBranch2.10103=HEP\:gestion des proc\u00E9d\u00E9s de construction swissEduPersonStudyBranch2.10104=HEP\:planification de l'espace swissEduPersonStudyBranch2.10105=HEP\:architecture du paysage swissEduPersonStudyBranch2.10106=HEP\:g\u00E9omatique swissEduPersonStudyBranch2.10107=HEP\: technologie du bois -swissEduPersonStudyBranch2.10999=HEP\:formation continue en architecture, construction et planification +swissEduPersonStudyBranch2.10999=HEP\:formation continue en architecture, construction et planification swissEduPersonStudyBranch2.11=U\:th\u00E9ologie swissEduPersonStudyBranch2.110199=HEP\:traduction swissEduPersonStudyBranch2.110299=HEP\:interpr\u00E8tes @@ -166,7 +166,7 @@ swissEduPersonStudyBranch2.120299=HEP\:p\u00E9dagogique sociale swissEduPersonStudyBranch2.120399=HEP\:animation socioculturelle swissEduPersonStudyBranch2.120999=HEP\:travail social g\u00E9n\u00E9ral swissEduPersonStudyBranch2.13=U\:sciences historiques et culturelles -swissEduPersonStudyBranch2.130101=HEP\:diagnostic et conseil psychologique +swissEduPersonStudyBranch2.130101=HEP\:diagnostic et conseil psychologique swissEduPersonStudyBranch2.130102=HEP\:conseil professionnel swissEduPersonStudyBranch2.130103=HEP\:psychologie du travail et de l'organisation swissEduPersonStudyBranch2.130999=HEP\:psychologie appliqu\u00E9 g\u00E9n\u00E9rale @@ -174,11 +174,11 @@ swissEduPersonStudyBranch2.14=HEP\:sciences sociales swissEduPersonStudyBranch2.140101=HEP\:soins swissEduPersonStudyBranch2.140102=HEP\:sage-femme swissEduPersonStudyBranch2.140199=HEP\:soin et \u00E9ducation \u00E0 la sant\u00E9 en g\u00E9n\u00E9ral -swissEduPersonStudyBranch2.140201=HEP\:physioth\u00E9rapie +swissEduPersonStudyBranch2.140201=HEP\:physioth\u00E9rapie swissEduPersonStudyBranch2.140202=HEP\:ergoth\u00E9rapie -swissEduPersonStudyBranch2.140203=HEP\:th\u00E9rapie psychomotrice -swissEduPersonStudyBranch2.140204=HEP\:conseil \u00E0 la nutrition -swissEduPersonStudyBranch2.140299=HEP\:th\u00E9rapie et r\u00E9habilitation en g\u00E9n\u00E9ral +swissEduPersonStudyBranch2.140203=HEP\:th\u00E9rapie psychomotrice +swissEduPersonStudyBranch2.140204=HEP\:conseil \u00E0 la nutrition +swissEduPersonStudyBranch2.140299=HEP\:th\u00E9rapie et r\u00E9habilitation en g\u00E9n\u00E9ral swissEduPersonStudyBranch2.140301=HEP\:radiologie m\u00E9dicale swissEduPersonStudyBranch2.140399=HEP\:technique diagnostique/th\u00E9rapeutique en g\u00E9n\u00E9ral swissEduPersonStudyBranch2.140999=HEP\:sant\u00E9 en g\u00E9n\u00E9ral @@ -188,33 +188,33 @@ swissEduPersonStudyBranch2.150201=HEP\:secondaire I en g\u00E9n\u00E9ral swissEduPersonStudyBranch2.150301=HEP\:secondaire II en g\u00E9n\u00E9ral (\u00E9cole de maturit\u00E9) swissEduPersonStudyBranch2.150302=HEP\:secondaire II g\u00E9n\u00E9ral (formation professionnelle) swissEduPersonStudyBranch2.150401=HEP\:logop\u00E9die -swissEduPersonStudyBranch2.150402=HEP\:psychomotricit\u00E9 +swissEduPersonStudyBranch2.150402=HEP\:psychomotricit\u00E9 swissEduPersonStudyBranch2.150499=HEP\:p\u00E9dagogie th\u00E9rapeutique en g\u00E9n\u00E9ral swissEduPersonStudyBranch2.150999=HEP\:formation du corps enseignant en g\u00E9n\u00E9ral -swissEduPersonStudyBranch2.20201=HEP\:\u00E9lectrotechnique +swissEduPersonStudyBranch2.20201=HEP\:\u00E9lectrotechnique swissEduPersonStudyBranch2.20202=HEP\:informatique swissEduPersonStudyBranch2.20203=HEP\:t\u00E9l\u00E9communication swissEduPersonStudyBranch2.20204=HEP\:microtechnique -swissEduPersonStudyBranch2.20205=HEP\:ing\u00E9nierie du syst\u00E8me +swissEduPersonStudyBranch2.20205=HEP\:ing\u00E9nierie du syst\u00E8me swissEduPersonStudyBranch2.20206=HEP\:ing\u00E9nierie m\u00E9canique -swissEduPersonStudyBranch2.20207=HEP\:gestion de projet en m\u00E9chatronique +swissEduPersonStudyBranch2.20207=HEP\:gestion de projet en m\u00E9chatronique swissEduPersonStudyBranch2.20208=HEP\:technique de l'automobile swissEduPersonStudyBranch2.20209=HEP\:ing\u00E9nierie \u00E9conomique swissEduPersonStudyBranch2.20210=HEP\:ing\u00E9nierie des m\u00E9dias swissEduPersonStudyBranch2.20211=HEP\:techniques du b\u00E2timent swissEduPersonStudyBranch2.20212=HEP\:ing\u00E9nierie du design swissEduPersonStudyBranch2.20213=HEP\: aviatique -swissEduPersonStudyBranch2.20214=HEP\:optom\u00E9trie +swissEduPersonStudyBranch2.20214=HEP\:optom\u00E9trie swissEduPersonStudyBranch2.20999=HEP\:technique swissEduPersonStudyBranch2.30301=HEP\:biotechnologie swissEduPersonStudyBranch2.30302=HEP\:technologie alimentaire -swissEduPersonStudyBranch2.30303=HEP\:Life Technologies +swissEduPersonStudyBranch2.30303=HEP\:Life Technologies swissEduPersonStudyBranch2.30304=HEP\:chimie -swissEduPersonStudyBranch2.30305=HEP\:oenologie +swissEduPersonStudyBranch2.30305=HEP\:oenologie swissEduPersonStudyBranch2.30308=HEP\:ing\u00E9nierie de l'environnement swissEduPersonStudyBranch2.30309=HEP\:sciences de la vie mol\u00E9culaire swissEduPersonStudyBranch2.30310=HEP\:Life Science Technologies -swissEduPersonStudyBranch2.30999=HEP\:Formation continue dans le domaine chimie et life sciences +swissEduPersonStudyBranch2.30999=HEP\:Formation continue dans le domaine chimie et life sciences swissEduPersonStudyBranch2.40401=HEP\:agriculture swissEduPersonStudyBranch2.40402=HEP\:sylviculture swissEduPersonStudyBranch2.40999=HEP\:formation continue dans le domaine agriculture et sylviculture @@ -223,9 +223,9 @@ swissEduPersonStudyBranch2.42=U\:sciences naturelles swissEduPersonStudyBranch2.43=U\: sciences naturelles et exactes, autres sciences swissEduPersonStudyBranch2.50501=HEP\:\u00E9conomie de gestion swissEduPersonStudyBranch2.50502=HEP\:\u00E9tudes europ\u00E9ennes pour l'\u00E9conomie de gestion -swissEduPersonStudyBranch2.50503=HEP\:International Business Management +swissEduPersonStudyBranch2.50503=HEP\:International Business Management swissEduPersonStudyBranch2.50504=HEP\:informatique \u00E9conomique -swissEduPersonStudyBranch2.50505=FH\:Facility Management +swissEduPersonStudyBranch2.50505=FH\:Facility Management swissEduPersonStudyBranch2.50506=HEP\:h\u00F4tellerie swissEduPersonStudyBranch2.50507=HEP\:tourisme swissEduPersonStudyBranch2.50508=HEP\:information et documentation @@ -245,20 +245,20 @@ swissEduPersonStudyBranch2.60605=HEP\:conservation-restauration swissEduPersonStudyBranch2.60606=HEP\:film swissEduPersonStudyBranch2.60607=HEP\:r\u00E9alisation de films swissEduPersonStudyBranch2.60999=HEP\:formation continue dans le domaine du design -swissEduPersonStudyBranch2.61=U\:construction et g\u00E9od\u00E9sie +swissEduPersonStudyBranch2.61=U\:construction et g\u00E9od\u00E9sie swissEduPersonStudyBranch2.62=U\:ing\u00E9nierie m\u00E9canique et \u00E9lectrique -swissEduPersonStudyBranch2.63=U\:agriculture et sylviculture -swissEduPersonStudyBranch2.64=U\:sciences techniques interdisciplinaires/autres +swissEduPersonStudyBranch2.63=U\:agriculture et sylviculture +swissEduPersonStudyBranch2.64=U\:sciences techniques interdisciplinaires/autres swissEduPersonStudyBranch2.70701=HEP\:sport swissEduPersonStudyBranch2.80199=HEP\:art plastique en g\u00E9n\u00E9ral swissEduPersonStudyBranch2.80201=HEP\:arts plastiques swissEduPersonStudyBranch2.80202=HEP\:enseignant manuel -swissEduPersonStudyBranch2.80203=HEP\:\u00E9ducation esth\u00E9tique +swissEduPersonStudyBranch2.80203=HEP\:\u00E9ducation esth\u00E9tique swissEduPersonStudyBranch2.80299=HEP\:formation du corps enseignant pour arts en g\u00E9n\u00E9ral swissEduPersonStudyBranch2.80301=HEP\:\u00E9criture litt\u00E9raire -swissEduPersonStudyBranch2.81=U\:administration centrale +swissEduPersonStudyBranch2.81=U\:administration centrale swissEduPersonStudyBranch2.82=U\:biblioth\u00E8ques centrales -swissEduPersonStudyBranch2.83=U\:services techniques et logistique +swissEduPersonStudyBranch2.83=U\:services techniques et logistique swissEduPersonStudyBranch2.84=U\:services pour collaborateurs et \u00E9tudiants swissEduPersonStudyBranch2.90101=HEP\:p\u00E9dagogique musicale (instrumentale et vocale) swissEduPersonStudyBranch2.90201=HEP\:interpr\u00E9tation/performance @@ -274,9 +274,9 @@ swissEduPersonStudyBranch3.1100=U\:sciences humaines et sociales, autres swissEduPersonStudyBranch3.1190=U\:formation du corps enseignant, secondaire I (phil.I) swissEduPersonStudyBranch3.1201=U\:th\u00E9ologie interdisciplinaire/autres swissEduPersonStudyBranch3.1205=U\:th\u00E9ologie protestante -swissEduPersonStudyBranch3.1210=U\:th\u00E9ologie catholique-romaine +swissEduPersonStudyBranch3.1210=U\:th\u00E9ologie catholique-romaine swissEduPersonStudyBranch3.1215=U\:th\u00E9ologie catholique-chr\u00E9tienne -swissEduPersonStudyBranch3.1300=U\:philosophie +swissEduPersonStudyBranch3.1300=U\:philosophie swissEduPersonStudyBranch3.1401=U\:langue et litt\u00E9raire interdisciplinaires / autres swissEduPersonStudyBranch3.1405=U\:linguistique swissEduPersonStudyBranch3.1410=U\:allemand @@ -293,16 +293,16 @@ swissEduPersonStudyBranch3.1449=U\:lettres classiques europ\u00E9ennes swissEduPersonStudyBranch3.1450=U\:lettres classiques swissEduPersonStudyBranch3.1454=U\:autre langues non europ\u00E9ennes swissEduPersonStudyBranch3.1455=U\:langues asiatiques -swissEduPersonStudyBranch3.1460=U\:langues du Proche-Orient +swissEduPersonStudyBranch3.1460=U\:langues du Proche-Orient swissEduPersonStudyBranch3.1465=U\:langues africaines -swissEduPersonStudyBranch3.1470=U\:interpr\u00E8tes et traductions +swissEduPersonStudyBranch3.1470=U\:interpr\u00E8tes et traductions swissEduPersonStudyBranch3.1500=U\:arch\u00E9ologie, histoire pr\u00E9historique et antique swissEduPersonStudyBranch3.1600=U\:histoire swissEduPersonStudyBranch3.1700=U\:histoire de l'art swissEduPersonStudyBranch3.1800=U\:musiclogie swissEduPersonStudyBranch3.1850=U\:th\u00E9\u00E2tre et film swissEduPersonStudyBranch3.1900=U\:ethnologie et folklore -swissEduPersonStudyBranch3.1990=U\:histoire et sciences culturelles interdisciplinaires/autres +swissEduPersonStudyBranch3.1990=U\:histoire et sciences culturelles interdisciplinaires/autres swissEduPersonStudyBranch3.2000=U\:psychologie swissEduPersonStudyBranch3.2100=U\:sciences de l'\u00E9ducation swissEduPersonStudyBranch3.2120=HEP\:p\u00E9dagogie sp\u00E9ciale @@ -311,10 +311,10 @@ swissEduPersonStudyBranch3.2200=HEP\:sociologie swissEduPersonStudyBranch3.2205=HEP\:travail social swissEduPersonStudyBranch3.2300=HEP\:sciences politiques swissEduPersonStudyBranch3.2400=HEP\:sciences de la communication et des m\u00E9dias -swissEduPersonStudyBranch3.2450=HEP\:sciences sociales interdisciplinaires/autres +swissEduPersonStudyBranch3.2450=HEP\:sciences sociales interdisciplinaires/autres swissEduPersonStudyBranch3.2505=HEP\:\u00E9conomie nationale swissEduPersonStudyBranch3.2520=HEP\:\u00E9conomie de gestion -swissEduPersonStudyBranch3.2530=HEP\:informatique de gestion +swissEduPersonStudyBranch3.2530=HEP\:informatique de gestion swissEduPersonStudyBranch3.2540=HEP\:\u00E9conomie interdisciplinaire/autres swissEduPersonStudyBranch3.2600=HEP\:droit swissEduPersonStudyBranch3.3099=HEP\:formation continue en architecture, construction et planification @@ -331,8 +331,8 @@ swissEduPersonStudyBranch3.3539=HEP\:formation du corps enseignant en arts en g\ swissEduPersonStudyBranch3.3540=HEP\:\u00E9criture litt\u00E9raire swissEduPersonStudyBranch3.3551=HEP\:p\u00E9dagogique musicale (instrumentale et vocale) swissEduPersonStudyBranch3.3552=HEP\:interpr\u00E9tation/performance -swissEduPersonStudyBranch3.3553=HEP\:musique scolaire et eccl\u00E9siastique -swissEduPersonStudyBranch3.3554=HEP\:chef d'orchestre +swissEduPersonStudyBranch3.3553=HEP\:musique scolaire et eccl\u00E9siastique +swissEduPersonStudyBranch3.3554=HEP\:chef d'orchestre swissEduPersonStudyBranch3.3555=HEP\:formation sp\u00E9ciale en musique swissEduPersonStudyBranch3.3569=HEP\:musique en g\u00E9n\u00E9ral swissEduPersonStudyBranch3.3571=HEP\: cr\u00E9ation th\u00E9\u00E2trale en arts performatifs @@ -342,14 +342,14 @@ swissEduPersonStudyBranch3.3574=HEP\:formation sp\u00E9ciale en th\u00E9\u00E2tr swissEduPersonStudyBranch3.3579=HEP\:th\u00E9\u00E2tre en g\u00E9n\u00E9ral swissEduPersonStudyBranch3.3589=HEP\:traduction swissEduPersonStudyBranch3.3599=HEP\:interpr\u00E9tation -swissEduPersonStudyBranch3.3600=HEP\:linguistique appliqu\u00E9e en g\u00E9n\u00E9ral +swissEduPersonStudyBranch3.3600=HEP\:linguistique appliqu\u00E9e en g\u00E9n\u00E9ral swissEduPersonStudyBranch3.3609=HEP\:travail social -swissEduPersonStudyBranch3.3619=HEP\:p\u00E9dagogie sp\u00E9cialis\u00E9e -swissEduPersonStudyBranch3.3629=HEP\:animation socioculturelle +swissEduPersonStudyBranch3.3619=HEP\:p\u00E9dagogie sp\u00E9cialis\u00E9e +swissEduPersonStudyBranch3.3629=HEP\:animation socioculturelle swissEduPersonStudyBranch3.3639=HEP\:travail social en g\u00E9n\u00E9ral -swissEduPersonStudyBranch3.3651=HEP\:diagnostic et conseil psychologique +swissEduPersonStudyBranch3.3651=HEP\:diagnostic et conseil psychologique swissEduPersonStudyBranch3.3652=HEP\:orientation professionnelle -swissEduPersonStudyBranch3.3653=HEP\:psychologie du travail et de l'organisation +swissEduPersonStudyBranch3.3653=HEP\:psychologie du travail et de l'organisation swissEduPersonStudyBranch3.3659=HEP\:psychologie appliqu\u00E9e en g\u00E9n\u00E9ral swissEduPersonStudyBranch3.3661=HEP\:soins swissEduPersonStudyBranch3.3662=HEP\:sage-femme @@ -359,31 +359,31 @@ swissEduPersonStudyBranch3.3672=HEP\:ergoth\u00E9rapie swissEduPersonStudyBranch3.3673=HEP\:th\u00E9rapie psychomotrice swissEduPersonStudyBranch3.3674=HEP\:conseil de nutrition swissEduPersonStudyBranch3.3679=HEP\:th\u00E9rapie et r\u00E9habilitation en g\u00E9n\u00E9ral -swissEduPersonStudyBranch3.3681=HEP\:radiologie m\u00E9dicale +swissEduPersonStudyBranch3.3681=HEP\:radiologie m\u00E9dicale swissEduPersonStudyBranch3.3689=HEP\:technique diagnostique/th\u00E9rapeutique en g\u00E9n\u00E9ral swissEduPersonStudyBranch3.3699=HEP\:sant\u00E9 en g\u00E9n\u00E9ral swissEduPersonStudyBranch3.3701=HEP\:\u00E9cole maternelle et primaire en g\u00E9n\u00E9ral swissEduPersonStudyBranch3.3710=HEP\:\u00E9cole secondaire I en g\u00E9n\u00E9ral -swissEduPersonStudyBranch3.3720=HEP\:secondaire II en g\u00E9n\u00E9ral (\u00E9coles universitaires) +swissEduPersonStudyBranch3.3720=HEP\:secondaire II en g\u00E9n\u00E9ral (\u00E9coles universitaires) swissEduPersonStudyBranch3.3725=HEP\:secondaire II en g\u00E9n\u00E9ral (formation profesionnelle) swissEduPersonStudyBranch3.3730=HEP\:logop\u00E9die -swissEduPersonStudyBranch3.3731=HEP\:psychomotricit\u00E9 +swissEduPersonStudyBranch3.3731=HEP\:psychomotricit\u00E9 swissEduPersonStudyBranch3.3739=HEP\:p\u00E9dagogie curative en g\u00E9n\u00E9ral swissEduPersonStudyBranch3.3799=HEP\:formation du corps enseignant en g\u00E9n\u00E9ral swissEduPersonStudyBranch3.3801=HEP\:architecture swissEduPersonStudyBranch3.3802=HEP\:ing\u00E9nierie civile swissEduPersonStudyBranch3.3803=HEP\:gestion des proc\u00E9d\u00E9s de construction -swissEduPersonStudyBranch3.3804=HEP\:planification du territoire +swissEduPersonStudyBranch3.3804=HEP\:planification du territoire swissEduPersonStudyBranch3.3805=HEP\:architecture du paysage -swissEduPersonStudyBranch3.3806=HEP\:g\u00E9omatique +swissEduPersonStudyBranch3.3806=HEP\:g\u00E9omatique swissEduPersonStudyBranch3.3807=HEP\:techniques du bois -swissEduPersonStudyBranch3.3808=HEP\:\u00E9lectrotechnique +swissEduPersonStudyBranch3.3808=HEP\:\u00E9lectrotechnique swissEduPersonStudyBranch3.3809=HEP\:informatique swissEduPersonStudyBranch3.3810=HEP\:t\u00E9l\u00E9communication swissEduPersonStudyBranch3.3811=HEP\:microtechnique swissEduPersonStudyBranch3.3812=HEP\:technique du syst\u00E8me swissEduPersonStudyBranch3.3813=HEP\:ing\u00E9nierie m\u00E9canique -swissEduPersonStudyBranch3.3814=HEP\:gestion de projet technique en m\u00E9chatronique +swissEduPersonStudyBranch3.3814=HEP\:gestion de projet technique en m\u00E9chatronique swissEduPersonStudyBranch3.3815=HEP\:technique de l'automobile swissEduPersonStudyBranch3.3816=HEP\:ing\u00E9nierie de gestion swissEduPersonStudyBranch3.3817=HEP\:ing\u00E9nierie des m\u00E9dias @@ -392,18 +392,18 @@ swissEduPersonStudyBranch3.3819=HEP\:biotechnologie swissEduPersonStudyBranch3.3820=HEP\:technologie alimentaire swissEduPersonStudyBranch3.3821=HEP\:life technologies swissEduPersonStudyBranch3.3822=HEP\:chimie -swissEduPersonStudyBranch3.3823=HEP\:oenologie +swissEduPersonStudyBranch3.3823=HEP\:oenologie swissEduPersonStudyBranch3.3824=HEP\:agriculture -swissEduPersonStudyBranch3.3825=HEP\:sylviculture -swissEduPersonStudyBranch3.3826=HEP\:ing\u00E9nierie de l'environnement +swissEduPersonStudyBranch3.3825=HEP\:sylviculture +swissEduPersonStudyBranch3.3826=HEP\:ing\u00E9nierie de l'environnement swissEduPersonStudyBranch3.3827=HEP\:\u00E9conomie de gestion swissEduPersonStudyBranch3.3828=HEP\:programme europ\u00E9en en \u00E9conomie de gestion -swissEduPersonStudyBranch3.3829=HEP\:International Business Management -swissEduPersonStudyBranch3.3830=HEP\:informatique \u00E9conomique -swissEduPersonStudyBranch3.3831=HEP\:Facility Management +swissEduPersonStudyBranch3.3829=HEP\:International Business Management +swissEduPersonStudyBranch3.3830=HEP\:informatique \u00E9conomique +swissEduPersonStudyBranch3.3831=HEP\:Facility Management swissEduPersonStudyBranch3.3832=HEP\:h\u00F4tellerie swissEduPersonStudyBranch3.3833=HEP\:tourisme -swissEduPersonStudyBranch3.3834=HEP\:information et documentation +swissEduPersonStudyBranch3.3834=HEP\:information et documentation swissEduPersonStudyBranch3.3835=HEP\:communication swissEduPersonStudyBranch3.3836=HEP\:communication visuelle swissEduPersonStudyBranch3.3837=HEP\:hyperwerk @@ -415,7 +415,7 @@ swissEduPersonStudyBranch3.3842=HEP\:droit de gestion swissEduPersonStudyBranch3.3843=HEP\:ing\u00E9nieur-designeur swissEduPersonStudyBranch3.3844=HEP\:aviation swissEduPersonStudyBranch3.3845=HEP\:optom\u00E9trie -swissEduPersonStudyBranch3.3846=HEP\:Molecular Life Sciences +swissEduPersonStudyBranch3.3846=HEP\:Molecular Life Sciences swissEduPersonStudyBranch3.3847=HEP\:Life Science Technologies swissEduPersonStudyBranch3.3848=HEP\:film swissEduPersonStudyBranch3.3849=HEP\:r\u00E9alisation de films @@ -446,21 +446,21 @@ swissEduPersonStudyBranch3.7200=U\:ing\u00E9nierie civile swissEduPersonStudyBranch3.7300=U\:architecture et planification swissEduPersonStudyBranch3.7400=U\:ing\u00E9nierie en chimie swissEduPersonStudyBranch3.7450=U\:microtechnique -swissEduPersonStudyBranch3.750=U\:services pour collaborateurs et \u00E9tudiants +swissEduPersonStudyBranch3.750=U\:services pour collaborateurs et \u00E9tudiants swissEduPersonStudyBranch3.7500=U\:ing\u00E9nierie \u00E9lectrique swissEduPersonStudyBranch3.7550=U\:syst\u00E8mes de communications swissEduPersonStudyBranch3.7600=U\:ing\u00E9nierie m\u00E9canique swissEduPersonStudyBranch3.7650=U\:sciences de gestion + de production swissEduPersonStudyBranch3.7700=U\:sciences des mati\u00E8res swissEduPersonStudyBranch3.7800=U\:techniques culturelles et mesurations -swissEduPersonStudyBranch3.7905=U\:sylviculture +swissEduPersonStudyBranch3.7905=U\:sylviculture swissEduPersonStudyBranch3.7910=U\:agriculture swissEduPersonStudyBranch3.7915=U\:technologie alimentaire swissEduPersonStudyBranch3.8000=U\:sciences militaires -swissEduPersonStudyBranch3.850=U\:administration centrale -swissEduPersonStudyBranch3.9000=U\:interdisciplinaire / interfacultaire +swissEduPersonStudyBranch3.850=U\:administration centrale +swissEduPersonStudyBranch3.9000=U\:interdisciplinaire / interfacultaire swissEduPersonStudyBranch3.9001=U\: Gender studies -swissEduPersonStudyBranch3.9002=U\:formation continue interfacultaire +swissEduPersonStudyBranch3.9002=U\:formation continue interfacultaire swissEduPersonStudyBranch3.9999=HEP\:non applicable swissEduPersonStudyLevel=niveau d'\u00E9tudes swissEduPersonStudyLevel.00=cours de pr\u00E9paration ou formation continue, \u00E9tudiants invit\u00E9s @@ -470,10 +470,10 @@ swissEduPersonStudyLevel.20=deuxi\u00E8me moiti\u00E9 des \u00E9tudes swissEduPersonStudyLevel.25=\u00E9tudes de master avec bachelor swissEduPersonStudyLevel.26=\u00E9tudes de master sans bachelor swissEduPersonStudyLevel.31=\u00E9tudes de doctorat -swissEduPersonStudyLevel.32=\u00E9tudes post dipl\u00F4me -swissEduPersonStudyLevel.33=formation continue +swissEduPersonStudyLevel.32=\u00E9tudes post dipl\u00F4me +swissEduPersonStudyLevel.33=formation continue swissEduPersonStudyLevel.34=formation continue modulaire -swissEduPersonStudyLevel.35=\u00E9tudes compl\u00E9mentaires et d'approfondissement +swissEduPersonStudyLevel.35=\u00E9tudes compl\u00E9mentaires et d'approfondissement swissEduPersonStudyLevel.39=formation postgradu\u00E9e individuelle, formation continue. swissEduPersonUniqueID=ID individuel SwissEdu wayf.homesite=Universit\u00E9 @@ -483,4 +483,4 @@ wayf.password.back=Retour \u00E0 la connexion wayf.password.text=Vous avez oubli\u00E9 les coordonn\u00E9es d'acc\u00E8s de votre universit\u00E9. Veuillez contacter le service comp\u00E9tent de votre universit\u00E9. wayf.pleasechoose=Veuillez choisir votre universit\u00E9... wayf.submit=Connexion -we.intro=Votre fournisseur d'acc\u00E8s ne fournit pas d'adresse e-mail. Veuillez indiquer votre adresse e-mail, s.v.p.. +we.intro=Veuillez compl\u00E9ter s'il vous pla\u00EEt vos donn\u00E9es. diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_it.properties index 7dfdacfe2f364be86bcbe1825da97ed4412d8f1e..1e59b0b448934da6441010017138e6673b3b8afa 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_it.properties @@ -11,6 +11,7 @@ admin.menu.shibboleth.desc=Configurazione modulo Shibboleth admin.title=Autorizzazione Shibboleth authentication.provider.description=Sei un membro di una istituzione che utilizza Single Sign-On basato su autenticazione Shibboleth? authentication.provider.linkText=Login con account Shibboleth +auto.shib.method=Shibboleth eduPersonAffiliation=Affiliazione eduPersonAffiliation.affiliate=Affiliati eduPersonAffiliation.alum=Alumni @@ -21,7 +22,6 @@ eduPersonAffiliation.student=Studente eduPersonEntitlement=Autorizzazione eduPersonOrgUnitDN=Unit\u00E0 organizzative DN employeeNumber=Numero personale -error.insufficieant.attributes=Attributi Shibboleth richiesti\: Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.generic=Errore Shibboleth. Ripeta il login, p.f.\! error.shibboleth.head=OLAT - Online Learning And Training - Errore error.shibboleth.not.authorized=Non sei autorizzato ad accedere ad OpenOLAT. @@ -415,8 +415,8 @@ swissEduPersonStudyBranch3.3842=SUP\:Diritto aziendale swissEduPersonStudyBranch3.3843=SPU\:Ingegneri disegnatori swissEduPersonStudyBranch3.3844=SPU\:Aviazione swissEduPersonStudyBranch3.3845=SPU\:Optometria -swissEduPersonStudyBranch3.3846=SUP\:Molecular Life Sciences -swissEduPersonStudyBranch3.3847=SUP\:Life Science Technologies +swissEduPersonStudyBranch3.3846=SUP\:Molecular Life Sciences +swissEduPersonStudyBranch3.3847=SUP\:Life Science Technologies swissEduPersonStudyBranch3.3848=SUP\:Film swissEduPersonStudyBranch3.3849=SUP\:Realizzazione film swissEduPersonStudyBranch3.3999=SUP\:Perfezionamento non attribuibile @@ -483,4 +483,3 @@ wayf.password.back=Indietro al login wayf.password.text=Ha dimenticato i dati d'accesso per la Sua universit\u00E0. Si rivolga all'ufficio competente della Sua universit\u00E0, p.f. wayf.pleasechoose=Selezioni la Sua universit\u00E0... wayf.submit=Login -we.intro=Il Suo identity provider non fornisce alcun indirizzo e-mail. Indichi il Suo indirizzo e-mail, p.f. diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_nl_NL.properties index 4787e47766762683e8ed138314f9e838e0a813a7..77d64188e1d7212cc9cab5a8b9e8d702d824cbb9 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_nl_NL.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_nl_NL.properties @@ -9,6 +9,7 @@ +auto.shib.method=Shibboleth eduPersonAffiliation=Aansluiting eduPersonAffiliation.affiliate=Aansluiten eduPersonAffiliation.alum=Voorafbestaande @@ -19,7 +20,6 @@ eduPersonAffiliation.student=Student eduPersonEntitlement=Autorisatie eduPersonOrgUnitDN=Organisatie-eenheid DN employeeNumber=Werknemer identificatienummer -error.insufficieant.attributes=Verplichte Shibboleth attributen\: Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.generic=Een Shibboleth fout trad op. Gelieve opnieuw aan te melden\! error.shibboleth.head=OLAT - Online Learning And Training - Error error.unqueid.notfound=Bent u echt gemachtigd om toegang te krijgen tot OLAT? Zo ja, gelieve opnieuw in te loggen. @@ -480,4 +480,3 @@ wayf.password.back=Terug naar login wayf.password.text=U bent de toegangsinformatie van uw universiteit vergeten. Gelieve contact op te nemen met het relevante departement van uw universiteit. wayf.pleasechoose=Gelieve uw universiteit te selecteren... wayf.submit=Login -we.intro=Uw identiteitsvoorziener bevat geen e-mailadres. Gelieve uw e-mailadres te verduidelijken. diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_pl.properties index 8cfd54fb20e22c71caf4d09832d8f15541b1a6e5..83b88e93a0c35afbf89355baa32f2449abb0b98a 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_pl.properties @@ -8,7 +8,7 @@ - +auto.shib.method=Shibboleth eduPersonAffiliation=Affiliation eduPersonAffiliation.affiliate=Affiliate eduPersonAffiliation.alum=Alumni @@ -19,7 +19,6 @@ eduPersonAffiliation.student=Student eduPersonEntitlement=Authorization eduPersonOrgUnitDN=Organization unit DN employeeNumber=Employee identification number -error.insufficieant.attributes=Mandatory Shibboleth attributes\: Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.generic=A Shibboleth error occured. Please log in again\! error.shibboleth.head=OLAT - Online Learning And Training - Error error.unqueid.notfound=Are you really entitled to access OLAT? If so, please log in again. @@ -480,4 +479,3 @@ wayf.password.back=Back to login wayf.password.text=You forgot your university's access information. Please contact the relevant department at your university. wayf.pleasechoose=Please select your university... wayf.submit=Login -we.intro=Your identity provider does not include an e-mail address. Please specify your e-mail address. diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_pt_BR.properties index ac6273683061b0703744e419392f47637a9ba93e..cb0f609a4bfb95c24aab356528f4838d8c503ad0 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Fri Apr 29 15:09:43 CEST 2016 +#Tue Sep 05 23:34:43 CEST 2017 admin.ac.attribute=Ativar o controle de acesso a atributos admin.ac.attribute.1=Atributo Shibboleth 1 admin.ac.attribute.2=Atributo Shibboleth 2 @@ -11,6 +11,7 @@ admin.menu.shibboleth.desc=M\u00F3dulo de configura\u00E7\u00E3o Shibboleth admin.title=Autoriza\u00E7\u00E3o Shibboleth authentication.provider.description=Voc\u00EA faz parte de uma das institui\u00E7\u00F5es que utilizam autentica\u00E7\u00E3o Shibboleth? authentication.provider.linkText=Entrar com conta Shibboleth +auto.shib.method=Shibboleth eduPersonAffiliation=Filia\u00E7\u00E3o eduPersonAffiliation.affiliate=Filiado eduPersonAffiliation.alum=Alumni @@ -21,7 +22,6 @@ eduPersonAffiliation.student=Estudante eduPersonEntitlement=Autoriza\u00E7\u00E3o eduPersonOrgUnitDN=Unidade da Organiza\u00E7\u00E3o employeeNumber=N\u00FAmero de Identifica\u00E7\u00E3o de Empregado -error.insufficieant.attributes=Atributos Shibboleth Obrigat\u00F3rios\: Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.generic=Um erro no Shibboleth ocorreu. Por favor fa\u00E7a o log in novamente\! error.shibboleth.head=OLAT - Online Learning And Training - Erro error.shibboleth.not.authorized=Voc\u00EA n\u00E3o est\u00E1 autorizado a iniciar sess\u00E3o OpenOLAT. @@ -483,4 +483,4 @@ wayf.password.back=Voltar ao login wayf.password.text=Voc\u00EA esqueceu a informa\u00E7\u00E3o de acesso da sua universidade. Entre em contato com o departamento competente na sua universidade. wayf.pleasechoose=Por favor, selecione sua universidade ... wayf.submit=Login -we.intro=Seu provedor de identidade n\u00E3o inclui um endere\u00E7o de e-mail. Por favor, especifique o endere\u00E7o de correio electr\u00F3nico. +we.intro=Por favor complete as propriedades do seu usu\u00E1rio diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_zh_CN.properties index 1034f657341e4bdd3ce10281813bc5ddf0b2a87a..330840f64bb91813773379c837e56955a84d38fa 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_zh_CN.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_zh_CN.properties @@ -19,7 +19,6 @@ eduPersonAffiliation.student=\u5B66\u751F eduPersonEntitlement=\u6388\u6743 eduPersonOrgUnitDN=DN\u7EC4\u7EC7\u5355\u5143 employeeNumber=\u96C7\u5458\u8EAB\u4EFD\u8BC1\u53F7\u7801 -error.insufficieant.attributes=\u5F3A\u5236\u6027\u53E3\u4EE4\u5C5E\u6027\uFF1AShib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization error.shibboleth.generic=\u53E3\u4EE4\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\uFF01 error.shibboleth.head=OLAT - \u5728\u7EBF\u5B66\u4E60\u4E0E\u57F9\u8BAD - \u9519\u8BEF error.unqueid.notfound=\u60A8\u771F\u7684\u6709\u6743\u5229\u8BBF\u95EEOLAT\uFF1F\u5982\u679C\u771F\u662F\u8FD9\u6837\u7684\u8BDD\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\u3002 @@ -92,4 +91,3 @@ wayf.password.back=\u8FD4\u56DE\u767B\u5F55 wayf.password.text=\u5982\u679C\u60A8\u5FD8\u8BB0\u60A8\u7684\u5927\u5B66\u7684\u8BBF\u95EE\u4FE1\u606F\uFF0C\u8BF7\u8054\u7CFB\u60A8\u7684\u5927\u5B66\u7684\u76F8\u5173\u90E8\u95E8\u3002 wayf.pleasechoose=\u8BF7\u9009\u62E9\u60A8\u7684\u5927\u5B66... wayf.submit=\u767B\u5F55 -we.intro=\u60A8\u7684\u8EAB\u4EFD\u8BA4\u8BC1\u5E76\u6CA1\u6709\u5305\u597D\u4E00\u4E2Ae-mail\u5730\u5740\u3002\u8BF7\u660E\u786E\u60A8\u7684e-mail\u5730\u5740\u3002 diff --git a/src/main/java/org/olat/shibboleth/_i18n/i18nBundleMetadata.properties b/src/main/java/org/olat/shibboleth/_i18n/i18nBundleMetadata.properties index b375df7451a788def6d5aebaad5e12d3943226ea..902f3d0f4967ae8039df16b2085bba68c9006acd 100644 --- a/src/main/java/org/olat/shibboleth/_i18n/i18nBundleMetadata.properties +++ b/src/main/java/org/olat/shibboleth/_i18n/i18nBundleMetadata.properties @@ -1,7 +1,6 @@ #Sun Jan 23 15:36:16 CET 2011 authentication.provider.description.annotation=\u8FD9\u4E2A\u53EF\u4EE5\u6839\u636E\u7528\u6237\u7684\u5355\u4F4D\u548C\u90E8\u95E8\u8FDB\u884C\u91CD\u65B0\u7FFB\u8BD1\uFF01\u4F8B\u5982\uFF1A\u60A8\u662F\u767E\u5EA6\u7684\u5206\u652F\u673A\u6784\u561B\uFF1F bundle.priority=650 -error.insufficieant.attributes.annotation=\u6839\u636E\u5B9E\u9645\u60C5\u51B5\u4ECE\u65B0\u5B9A\u4E49\uFF0C\u8FD9\u91CC\u672A\u505A\u4EFB\u4F55\u4FEE\u6539 swissEduPersonHomeOrganizationType.uas.annotation=ENG Translation should be \: College (???) \r\n\=> No. swissEduPersonStaffCategory.101.annotation=Check spelling swissEduPersonStaffCategory.102.annotation=Check spelling diff --git a/src/main/java/org/olat/shibboleth/_spring/shibbolethContext.xml b/src/main/java/org/olat/shibboleth/_spring/shibbolethContext.xml index 61432c380edfced3f5e5593ba304be9abcf3b209..9066ebadf7583736de2e8bab656f02213a6fff29 100644 --- a/src/main/java/org/olat/shibboleth/_spring/shibbolethContext.xml +++ b/src/main/java/org/olat/shibboleth/_spring/shibbolethContext.xml @@ -3,18 +3,18 @@ xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" - http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/context + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.olat.shibboleth" /> - + <!-- Shibboleth admin. panel --> <bean class="org.olat.core.extensions.action.GenericActionExtension" id="sysadmin.menupoint.syscfg.shibbolethcfg" init-method="initExtensionPoints"> <property name="order" value="8830" /> <property name="enabled" value="${shibboleth.enable}" /> - <property name="actionController"> + <property name="actionController"> <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> <property name="className" value="org.olat.shibboleth.ShibbolethAdminController"/> </bean> @@ -24,11 +24,11 @@ <property name="i18nDescriptionKey" value="admin.menu.shibboleth.desc"/> <property name="translationPackage" value="org.olat.shibboleth"/> <property name="extensionPoints"> - <list> - <value>org.olat.admin.SystemAdminMainController</value> + <list> + <value>org.olat.admin.SystemAdminMainController</value> </list> </property> - <property name="parentTreeNodeIdentifier" value="loginAndSecurityParent" /> + <property name="parentTreeNodeIdentifier" value="loginAndSecurityParent" /> </bean> <bean name="shibbolethOperators" class="java.util.ArrayList" scope="prototype" > @@ -43,37 +43,161 @@ </list> </constructor-arg> </bean> - + <bean name="shibbolethUserMapping" class="java.util.HashMap" scope="prototype" > - <constructor-arg> - <map key-type="java.lang.String" value-type="java.lang.String"> - <entry key="FirstName" value="Shib-InetOrgPerson-givenName" /> - <entry key="LastName" value="Shib-Person-surname" /> - <entry key="EMail" value="Shib-InetOrgPerson-mail" /> - <entry key="InstitutionalName" value="Shib-SwissEP-HomeOrganization" /> - <entry key="InstitutionalEMail" value="Shib-InetOrgPerson-mail" /> - <entry key="InstitutionalUserIdentifier" value="Shib-InetOrgPerson-employeeNumber" /> - <!-- <entry key="OrgUnit" value="" /> --> - <!-- <entry key="PreferedLanguage" value="" /> --> - </map> - </constructor-arg> + <constructor-arg> + <map key-type="java.lang.String" value-type="java.lang.String"> + <!-- These attributes are mandatory --> + <entry key='${shibboleth.user.mapping.email.shib}' value="email" /> + <entry key='${shibboleth.user.mapping.first.name.shib}' value="firstName" /> + <entry key='${shibboleth.user.mapping.last.name.shib}' value="lastName" /> + + <!-- All other attributes are optional --> + <entry key='${shibboleth.user.mapping.key1.shib}' value='${shibboleth.user.mapping.key1.olat}' /> + <entry key='${shibboleth.user.mapping.key2.shib}' value='${shibboleth.user.mapping.key2.olat}' /> + <entry key='${shibboleth.user.mapping.key3.shib}' value='${shibboleth.user.mapping.key3.olat}' /> + <entry key='${shibboleth.user.mapping.key4.shib}' value='${shibboleth.user.mapping.key4.olat}' /> + <entry key='${shibboleth.user.mapping.key5.shib}' value='${shibboleth.user.mapping.key5.olat}' /> + <entry key='${shibboleth.user.mapping.key6.shib}' value='${shibboleth.user.mapping.key6.olat}' /> + <entry key='${shibboleth.user.mapping.key7.shib}' value='${shibboleth.user.mapping.key7.olat}' /> + <entry key='${shibboleth.user.mapping.key8.shib}' value='${shibboleth.user.mapping.key8.olat}' /> + <entry key='${shibboleth.user.mapping.key9.shib}' value='${shibboleth.user.mapping.key9.olat}' /> + <entry key='${shibboleth.user.mapping.key10.shib}' value='${shibboleth.user.mapping.key10.olat}' /> + <entry key='${shibboleth.user.mapping.key11.shib}' value='${shibboleth.user.mapping.key11.olat}' /> + <entry key='${shibboleth.user.mapping.key12.shib}' value='${shibboleth.user.mapping.key12.olat}' /> + <entry key='${shibboleth.user.mapping.key13.shib}' value='${shibboleth.user.mapping.key13.olat}' /> + <entry key='${shibboleth.user.mapping.key14.shib}' value='${shibboleth.user.mapping.key14.olat}' /> + <entry key='${shibboleth.user.mapping.key15.shib}' value='${shibboleth.user.mapping.key15.olat}' /> + <entry key='${shibboleth.user.mapping.key16.shib}' value='${shibboleth.user.mapping.key16.olat}' /> + <entry key='${shibboleth.user.mapping.key17.shib}' value='${shibboleth.user.mapping.key17.olat}' /> + <entry key='${shibboleth.user.mapping.key18.shib}' value='${shibboleth.user.mapping.key18.olat}' /> + <entry key='${shibboleth.user.mapping.key19.shib}' value='${shibboleth.user.mapping.key19.olat}' /> + <entry key='${shibboleth.user.mapping.key20.shib}' value='${shibboleth.user.mapping.key20.olat}' /> + </map> + </constructor-arg> </bean> -<bean id="attributeTranslator" class="org.olat.shibboleth.util.AttributeTranslator" > + <bean name="shibbolethAttributeHandler" class="java.util.HashMap" scope="prototype" > + <constructor-arg> + <map key-type="java.lang.String" value-type="java.lang.String"> + <entry key='${shibboleth.uid.shib}' value='${shibboleth.uid.handler}' /> + <entry key='${shibboleth.preferred.language.shib}' value='${shibboleth.preferred.language.handler}' /> + <entry key='${shibboleth.user.mapping.email.shib}' value='${shibboleth.user.mapping.email.handler}' /> + <entry key='${shibboleth.user.mapping.first.name.shib}' value='${shibboleth.user.mapping.first.name.handler}' /> + <entry key='${shibboleth.user.mapping.last.name.shib}' value='${shibboleth.user.mapping.last.name.handler}' /> + <entry key='${shibboleth.user.mapping.key1.shib}' value='${shibboleth.user.mapping.key1.handler}' /> + <entry key='${shibboleth.user.mapping.key2.shib}' value='${shibboleth.user.mapping.key2.handler}' /> + <entry key='${shibboleth.user.mapping.key3.shib}' value='${shibboleth.user.mapping.key3.handler}' /> + <entry key='${shibboleth.user.mapping.key4.shib}' value='${shibboleth.user.mapping.key4.handler}' /> + <entry key='${shibboleth.user.mapping.key5.shib}' value='${shibboleth.user.mapping.key5.handler}' /> + <entry key='${shibboleth.user.mapping.key6.shib}' value='${shibboleth.user.mapping.key6.handler}' /> + <entry key='${shibboleth.user.mapping.key7.shib}' value='${shibboleth.user.mapping.key7.handler}' /> + <entry key='${shibboleth.user.mapping.key8.shib}' value='${shibboleth.user.mapping.key8.handler}' /> + <entry key='${shibboleth.user.mapping.key9.shib}' value='${shibboleth.user.mapping.key9.handler}' /> + <entry key='${shibboleth.user.mapping.key10.shib}' value='${shibboleth.user.mapping.key10.handler}' /> + <entry key='${shibboleth.user.mapping.key11.shib}' value='${shibboleth.user.mapping.key11.handler}' /> + <entry key='${shibboleth.user.mapping.key12.shib}' value='${shibboleth.user.mapping.key12.handler}' /> + <entry key='${shibboleth.user.mapping.key13.shib}' value='${shibboleth.user.mapping.key13.handler}' /> + <entry key='${shibboleth.user.mapping.key14.shib}' value='${shibboleth.user.mapping.key14.handler}' /> + <entry key='${shibboleth.user.mapping.key15.shib}' value='${shibboleth.user.mapping.key15.handler}' /> + <entry key='${shibboleth.user.mapping.key16.shib}' value='${shibboleth.user.mapping.key16.handler}' /> + <entry key='${shibboleth.user.mapping.key17.shib}' value='${shibboleth.user.mapping.key17.handler}' /> + <entry key='${shibboleth.user.mapping.key18.shib}' value='${shibboleth.user.mapping.key18.handler}' /> + <entry key='${shibboleth.user.mapping.key19.shib}' value='${shibboleth.user.mapping.key19.handler}' /> + <entry key='${shibboleth.user.mapping.key20.shib}' value='${shibboleth.user.mapping.key20.handler}' /> + </map> + </constructor-arg> + </bean> + + <bean name="shibbolethDeleteIfNull" class="java.util.HashMap" scope="prototype" > + <constructor-arg> + <map key-type="java.lang.String" value-type="java.lang.Boolean"> + <entry key='${shibboleth.user.mapping.key1.shib}' value='${shibboleth.user.mapping.key1.delete}' /> + <entry key='${shibboleth.user.mapping.key2.shib}' value='${shibboleth.user.mapping.key2.delete}' /> + <entry key='${shibboleth.user.mapping.key3.shib}' value='${shibboleth.user.mapping.key3.delete}' /> + <entry key='${shibboleth.user.mapping.key4.shib}' value='${shibboleth.user.mapping.key4.delete}' /> + <entry key='${shibboleth.user.mapping.key5.shib}' value='${shibboleth.user.mapping.key5.delete}' /> + <entry key='${shibboleth.user.mapping.key6.shib}' value='${shibboleth.user.mapping.key6.delete}' /> + <entry key='${shibboleth.user.mapping.key7.shib}' value='${shibboleth.user.mapping.key7.delete}' /> + <entry key='${shibboleth.user.mapping.key8.shib}' value='${shibboleth.user.mapping.key8.delete}' /> + <entry key='${shibboleth.user.mapping.key9.shib}' value='${shibboleth.user.mapping.key9.delete}' /> + <entry key='${shibboleth.user.mapping.key10.shib}' value='${shibboleth.user.mapping.key10.delete}' /> + <entry key='${shibboleth.user.mapping.key11.shib}' value='${shibboleth.user.mapping.key11.delete}' /> + <entry key='${shibboleth.user.mapping.key12.shib}' value='${shibboleth.user.mapping.key12.delete}' /> + <entry key='${shibboleth.user.mapping.key13.shib}' value='${shibboleth.user.mapping.key13.delete}' /> + <entry key='${shibboleth.user.mapping.key14.shib}' value='${shibboleth.user.mapping.key14.delete}' /> + <entry key='${shibboleth.user.mapping.key15.shib}' value='${shibboleth.user.mapping.key15.delete}' /> + <entry key='${shibboleth.user.mapping.key16.shib}' value='${shibboleth.user.mapping.key16.delete}' /> + <entry key='${shibboleth.user.mapping.key17.shib}' value='${shibboleth.user.mapping.key17.delete}' /> + <entry key='${shibboleth.user.mapping.key18.shib}' value='${shibboleth.user.mapping.key18.delete}' /> + <entry key='${shibboleth.user.mapping.key19.shib}' value='${shibboleth.user.mapping.key19.delete}' /> + <entry key='${shibboleth.user.mapping.key20.shib}' value='${shibboleth.user.mapping.key20.delete}' /> + </map> + </constructor-arg> + </bean> + + +<bean id="emptyAttributeTranslator" class="org.olat.shibboleth.util.AttributeTranslator"> + <!-- + The default attribute translator to not translate anything. This will disable the attribute editor + in the course easy condition editor. + --> + <property name="attributeTranslations"><map></map></property> + <property name="attributeSelectableValues"><map></map></property> +</bean> + +<bean id="userMappingAttributeTranslator" class="org.olat.shibboleth.util.AttributeTranslator"> + <!-- + A simple attibute translator that will use all shibboleth attribute that are mapped + to OpenOLAT userproperties. Those mapped attributes will appear in the course easy + condition editor. + --> + <property name="attributeTranslations"> + <map> + <entry key='${shibboleth.user.mapping.email.shib}' value="email" /> + <entry key='${shibboleth.user.mapping.first.name.shib}' value="firstName" /> + <entry key='${shibboleth.user.mapping.last.name.shib}' value="lastName" /> + <entry key='${shibboleth.user.mapping.key1.shib}' value='${shibboleth.user.mapping.key1.olat}' /> + <entry key='${shibboleth.user.mapping.key2.shib}' value='${shibboleth.user.mapping.key2.olat}' /> + <entry key='${shibboleth.user.mapping.key3.shib}' value='${shibboleth.user.mapping.key3.olat}' /> + <entry key='${shibboleth.user.mapping.key4.shib}' value='${shibboleth.user.mapping.key4.olat}' /> + <entry key='${shibboleth.user.mapping.key5.shib}' value='${shibboleth.user.mapping.key5.olat}' /> + <entry key='${shibboleth.user.mapping.key6.shib}' value='${shibboleth.user.mapping.key6.olat}' /> + <entry key='${shibboleth.user.mapping.key7.shib}' value='${shibboleth.user.mapping.key7.olat}' /> + <entry key='${shibboleth.user.mapping.key8.shib}' value='${shibboleth.user.mapping.key8.olat}' /> + <entry key='${shibboleth.user.mapping.key9.shib}' value='${shibboleth.user.mapping.key9.olat}' /> + <entry key='${shibboleth.user.mapping.key10.shib}' value='${shibboleth.user.mapping.key10.olat}' /> + <entry key='${shibboleth.user.mapping.key11.shib}' value='${shibboleth.user.mapping.key11.olat}' /> + <entry key='${shibboleth.user.mapping.key12.shib}' value='${shibboleth.user.mapping.key12.olat}' /> + <entry key='${shibboleth.user.mapping.key13.shib}' value='${shibboleth.user.mapping.key13.olat}' /> + <entry key='${shibboleth.user.mapping.key14.shib}' value='${shibboleth.user.mapping.key14.olat}' /> + <entry key='${shibboleth.user.mapping.key15.shib}' value='${shibboleth.user.mapping.key15.olat}' /> + <entry key='${shibboleth.user.mapping.key16.shib}' value='${shibboleth.user.mapping.key16.olat}' /> + <entry key='${shibboleth.user.mapping.key17.shib}' value='${shibboleth.user.mapping.key17.olat}' /> + <entry key='${shibboleth.user.mapping.key18.shib}' value='${shibboleth.user.mapping.key18.olat}' /> + <entry key='${shibboleth.user.mapping.key19.shib}' value='${shibboleth.user.mapping.key19.olat}' /> + <entry key='${shibboleth.user.mapping.key20.shib}' value='${shibboleth.user.mapping.key20.olat}' /> + </map> + </property> + <property name="attributeSelectableValues"><map></map></property> +</bean> + +<bean id="switchAttributeTranslator" class="org.olat.shibboleth.util.AttributeTranslator" > <property name="attributeTranslations"> <map> <!-- - Attributes to translate for easier reading/handling within OLAT. - Attributes will be available by their translated name (value) within OLAT. - - As an option, for each attribute predefined selectable values can be added as + Attributes to translate for easier reading/handling within OpenOLAT based + on the SWITCH AAI infrastructure. Attributes will be available by their + translated name (value) within OpenOLAT. + + As an option, for each attribute predefined selectable values can be added as in the example below. These are used in the course editors easy mode to display a list of items to choose from instead of a text input field. - - All attributes value and all selectableValue can be translated in the - ShibbolethModule package or the default package. When not translation is found, + + All attributes value and all selectableValue can be translated in the + ShibbolethModule package or the default package. When not translation is found, the keys defined in this file will be displayed. - + Example: To make a GUI translation of the attribute "urn:mace:switch.ch:attribute-def:swissEduPersonHomeOrganization" you must define an value="swissEduPersonHomeOrganization" and add some selectable values. Now in the i18n @@ -97,11 +221,11 @@ <entry key="Shib-SwissEP-StudyLevel" value="swissEduPersonStudyLevel" /> <entry key="Shib-SwissEP-StaffCategory" value="swissEduPersonStaffCategory" /> <!-- Is anyone using these attributes? it's not in the attribute-map.xml - <entry key="urn:mace:switch.ch:attribute-def:eduPersonOrgUnitDN" value="eduPersonOrgUnitDN" /> - <entry key="urn:mace:dir:attribute-def:eduPersonScopedAffiliation" value="eduPersonScopedAffiliation" /> + <entry key="urn:mace:switch.ch:attribute-def:eduPersonOrgUnitDN" value="eduPersonOrgUnitDN" /> + <entry key="urn:mace:dir:attribute-def:eduPersonScopedAffiliation" value="eduPersonScopedAffiliation" /> <entry key="urn:mace:dir:attribute-def:swissEduPersonGender" value="swissEduPersonGender" /> --> - <entry key="Shib-OrgPerson-postalAddress" value="postalAddress" /> + <entry key="Shib-OrgPerson-postalAddress" value="postalAddress" /> <entry key="Shib-InetOrgPerson-employeeNumber" value="employeeNumber" /> <entry key="Shib-Person-ou" value="organizationalUnit" /> <entry key="Shib-InetOrgPerson-preferredLanguage" value="PreferedLanguage" /> @@ -220,7 +344,7 @@ <value>81</value> <value>82</value> <value>83</value> - <value>84</value> + <value>84</value> <!-- University of Applied Sciences --> <value>10101</value> <value>10102</value> @@ -546,22 +670,22 @@ <value>304</value> <value>305</value> <value>306</value> - <value>307</value> - <value>308</value> + <value>307</value> + <value>308</value> </list> </entry> </map> </property> </bean> - <bean id="switchShibbolethAuthenticationConfigurator" class="org.olat.shibboleth.SwitchShibbolethAuthenticationConfigurator"> - <property name="wayfSPEntityID" value="${shibboleth.wayfSPEntityID}" /> + <bean id="switchShibbolethAuthenticationConfigurator" class="org.olat.shibboleth.SwitchShibbolethAuthenticationConfigurator"> + <property name="wayfSPEntityID" value="${shibboleth.wayfSPEntityID}" /> <property name="wayfSPHandlerURL" value="${shibboleth.wayfSPHandlerURL}" /> <property name="wayfSPSamlDSURL" value="${shibboleth.wayfSPSamlDSURL}" /> <property name="wayfReturnUrl" value="${shibboleth.wayfReturnUrl}" /> <property name="wayfReturnMobileUrl" value="${shibboleth.wayfReturnMobileUrl}" /> - <property name="additionalIdentityProviders" value="${shibboleth.wayf.additionalIDPs}" /> - </bean> + <property name="additionalIdentityProviders" value="${shibboleth.wayf.additionalIDPs}" /> + </bean> <bean id="registrationPresetUsername.byShibbolethAttribute" class="org.olat.shibboleth.ShibbolethUserNameFromAttributeUserNameCreationInterceptor" lazy-init="true"> diff --git a/src/main/java/org/olat/shibboleth/handler/DoNothingHandler.java b/src/main/java/org/olat/shibboleth/handler/DoNothingHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..7bde11e465cfb415e3c595f3982db54c95443c14 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/DoNothingHandler.java @@ -0,0 +1,39 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import org.springframework.stereotype.Component; + +/** + * This Handler does nothing that is it returns raw input. + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component("DoNothing") +class DoNothingHandler implements ShibbolethAttributeHandler { + + @Override + public String parse(String shibbolethAttributeValue) { + return shibbolethAttributeValue; + } + +} diff --git a/src/main/java/org/olat/shibboleth/handler/FirstValueHandler.java b/src/main/java/org/olat/shibboleth/handler/FirstValueHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..ae317a0842d49622ff0d863c3439d7bcb5f9bfd1 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/FirstValueHandler.java @@ -0,0 +1,46 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import org.olat.shibboleth.ShibbolethModule; +import org.springframework.stereotype.Component; + +/** + * A Shibboleth attribute may contain multiple values delimited by ";". This + * handler splits the Shibboleth attribute in its separate values and returns + * the first value. + * + * Initial date: 21.07.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component("FirstValue") +class FirstValueHandler implements ShibbolethAttributeHandler { + + @Override + public String parse(String shibbolethAttributeValue) { + if (shibbolethAttributeValue == null) return null; + + String[] values = shibbolethAttributeValue.split(ShibbolethModule.MULTIVALUE_SEPARATOR); + return values[0]; + } + +} diff --git a/src/main/java/org/olat/shibboleth/handler/SchacGenderHandler.java b/src/main/java/org/olat/shibboleth/handler/SchacGenderHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..df466055d170ca5b21056dcaedcdb1a2cc4e17a1 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/SchacGenderHandler.java @@ -0,0 +1,50 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import org.springframework.stereotype.Component; + +/** + * Handles the values from SchacGender (http://macedir.org/ontologies/attribute/2012-11-10/attributeOntologyDoc/schacgender.html) + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component("SchacGender") +class SchacGenderHandler implements ShibbolethAttributeHandler { + + private static final String GNEDER_DEFAULT = "-"; + + @Override + public String parse(String shibbolethAttributeValue) { + if (shibbolethAttributeValue == null) return GNEDER_DEFAULT; + + switch(shibbolethAttributeValue) { + case "1": + return "male"; + case "2": + return "female"; + default: + return GNEDER_DEFAULT; + } + } + +} diff --git a/src/main/java/org/olat/shibboleth/handler/ShibbolethAttributeHandler.java b/src/main/java/org/olat/shibboleth/handler/ShibbolethAttributeHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..9c5540f70071e0a75e208be3007327b737a13a95 --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/ShibbolethAttributeHandler.java @@ -0,0 +1,44 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +/** + * A ShibollethAttributeHandler parses the value of a Shibboleth attribute, so + * that the resulting value has the right form to use as a user property. For + * example a concrete implementation maps the Shibboleth gender values "1" and + * "2" to the user gender values "female" and "male". The implementation have to + * be Spring Services (use @Service) because they are get from the Spring + * application context by there name. + * + * Initial date: 21.07.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface ShibbolethAttributeHandler { + + /** + * Parses the value of the Shibboleth attribute. + * + * @param shibbolethAttributeValue + * @return + */ + public String parse(String shibbolethAttributeValue); +} diff --git a/src/main/java/org/olat/shibboleth/handler/ShibbolethAttributeHandlerFactory.java b/src/main/java/org/olat/shibboleth/handler/ShibbolethAttributeHandlerFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..7616d5f6d39395d791a9e6ada08999216ebb8ebd --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/ShibbolethAttributeHandlerFactory.java @@ -0,0 +1,37 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +/** + * + * Initial date: 05.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface ShibbolethAttributeHandlerFactory { + + /** + * + * @param handlerName + * @return the appropriate handler or a default handler if no handler was + * found. + */ + public ShibbolethAttributeHandler getHandler(String handlerName); +} diff --git a/src/main/java/org/olat/shibboleth/handler/SpringShibbolethAttributeHandlerFactory.java b/src/main/java/org/olat/shibboleth/handler/SpringShibbolethAttributeHandlerFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..ac9237b6a84d60ef472654034ec39c4a47e099aa --- /dev/null +++ b/src/main/java/org/olat/shibboleth/handler/SpringShibbolethAttributeHandlerFactory.java @@ -0,0 +1,65 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.springframework.stereotype.Component; + +/** + * + * Initial date: 05.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +public class SpringShibbolethAttributeHandlerFactory implements ShibbolethAttributeHandlerFactory { + + private static final OLog log = Tracing.createLoggerFor(SpringShibbolethAttributeHandlerFactory.class); + + private static final String DEFAULT_HANDLER_NAME = "DoNothing"; + + @Override + public ShibbolethAttributeHandler getHandler(String handlerName) { + ShibbolethAttributeHandler shibbolethAttributeHandler; + try { + shibbolethAttributeHandler = getHandlerByName(handlerName); + } catch (Exception e) { + if (StringHelper.containsNonWhitespace(handlerName)) { + log.warn("ShibbolethAttributeHandler '" + handlerName + + "' does not exist. Using the Default ShibbolethAttributeHandler '" + DEFAULT_HANDLER_NAME + + "'."); + } + shibbolethAttributeHandler = getDefaultHandler(); + } + return shibbolethAttributeHandler; + } + + private ShibbolethAttributeHandler getHandlerByName(String handlerName) { + return (ShibbolethAttributeHandler) CoreSpringFactory.getBean(handlerName); + } + + private ShibbolethAttributeHandler getDefaultHandler() { + return (ShibbolethAttributeHandler) CoreSpringFactory.getBean(DEFAULT_HANDLER_NAME); + } + +} diff --git a/src/main/java/org/olat/shibboleth/manager/DifferenceChecker.java b/src/main/java/org/olat/shibboleth/manager/DifferenceChecker.java new file mode 100644 index 0000000000000000000000000000000000000000..07694557c8c0495bb20cc92151492eccf625049c --- /dev/null +++ b/src/main/java/org/olat/shibboleth/manager/DifferenceChecker.java @@ -0,0 +1,56 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import org.olat.shibboleth.ShibbolethModule; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Helper to check if the value of an Shibboleth attribute and a user property + * are the same or if they are different. The comparison considers the settings + * in the OpenOLAT configuration. + * + * Initial date: 10.08.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +public class DifferenceChecker { + + @Autowired + private ShibbolethModule shibbolethModule; + + public boolean isDifferent(String shibbolethAttributeName, String shibbolethAttributeValue, String userPropertyValue) { + return (shibbolethAttributeValue == null && userPropertyValue != null && getDeleteIfNull(shibbolethAttributeName)) + || (shibbolethAttributeValue != null && userPropertyValue == null) + || (shibbolethAttributeValue != null && userPropertyValue != null && !shibbolethAttributeValue.equals(userPropertyValue)); + } + + private boolean getDeleteIfNull(String attributeName) { + try { + return shibbolethModule.getDeleteIfNull().get(attributeName); + } catch (Exception e) { + return true; + } + } + +} diff --git a/src/main/java/org/olat/shibboleth/manager/ShibbolethAdvanceOrderInput.java b/src/main/java/org/olat/shibboleth/manager/ShibbolethAdvanceOrderInput.java new file mode 100644 index 0000000000000000000000000000000000000000..cd5a363a1c9466468dad966f1f0469b113f3e76b --- /dev/null +++ b/src/main/java/org/olat/shibboleth/manager/ShibbolethAdvanceOrderInput.java @@ -0,0 +1,82 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import java.util.Set; + +import org.olat.core.id.Identity; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrderInput; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.olat.resource.accesscontrol.provider.auto.model.AutoAccessMethod; +import org.olat.shibboleth.ShibbolethModule; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * + * Initial date: 17.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +@Scope("prototype") +public class ShibbolethAdvanceOrderInput implements AdvanceOrderInput { + + @Autowired + private ShibbolethModule shibbolethModule; + + private Identity identity; + private String rawValues; + + @Override + public Class<? extends AutoAccessMethod> getMethodClass() { + return ShibbolethAutoAccessMethod.class; + } + + public void setIdentity(Identity identity) { + this.identity = identity; + } + + @Override + public Identity getIdentity() { + return identity; + } + + @Override + public Set<IdentifierKey> getKeys() { + return shibbolethModule.getAcAutoIdentifiers(); + } + + public void setRawValues(String rawValues) { + this.rawValues = rawValues; + } + + @Override + public String getRawValues() { + return rawValues; + } + + @Override + public String getSplitterType() { + return shibbolethModule.getAcAutoSplitter(); + } + +} diff --git a/src/main/java/org/olat/shibboleth/manager/ShibbolethAttributes.java b/src/main/java/org/olat/shibboleth/manager/ShibbolethAttributes.java new file mode 100644 index 0000000000000000000000000000000000000000..e5432590de197ff64bf83354b81bf60baba62aed --- /dev/null +++ b/src/main/java/org/olat/shibboleth/manager/ShibbolethAttributes.java @@ -0,0 +1,164 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.olat.core.id.User; +import org.olat.core.util.StringHelper; +import org.olat.shibboleth.ShibbolethModule; +import org.olat.shibboleth.handler.ShibbolethAttributeHandler; +import org.olat.shibboleth.handler.ShibbolethAttributeHandlerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * + * Initial date: 06.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +@Scope("prototype") +public class ShibbolethAttributes { + + private Map<String, String> shibbolethMap = new HashMap<>(0); + + @Autowired + private ShibbolethModule shibbolethModule; + @Autowired + private ShibbolethAttributeHandlerFactory shibbolethAttributeHandlerFactory; + @Autowired + private DifferenceChecker differenceChecker; + + public void init(Map<String, String> attributes) { + Collection<String> shibbolethAttributeNames = shibbolethModule.getShibbolethAttributeNames(); + shibbolethMap = new HashMap<>(shibbolethAttributeNames.size()); + + for (String attributeName : shibbolethAttributeNames) { + String attributeValue = attributes.get(attributeName); + ShibbolethAttributeHandler handler = getAttributeHandler(attributeName); + String parsedValue = handler.parse(attributeValue); + shibbolethMap.put(attributeName, parsedValue); + } + } + + private ShibbolethAttributeHandler getAttributeHandler(String attributeName) { + Map<String, String> handlerNames = shibbolethModule.getAttributeHandlerNames(); + String handlerName = handlerNames.get(attributeName); + return shibbolethAttributeHandlerFactory.getHandler(handlerName); + } + + public String getUID() { + String uidAttributeName = shibbolethModule.getUIDAttributeName(); + return getValueForAttributeName(uidAttributeName); + + } + + public String getPreferredLanguage() { + String langAttributeName = shibbolethModule.getPreferredLanguageAttributeName(); + return getValueForAttributeName(langAttributeName); + } + + public String getAcRawValues() { + String langAttributeName = shibbolethModule.getAcAutoAttributeName(); + return getValueForAttributeName(langAttributeName); + } + + public String getValueForAttributeName(String attributeName) { + return shibbolethMap.get(attributeName); + } + + public void setValueForUserPropertyName(String propertyName, String value) { + String attributeName = getShibbolethAttributeName(propertyName); + if (StringHelper.containsNonWhitespace(attributeName)) { + shibbolethMap.put(attributeName, value); + } + } + + public String getValueForUserPropertyName(String propertyName) { + String attributeName = getShibbolethAttributeName(propertyName); + return getValueForAttributeName(attributeName); + } + + private String getShibbolethAttributeName(String userProperty) { + if (userProperty == null) return null; + + for (Entry<String, String> mapping : getUserMappingEntrySet()) { + if (userProperty.equals(mapping.getValue())) { + return mapping.getKey(); + } + } + return null; + } + + public Map<String, String> toMap() { + return new HashMap<>(shibbolethMap); + } + + public boolean isAuthor() { + try { + String attributeValue = getValueForAttributeName(shibbolethModule.getAuthorMappingAttributeName()); + for (String isContained : shibbolethModule.getAuthorMappingContains()) { + if (attributeValue.contains(isContained)) { + return true; + } + } + return false; + } catch (Exception e) { + return false; + } + } + + public User syncUser(User user) { + for (Entry<String, String> mapping : getUserMappingEntrySet()) { + String shibbolethName = mapping.getKey(); + String shibbolethValue = getValueForAttributeName(shibbolethName); + String userValue = user.getProperty(mapping.getValue(), null); + String userPropertyName = mapping.getValue(); + if (differenceChecker.isDifferent(shibbolethName, shibbolethValue, userValue)) { + user.setProperty(userPropertyName, shibbolethValue); + } + } + return user; + } + + public boolean hasDifference(User user) { + for (Entry<String, String> mapping : getUserMappingEntrySet()) { + String shibbolethName = mapping.getKey(); + String shibbolethValue = getValueForAttributeName(shibbolethName); + String userValue = user.getProperty(mapping.getValue(), null); + if (differenceChecker.isDifferent(shibbolethName, shibbolethValue, userValue)) { + return true; + } + } + return false; + } + + private Set<Entry<String, String>> getUserMappingEntrySet() { + return shibbolethModule.getUserMapping().entrySet(); + } + +} diff --git a/src/main/java/org/olat/shibboleth/manager/ShibbolethAutoAccessHandler.java b/src/main/java/org/olat/shibboleth/manager/ShibbolethAutoAccessHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..81d39a87a774d2224453a24da96258dd58c2cbfc --- /dev/null +++ b/src/main/java/org/olat/shibboleth/manager/ShibbolethAutoAccessHandler.java @@ -0,0 +1,50 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import java.util.Locale; + +import org.olat.core.gui.translator.Translator; +import org.olat.core.util.Util; +import org.olat.resource.accesscontrol.provider.auto.AutoAccessHandler; +import org.olat.shibboleth.ShibbolethModule; +import org.springframework.stereotype.Component; + +/** + * + * Initial date: 17.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Component +public class ShibbolethAutoAccessHandler extends AutoAccessHandler { + public static final String METHOD_TYPE = "auto.shib.method"; + + @Override + public String getType() { + return METHOD_TYPE; + } + + @Override + public String getMethodName(Locale locale) { + Translator translator = Util.createPackageTranslator(ShibbolethModule.class, locale); + return translator.translate(METHOD_TYPE); + } +} diff --git a/src/main/java/org/olat/shibboleth/manager/ShibbolethAutoAccessMethod.java b/src/main/java/org/olat/shibboleth/manager/ShibbolethAutoAccessMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..1de0debf5d7fc177732fba0495b680c196b602aa --- /dev/null +++ b/src/main/java/org/olat/shibboleth/manager/ShibbolethAutoAccessMethod.java @@ -0,0 +1,45 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; + +import org.olat.resource.accesscontrol.provider.auto.model.AutoAccessMethod; + +/** + * + * Initial date: 17.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Entity(name="acautomethod") +@DiscriminatorValue(value="auto.shib.method") +public class ShibbolethAutoAccessMethod extends AutoAccessMethod { + + private static final long serialVersionUID = -241494885573765862L; + + @Override + public String getType() { + return ShibbolethAutoAccessHandler.METHOD_TYPE; + } + + +} diff --git a/src/main/java/org/olat/shibboleth/manager/ShibbolethManagerImpl.java b/src/main/java/org/olat/shibboleth/manager/ShibbolethManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..1f6f85ad6b8b82052cdc2162469c7f0d1740d7bb --- /dev/null +++ b/src/main/java/org/olat/shibboleth/manager/ShibbolethManagerImpl.java @@ -0,0 +1,141 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.BaseSecurityManager; +import org.olat.basesecurity.Constants; +import org.olat.basesecurity.SecurityGroup; +import org.olat.core.CoreSpringFactory; +import org.olat.core.id.Identity; +import org.olat.core.id.User; +import org.olat.resource.accesscontrol.AccessControlModule; +import org.olat.resource.accesscontrol.provider.auto.AutoAccessManager; +import org.olat.shibboleth.ShibbolethDispatcher; +import org.olat.shibboleth.ShibbolethManager; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 19.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Service +public class ShibbolethManagerImpl implements ShibbolethManager { + + private BaseSecurity securityManager; + + @Autowired + private AccessControlModule acModule; + @Autowired + private UserManager userManager; + @Autowired + private AutoAccessManager autoAccessManager; + + public ShibbolethManagerImpl() { + securityManager = BaseSecurityManager.getInstance(); + } + + @Override + public Identity createUser(String username, String shibbolethUniqueID, String language, ShibbolethAttributes shibbolethAttributes) { + if (shibbolethAttributes == null) return null; + + Identity identity = createUserAndPersist(username, shibbolethUniqueID, language, shibbolethAttributes); + addToUsersGroup(identity); + addToAuthorsGroup(identity, shibbolethAttributes); + createAndBookAdvanceOrders(identity, shibbolethAttributes); + + return identity; + } + + private Identity createUserAndPersist(String username, String shibbolethUniqueID, String language, ShibbolethAttributes shibbolethAttributes) { + User user = userManager.createUser(null, null, null); + user = shibbolethAttributes.syncUser(user); + user.getPreferences().setLanguage(language); + return securityManager.createAndPersistIdentityAndUser(username, null, user, ShibbolethDispatcher.PROVIDER_SHIB, shibbolethUniqueID); + } + + private void addToUsersGroup(Identity identity) { + securityManager.addIdentityToSecurityGroup(identity, getUsersSecurityGroup()); + } + + private void addToAuthorsGroup(Identity identity, ShibbolethAttributes shibbolethAttributes) { + if (shibbolethAttributes.isAuthor() && isNotInAuthorsGroup(identity)) { + securityManager.addIdentityToSecurityGroup(identity, getAuthorsSecurityGroup()); + } + } + + private boolean isNotInAuthorsGroup(Identity identity) { + return !securityManager.isIdentityInSecurityGroup(identity, getAuthorsSecurityGroup()); + } + + private SecurityGroup getUsersSecurityGroup() { + return securityManager.findSecurityGroupByName(Constants.GROUP_OLATUSERS); + } + + private SecurityGroup getAuthorsSecurityGroup() { + return securityManager.findSecurityGroupByName(Constants.GROUP_AUTHORS); + } + + private void createAndBookAdvanceOrders(Identity identity, ShibbolethAttributes shibbolethAttributes) { + if (acModule.isAutoEnabled()) { + createAdvanceOr(identity, shibbolethAttributes); + autoAccessManager.grantAccessToCourse(identity); + } + } + + private void createAdvanceOr(Identity identity, ShibbolethAttributes shibbolethAttributes) { + ShibbolethAdvanceOrderInput input = getShibbolethAdvanceOrderInput(); + input.setIdentity(identity); + String rawValues = shibbolethAttributes.getAcRawValues(); + input.setRawValues(rawValues); + autoAccessManager.createAdvanceOrders(input); + } + + @Override + public void syncUser(Identity identity, ShibbolethAttributes shibbolethAttributes) { + if (identity == null || shibbolethAttributes == null) { + return; + } + + User user = identity.getUser(); + syncAndPersistUser(user, shibbolethAttributes); + addToAuthorsGroup(identity, shibbolethAttributes); + createAndBookAdvanceOrders(identity, shibbolethAttributes); + } + + private void syncAndPersistUser(User user, ShibbolethAttributes shibbolethAttributes) { + if (shibbolethAttributes.hasDifference(user)) { + User syncedUser = shibbolethAttributes.syncUser(user); + userManager.updateUser(syncedUser); + } + } + + /** + * Because the static method of the CoreSpringFactory can not be mocked. + */ + protected ShibbolethAdvanceOrderInput getShibbolethAdvanceOrderInput() { + return CoreSpringFactory.getImpl(ShibbolethAdvanceOrderInput.class); + } + +} diff --git a/src/main/java/org/olat/shibboleth/util/AttributeTranslator.java b/src/main/java/org/olat/shibboleth/util/AttributeTranslator.java index 57eb2906d5dd8455b9cb66cb30d1d02d0187ba64..6c9a9a12a00135fc9d539f35ffdcad2bb3944179 100644 --- a/src/main/java/org/olat/shibboleth/util/AttributeTranslator.java +++ b/src/main/java/org/olat/shibboleth/util/AttributeTranslator.java @@ -36,23 +36,26 @@ public class AttributeTranslator { // contains the mapping from the shib-attribute to the simplified shib attribute private Map<String, String> attributeTranslations; - // contains predefined values that can be selected for a specific shib-attribute. - // Note that as key the simplified shib attribute is used and not the original + // contains predefined values that can be selected for a specific shib-attribute. + // Note that as key the simplified shib attribute is used and not the original // attributes (see attributeTranslations map) private Map<String, List<String>> attributeSelectableValues; - + /** * [used by spring] */ public AttributeTranslator() { // } - + /** * [used by spring] */ public void setAttributeTranslations(Map<String, String> attributeTranslations) { this.attributeTranslations = attributeTranslations; + // cleanup empty value + this.attributeTranslations.remove(""); + this.attributeTranslations.remove(" "); } @@ -61,26 +64,31 @@ public class AttributeTranslator { */ public void setAttributeSelectableValues(Map<String, List<String>> attributeSelectableValues) { this.attributeSelectableValues = attributeSelectableValues; + // cleanup empty value + this.attributeTranslations.remove(""); + this.attributeTranslations.remove(" "); } - + public final Map<String, String> translateAttributesMap(Map<String, String> attributesMap) { - Map<String, String> convertedMap = new HashMap<String, String>(attributesMap.size()); + Map<String, String> convertedMap = new HashMap<>(attributesMap.size()); Iterator<String> keys = attributesMap.keySet().iterator(); while (keys.hasNext()) { String attribute = keys.next(); String translatedKey = translateAttribute(attribute); String value = attributesMap.get(attribute); - convertedMap.put(translatedKey, value); } return convertedMap; } - - + + /** - * Translate Shibboleth Attributes according to configured attribute translations + * Translate Shibboleth Attributes according to configured attribute + * translations. If not attribute translator is found, use the untranslated + * attribute name. + * * @param inName * @return Translated attribute name. */ @@ -92,19 +100,19 @@ public class AttributeTranslator { /** * Get all valid values for this attribute if such values are defined. When no * values are defined, NULL will be returned. - * + * * @param attribute * @return */ public String[] getSelectableValuesForAttribute(String attribute) { - List<String> list = attributeSelectableValues.get(attribute); + List<String> list = attributeSelectableValues.get(attribute); if(list!=null) { //only some attributes have selectable values - return list.toArray(new String[0]); + return list.toArray(new String[0]); } return new String[0]; } - + /** * Get all attributes identifiers that can be translated * @return @@ -112,5 +120,5 @@ public class AttributeTranslator { public Set<String> getTranslateableAttributes() { return this.attributeTranslations.keySet(); } - + } diff --git a/src/main/java/org/olat/shibboleth/util/ShibbolethAttribute.java b/src/main/java/org/olat/shibboleth/util/ShibbolethAttribute.java deleted file mode 100644 index d1e9b62bb1ec564d684bfca7111cffeb73389b41..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/shibboleth/util/ShibbolethAttribute.java +++ /dev/null @@ -1,109 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.shibboleth.util; - -import java.io.UnsupportedEncodingException; -import java.util.regex.Pattern; - -import org.olat.core.logging.AssertException; -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; -import org.olat.core.util.StringHelper; - -/** - * Description:<br> - * Represents a shibboleth attribut, which may contain values delimited by ";". - * - * - * <P> - * Initial Date: Oct 27, 2010 <br> - * @author patrick - */ -public final class ShibbolethAttribute{ - - private static final OLog log = Tracing.createLoggerFor(ShibbolethAttribute.class); - - private static final Pattern SPLITTER = Pattern.compile(";"); - private final String attributeName; - private final String originalValue; - private final String[] splittedValues; - - private final static ShibbolethAttribute INVALID_ATTRIBUTE = new ShibbolethAttribute("INVALIDMARKED","INVALIDMARKED"); - - ShibbolethAttribute(String name, String value) { - if(isInvalidValue(value)){ - throw new IllegalArgumentException("value must be not null and not empty"); - } - - this.attributeName = name; - this.originalValue = value; - this.splittedValues = SPLITTER.split(value); - } - - public String getName(){ - return attributeName; - } - - public String getValueString(){ - return originalValue; - } - - public String[] getValues(){ - return splittedValues; - } - - String getFirstValue(){ - return splittedValues[0]; - } - - public boolean isValid(){ - return this != INVALID_ATTRIBUTE; - } - - - public static ShibbolethAttribute createFromUserRequestValue(String name, String rawRequestValue){ - if(isInvalidValue(rawRequestValue)){ - if(log.isDebug()){ - log.debug("invalid attribute: " + name + " attributeValue: " + rawRequestValue); - } - return INVALID_ATTRIBUTE; - } - - try { - - String utf8Value = new String(rawRequestValue.getBytes("ISO-8859-1"), "UTF-8"); - return new ShibbolethAttribute(name, utf8Value); - - } catch (UnsupportedEncodingException e) { - //bad luck - throw new AssertException("ISO-8859-1, or UTF-8 Encoding not supported",e); - } - } - - private static boolean isInvalidValue(String value){ - return ( ! StringHelper.containsNonWhitespace(value)); - } - -} diff --git a/src/main/java/org/olat/shibboleth/util/ShibbolethHelper.java b/src/main/java/org/olat/shibboleth/util/ShibbolethHelper.java deleted file mode 100644 index 3c6ff18be57472d8ea9d9198dd590ce3c14fd4ea..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/shibboleth/util/ShibbolethHelper.java +++ /dev/null @@ -1,47 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.shibboleth.util; - -import java.util.Map; - -/** - * Initial Date: Oct 29, 2010 <br> - * @author patrick - */ -public class ShibbolethHelper { - - /** - * @return the first value of a multivalue shibboleth attribute, works also for singlevalue attributes. - */ - public static String getFirstValueOf(String attributeName, Map<String, String> shibbolethAttributesMap) { - String attrVal = shibbolethAttributesMap.get(attributeName); - if (attrVal != null) { - ShibbolethAttribute multivalueShibbAttributeEmail = new ShibbolethAttribute(attributeName, attrVal); - return multivalueShibbAttributeEmail.getFirstValue(); - } - else return null; - } - -} diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_11_4_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_11_4_0.java index b53359fe7228deb456f5f8d41deb9597766b80f2..194e20f6d7f1d1da8e6d63be13f7cf4aa824aef1 100644 --- a/src/main/java/org/olat/upgrade/OLATUpgrade_11_4_0.java +++ b/src/main/java/org/olat/upgrade/OLATUpgrade_11_4_0.java @@ -24,7 +24,7 @@ import java.util.List; import org.olat.basesecurity.GroupRoles; import org.olat.collaboration.CollaborationTools; import org.olat.collaboration.CollaborationToolsFactory; -import org.olat.commons.info.manager.InfoMessageFrontendManager; +import org.olat.commons.info.InfoMessageFrontendManager; import org.olat.commons.info.model.InfoMessageImpl; import org.olat.core.commons.persistence.DB; import org.olat.core.gui.translator.Translator; diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_12_0_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_12_0_0.java index be32cc7b32c2ec7b44c45edbe98b1a8e8976ed45..4cb4d3151e53ab4a467e774614b4516b26bfc4af 100644 --- a/src/main/java/org/olat/upgrade/OLATUpgrade_12_0_0.java +++ b/src/main/java/org/olat/upgrade/OLATUpgrade_12_0_0.java @@ -19,13 +19,51 @@ */ package org.olat.upgrade; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Paths; import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Properties; +import java.util.Set; +import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.core.id.Roles; +import org.olat.core.util.WebappHelper; +import org.olat.course.CorruptedCourseException; +import org.olat.course.CourseFactory; +import org.olat.course.ICourse; +import org.olat.course.assessment.AssessmentHelper; +import org.olat.course.assessment.manager.EfficiencyStatementManager; +import org.olat.course.assessment.model.UserEfficiencyStatementImpl; +import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.IQTESTCourseNode; +import org.olat.course.nodes.MSCourseNode; +import org.olat.course.nodes.ScormCourseNode; +import org.olat.course.nodes.iq.IQEditController; +import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.fileresource.types.BlogFileResource; +import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.fileresource.types.PodcastFileResource; +import org.olat.ims.qti.QTIResultSet; +import org.olat.ims.qti21.AssessmentTestSession; +import org.olat.ims.qti21.QTI21Service; +import org.olat.modules.assessment.AssessmentService; +import org.olat.modules.assessment.model.AssessmentEntryImpl; +import org.olat.modules.iq.IQManager; import org.olat.modules.webFeed.manager.FeedManager; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryEntryRef; +import org.olat.repository.RepositoryManager; +import org.olat.repository.model.SearchRepositoryEntryParameters; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.springframework.beans.factory.annotation.Autowired; @@ -38,13 +76,27 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class OLATUpgrade_12_0_0 extends OLATUpgrade { + private static final int BATCH_SIZE = 50; + private static final String VERSION = "OLAT_12.0.0"; private static final String FEED_XML_TO_DB = "FEED XML TO DB"; + private static final String USER_PROPERTY_CONTEXT_RENAME = "USER PROPERTY CONTEXT RENAME"; + private static final String LAST_USER_MODIFICATION = "LAST USER MODIFICATION"; @Autowired private DB dbInstance; @Autowired - FeedManager feedManager; + private FeedManager feedManager; + @Autowired + private QTI21Service qtiService; + @Autowired + private IQManager iqManager; + @Autowired + private AssessmentService assessmentService; + @Autowired + private RepositoryManager repositoryManager; + @Autowired + private EfficiencyStatementManager efficiencyStatementManager; public OLATUpgrade_12_0_0() { super(); @@ -71,8 +123,12 @@ public class OLATUpgrade_12_0_0 extends OLATUpgrade { } boolean allOk = true; + // migrate all blogs and podcasts from xml to database data structure allOk &= upgradeBlogXmlToDb(upgradeManager, uhd); - + // rename a user property context name to a more suitable name + allOk &= changeUserPropertyContextName(upgradeManager, uhd); + allOk &= upgradeLastModified(upgradeManager, uhd); + uhd.setInstallationComplete(allOk); upgradeManager.setUpgradesHistory(uhd, VERSION); if(allOk) { @@ -106,5 +162,239 @@ public class OLATUpgrade_12_0_0 extends OLATUpgrade { } return allOk; } + + /** + * Copy existing user property configuration to the new user property + * context handler name. The handler was renamed because it is now not only + * used in the course but also in the group. + * + * @param upgradeManager + * @param uhd + * @return + */ + private boolean changeUserPropertyContextName(UpgradeManager upgradeManager, UpgradeHistoryData uhd) { + boolean allOk = true; + if (!uhd.getBooleanDataValue(USER_PROPERTY_CONTEXT_RENAME)) { + // Load configured properties from properties file + String userDataDirectory = WebappHelper.getUserDataRoot(); + File configurationPropertiesFile = Paths.get(userDataDirectory, "system", "configuration", "com.frentix.olat.admin.userproperties.UsrPropCfgManager.properties").toFile(); + if (configurationPropertiesFile.exists()) { + InputStream is = null; + OutputStream fileStream = null; + try { + is = new FileInputStream(configurationPropertiesFile); + Properties configuredProperties = new Properties(); + configuredProperties.load(is); + is.close(); + boolean dirty = false; + // list of possible user property appendices + List<String> appendices = Arrays.asList("", "_hndl_", "_hndl_mandatory", "_hndl_usrreadonly", "_hndl_adminonly"); + for (String appendix : appendices) { + String oldKey = "org.olat.course.nodes.members.MembersCourseNodeRunController" + appendix; + String existingConfig = configuredProperties.getProperty(oldKey); + String newKey = "org.olat.commons.memberlist.ui.MembersPrintController" + appendix; + String existingNewConfig = configuredProperties.getProperty(newKey); + if (existingConfig != null && existingNewConfig == null) { + configuredProperties.setProperty("org.olat.commons.memberlist.ui.MembersPrintController" + appendix, existingConfig); + dirty = true; + log.info("Migrated user property context handler config from::" + oldKey + " to::" + newKey); + } + } + if (dirty) { + fileStream = new FileOutputStream(configurationPropertiesFile); + configuredProperties.store(fileStream, null); + // Flush and close before sending events to other nodes to make changes appear on other node + fileStream.flush(); + } + } catch (Exception e) { + log.error("Error when reading / writing user properties config file from path::" + configurationPropertiesFile.getAbsolutePath(), e); + allOk &= false; + } finally { + try { + if (is != null ) is.close(); + if (fileStream != null ) fileStream.close(); + } catch (Exception e) { + log.error("Could not close stream after storing config to file::" + configurationPropertiesFile.getAbsolutePath(), e); + allOk &= false; + } + } + } + + uhd.setBooleanDataValue(USER_PROPERTY_CONTEXT_RENAME, allOk); + upgradeManager.setUpgradesHistory(uhd, VERSION); + } + return allOk; + } + + private boolean upgradeLastModified(UpgradeManager upgradeManager, UpgradeHistoryData uhd) { + boolean allOk = true; + if (!uhd.getBooleanDataValue(LAST_USER_MODIFICATION)) { + + int counter = 0; + final Roles roles = new Roles(true, true, true, true, false, true, false); + final SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(); + params.setRoles(roles); + params.setResourceTypes(Collections.singletonList("CourseModule")); + + List<RepositoryEntry> courses; + do { + courses = repositoryManager.genericANDQueryWithRolesRestriction(params, counter, 50, true); + for(RepositoryEntry course:courses) { + try { + allOk &= processCourseAssessmentLastModified(course); + } catch (CorruptedCourseException e) { + log.error("Corrupted course: " + course.getKey(), e); + } + } + counter += courses.size(); + log.audit("Last modifications migration processed: " + courses.size() + ", total courses processed (" + counter + ")"); + dbInstance.commitAndCloseSession(); + } while(courses.size() == BATCH_SIZE); + + + uhd.setBooleanDataValue(LAST_USER_MODIFICATION, allOk); + upgradeManager.setUpgradesHistory(uhd, VERSION); + } + return allOk; + } + + + private boolean processCourseAssessmentLastModified(RepositoryEntry entry) { + try { + ICourse course = CourseFactory.loadCourse(entry); + CourseNode rootNode = course.getRunStructure().getRootNode(); + Set<Identity> changeSet = new HashSet<>(); + processCourseNodeAssessmentLastModified(course, entry, rootNode, changeSet); + dbInstance.commitAndCloseSession(); + + //update structure nodes and efficiency statement if any + Set<Identity> identitiesWithEfficiencyStatements = findIdentitiesWithEfficiencyStatements(entry); + for(Identity assessedIdentity:changeSet) { + UserCourseEnvironment userCourseEnv = AssessmentHelper + .createInitAndUpdateUserCourseEnvironment(assessedIdentity, course); + if(identitiesWithEfficiencyStatements.contains(assessedIdentity)) { + efficiencyStatementManager.updateUserEfficiencyStatement(userCourseEnv); + } + dbInstance.commitAndCloseSession(); + } + } catch(CorruptedCourseException e) { + log.error("Corrupted course: " + entry.getKey(), e); + } catch (Exception e) { + log.error("Unexpected error", e); + } finally { + dbInstance.commitAndCloseSession(); + } + return true; + } + + private boolean processCourseNodeAssessmentLastModified(ICourse course, RepositoryEntry entry, CourseNode courseNode, Set<Identity> changeSet) { + if(courseNode instanceof IQTESTCourseNode) { + updateTest(entry, (IQTESTCourseNode)courseNode, changeSet); + } else if(courseNode instanceof MSCourseNode) { + updateMS(entry, courseNode, changeSet); + } else if(courseNode instanceof ScormCourseNode) { + updateScorm(course, entry, courseNode, changeSet); + } + dbInstance.commitAndCloseSession(); + + for(int i=courseNode.getChildCount(); i-->0; ) { + CourseNode child = (CourseNode)courseNode.getChildAt(i); + processCourseNodeAssessmentLastModified(course, entry, child, changeSet); + } + return true; + } + + private void updateTest(RepositoryEntry entry, IQTESTCourseNode courseNode, Set<Identity> changeSet) { + boolean onyx = IQEditController.CONFIG_VALUE_QTI2.equals(courseNode.getModuleConfiguration().get(IQEditController.CONFIG_KEY_TYPE_QTI)); + if (onyx) return; + + RepositoryEntry testEntry = courseNode.getReferencedRepositoryEntry(); + OLATResource ores = testEntry.getOlatResource(); + boolean qti21 = ImsQTI21Resource.TYPE_NAME.equals(ores.getResourceableTypeName()); + + List<AssessmentEntryImpl> assessmentEntries = loadAssessmentEntries(entry, courseNode.getIdent()); + for(AssessmentEntryImpl assessmentEntry:assessmentEntries) { + if(assessmentEntry.getLastUserModified() != null || assessmentEntry.getLastCoachModified() != null) continue; + + if(qti21) { + Long assessmentId = assessmentEntry.getAssessmentId(); + if(assessmentId != null) { + AssessmentTestSession session = qtiService.getAssessmentTestSession(assessmentEntry.getAssessmentId()); + if(session != null && session.getFinishTime() != null) { + assessmentEntry.setLastUserModified(session.getFinishTime()); + assessmentService.updateAssessmentEntry(assessmentEntry); + changeSet.add(assessmentEntry.getIdentity()); + } + } + } else { + long olatResource = entry.getOlatResource().getResourceableId().longValue(); + QTIResultSet rset = iqManager.getLastResultSet(assessmentEntry.getIdentity(), olatResource, courseNode.getIdent()); + if(rset != null && rset.getLastModified() != null ) { + assessmentEntry.setLastUserModified(rset.getLastModified()); + assessmentService.updateAssessmentEntry(assessmentEntry); + changeSet.add(assessmentEntry.getIdentity()); + } + } + } + } + private void updateMS(RepositoryEntry entry, CourseNode msNode, Set<Identity> changeSet) { + List<AssessmentEntryImpl> assessmentEntries = loadAssessmentEntries(entry, msNode.getIdent()); + for(AssessmentEntryImpl assessmentEntry:assessmentEntries) { + if(assessmentEntry.getLastCoachModified() != null) continue; + + assessmentEntry.setLastCoachModified(assessmentEntry.getLastModified()); + assessmentService.updateAssessmentEntry(assessmentEntry); + changeSet.add(assessmentEntry.getIdentity()); + } + } + + private void updateScorm(ICourse course, RepositoryEntry entry, CourseNode scormNode, Set<Identity> changeSet) { + Long courseId = course.getResourceableId(); + String courseIdNodeId = courseId + "-" + scormNode.getIdent(); + Calendar cal = Calendar.getInstance(); + + List<AssessmentEntryImpl> assessmentEntries = loadAssessmentEntries(entry, scormNode.getIdent()); + for(AssessmentEntryImpl assessmentEntry:assessmentEntries) { + if(assessmentEntry.getLastUserModified() != null || assessmentEntry.getLastCoachModified() != null) continue; + + String userId = assessmentEntry.getIdentity().getName(); + String path = FolderConfig.getCanonicalRoot() + "/scorm/" + userId + "/" + courseIdNodeId; + File quiz = new File(path, "thequiz.xml"); + if(quiz.exists()) { + long lastModified = quiz.lastModified(); + if(lastModified > 0) { + cal.setTimeInMillis(lastModified); + assessmentEntry.setLastUserModified(cal.getTime()); + assessmentService.updateAssessmentEntry(assessmentEntry); + changeSet.add(assessmentEntry.getIdentity()); + } + } + } + } + + private List<AssessmentEntryImpl> loadAssessmentEntries(RepositoryEntryRef courseEntry, String subIdent) { + StringBuilder sb = new StringBuilder(); + sb.append("select data from assessmententry data") + .append(" inner join fetch data.identity ident") + .append(" where data.repositoryEntry.key=:courseEntryKey and data.subIdent=:subIdent") + .append(" and data.lastUserModified is null and data.lastCoachModified is null"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), AssessmentEntryImpl.class) + .setParameter("courseEntryKey", courseEntry.getKey()) + .setParameter("subIdent", subIdent) + .getResultList(); + } + + private Set<Identity> findIdentitiesWithEfficiencyStatements(RepositoryEntryRef courseRepoEntry) { + StringBuilder sb = new StringBuilder(); + sb.append("select distinct(statement.identity) from ").append(UserEfficiencyStatementImpl.class.getName()).append(" as statement ") + .append(" where statement.lastUserModified is null and statement.lastCoachModified is null and statement.courseRepoKey=:repoKey"); + + List<Identity> identities = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Identity.class) + .setParameter("repoKey", courseRepoEntry.getKey()) + .getResultList(); + return new HashSet<>(identities); + } } diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_8_1_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_8_1_0.java index 0584402f61706c3c384ae6ecd2efa6926b33f91c..30e7b4ff2dc318ee63ccd98dcb0d895cdb223cbe 100644 --- a/src/main/java/org/olat/upgrade/OLATUpgrade_8_1_0.java +++ b/src/main/java/org/olat/upgrade/OLATUpgrade_8_1_0.java @@ -173,7 +173,7 @@ public class OLATUpgrade_8_1_0 extends OLATUpgrade { } EfficiencyStatement s = (EfficiencyStatement)XStreamHelper.createXStreamInstance().fromXML(property.getTextValue()); - efficiencyStatementManager.fillEfficiencyStatement(s, statement); + efficiencyStatementManager.fillEfficiencyStatement(s, null, statement); statement.setLastModified(property.getLastModified()); dbInstance.saveObject(statement); diff --git a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml index 495d502efebfbd6b2fd3231ae64f3e16bbe43614..b31bec41be79fac6c8e89ace77f0da11b36c08ac 100644 --- a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml +++ b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml @@ -2,9 +2,9 @@ <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" - http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - + <bean id="databaseUpgrader" class="org.olat.upgrade.DatabaseUpgradeManager" init-method="init" depends-on="org.olat.core.util.WebappHelper"> <property name="dbVendor" value="${db.vendor}"/> @@ -148,6 +148,14 @@ <constructor-arg index="0" value="OLAT_12.0.0" /> <property name="alterDbStatements" value="alter_11_5_x_to_12_0_0.sql" /> </bean> + <bean id="database_upgrade_12_0_1" class="org.olat.upgrade.DatabaseUpgrade"> + <constructor-arg index="0" value="OLAT_12.0.1" /> + <property name="alterDbStatements" value="alter_12_0_0_to_12_0_1.sql" /> + </bean> + <bean id="database_upgrade_12_1_0" class="org.olat.upgrade.DatabaseUpgrade"> + <constructor-arg index="0" value="OLAT_12.1.0" /> + <property name="alterDbStatements" value="alter_12_0_x_to_12_1_0.sql" /> + </bean> </list> </property> </bean> diff --git a/src/main/java/org/olat/user/ChangePasswordController.java b/src/main/java/org/olat/user/ChangePasswordController.java index bb8689d47bc73129c1f3341700add980e883e1a3..8e88aacc94fdcefe7369dd3cd71b66260a563c84 100644 --- a/src/main/java/org/olat/user/ChangePasswordController.java +++ b/src/main/java/org/olat/user/ChangePasswordController.java @@ -139,11 +139,12 @@ public class ChangePasswordController extends BasicController implements Support String oldPwd = chPwdForm.getOldPasswordValue(); Identity provenIdent = null; - - if (securityManager.findAuthentication(ureq.getIdentity(), LDAPAuthenticationController.PROVIDER_LDAP) != null) { + Authentication ldapAuthentication = securityManager.findAuthentication(ureq.getIdentity(), LDAPAuthenticationController.PROVIDER_LDAP); + if (ldapAuthentication != null) { LDAPError ldapError = new LDAPError(); //fallback to OLAT if enabled happen automatically in LDAPAuthenticationController - provenIdent = ldapLoginManager.authenticate(ureq.getIdentity().getName(), oldPwd, ldapError); + String userName = ldapAuthentication.getAuthusername(); + provenIdent = ldapLoginManager.authenticate(userName, oldPwd, ldapError); } else if(securityManager.findAuthentication(ureq.getIdentity(), BaseSecurityModule.getDefaultAuthProviderIdentifier()) != null) { provenIdent = olatAuthenticationSpi.authenticate(ureq.getIdentity(), ureq.getIdentity().getName(), oldPwd); } @@ -152,8 +153,7 @@ public class ChangePasswordController extends BasicController implements Support showError("error.password.noauth"); } else { String newPwd = chPwdForm.getNewPasswordValue(); - if(olatAuthenticationSpi.changePassword(ureq.getIdentity(), provenIdent, newPwd)) { - //TODO: verify that we are NOT in a transaction (changepwd should be commited immediately) + if(olatAuthenticationSpi.changePassword(ureq.getIdentity(), provenIdent, newPwd)) { fireEvent(ureq, Event.DONE_EVENT); getLogger().audit("Changed password for identity."+provenIdent.getName()); showInfo("password.successful"); diff --git a/src/main/java/org/olat/user/ChangePasswordForm.java b/src/main/java/org/olat/user/ChangePasswordForm.java index ae5e91417a45f961d566a3080d05bb5cadfcb638..9383ce8ebdf72809ff1c1ebf41fda2d5a017e2f1 100644 --- a/src/main/java/org/olat/user/ChangePasswordForm.java +++ b/src/main/java/org/olat/user/ChangePasswordForm.java @@ -33,6 +33,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.springframework.beans.factory.annotation.Autowired; /** @@ -52,6 +53,9 @@ public class ChangePasswordForm extends FormBasicController { private String _oldpass = ""; private String _newpass = ""; + + @Autowired + private UserManager userManager; /** * @param name @@ -95,17 +99,23 @@ public class ChangePasswordForm extends FormBasicController { @Override protected boolean validateFormLogic (UserRequest ureq) { - if (!UserManager.getInstance().syntaxCheckOlatPassword(newpass1.getValue())) { + boolean allOk = true; + newpass1.clearError(); + newpass2.clearError(); + + if (!userManager.syntaxCheckOlatPassword(newpass1.getValue())) { newpass1.setErrorKey("form.checkPassword", null); - return false; + allOk &= false; } + if (!newpass1.getValue().equals(newpass2.getValue())) { newpass1.setValue(""); newpass2.setValue(""); newpass2.setErrorKey("error.password.nomatch", null); - return false; + allOk &= false; } - return true; + + return allOk & super.validateFormLogic(ureq); } @Override diff --git a/src/main/java/org/olat/user/ChangePrefsController.java b/src/main/java/org/olat/user/ChangePrefsController.java index f5c493e634efbb91f1216fd96096550c30e9e39c..0d1bd3f44c091716c9dd64a486036b67e6e18080 100644 --- a/src/main/java/org/olat/user/ChangePrefsController.java +++ b/src/main/java/org/olat/user/ChangePrefsController.java @@ -52,7 +52,7 @@ import org.olat.core.id.context.HistoryModule; import org.olat.core.util.StringHelper; import org.olat.core.util.UserSession; import org.olat.core.util.WebappHelper; -import org.olat.core.util.i18n.I18nManager; +import org.olat.core.util.i18n.I18nModule; import org.olat.core.util.prefs.Preferences; import org.olat.core.util.prefs.PreferencesFactory; import org.olat.core.util.session.UserSessionManager; @@ -296,11 +296,13 @@ class UserPrefsResetForm extends FormBasicController { private MultipleSelectionElement resetElements; private String[] keys, values; - private final UserSessionManager sessionManager; + @Autowired + private I18nModule i18nModule; + @Autowired + private UserSessionManager sessionManager; public UserPrefsResetForm(UserRequest ureq, WindowControl wControl, Identity changeableIdentity) { super(ureq, wControl); - sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class); tobeChangedIdentity = changeableIdentity; initForm(ureq); } @@ -363,7 +365,7 @@ class UserPrefsResetForm extends FormBasicController { if(logout) { //if logout, need a redirect to the login page - String lang = I18nManager.getInstance().getLocaleKey(ureq.getLocale()); + String lang = i18nModule.getLocaleKey(ureq.getLocale()); ureq.getDispatchResult().setResultingMediaResource( new RedirectMediaResource(WebappHelper.getServletContextPath() + "/dmz/?lang=" + lang + "&logout=true")); } diff --git a/src/main/java/org/olat/user/PreferencesFormController.java b/src/main/java/org/olat/user/PreferencesFormController.java index 76ef2677b9f61b3c3d615498c243a72b6b2d2db5..981570a7e58d6406181abd1806d22a72e20693ce 100644 --- a/src/main/java/org/olat/user/PreferencesFormController.java +++ b/src/main/java/org/olat/user/PreferencesFormController.java @@ -50,6 +50,7 @@ import org.olat.core.util.Util; import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nModule; import org.olat.core.util.mail.MailModule; +import org.springframework.beans.factory.annotation.Autowired; /** * This form controller provides an interface to change the user's system @@ -70,6 +71,9 @@ public class PreferencesFormController extends FormBasicController { private Identity tobeChangedIdentity; private SingleSelection language, fontsize, charset, notificationInterval, mailSystem; private static final String[] mailIntern = new String[]{"intern.only","send.copy"}; + + @Autowired + private I18nModule i18nModule; /** * Constructor for the user preferences form @@ -193,7 +197,7 @@ public class PreferencesFormController extends FormBasicController { String langKey = prefs.getLanguage(); // Preselect the users language if available. Maye not anymore enabled on // this server - if (prefs.getLanguage() != null && I18nModule.getEnabledLanguageKeys().contains(langKey)) { + if (prefs.getLanguage() != null && i18nModule.getEnabledLanguageKeys().contains(langKey)) { language.select(prefs.getLanguage(), true); } else { language.select(I18nModule.getDefaultLocale().toString(), true); diff --git a/src/main/java/org/olat/user/UserImpl.java b/src/main/java/org/olat/user/UserImpl.java index 97bd673daf327ad2ff554bfaedf4bebfcafd324b..7b0fba26c4a380086ea04c4a9a07412914252358 100644 --- a/src/main/java/org/olat/user/UserImpl.java +++ b/src/main/java/org/olat/user/UserImpl.java @@ -318,6 +318,7 @@ public class UserImpl implements Persistable, User { this.firstName = firstName; } + @Override public String getLastName() { return lastName; } @@ -326,6 +327,7 @@ public class UserImpl implements Persistable, User { this.lastName = lastName; } + @Override public String getEmail() { return email; } @@ -334,6 +336,15 @@ public class UserImpl implements Persistable, User { this.email = email; } + @Override + public String getInstitutionalEmail() { + return institutionalEmail; + } + + public void setInstitutionalEmail(String institutionalEmail) { + this.institutionalEmail = institutionalEmail; + } + public boolean isWebdav() { return webdav; } diff --git a/src/main/java/org/olat/user/UserManager.java b/src/main/java/org/olat/user/UserManager.java index cbcc3c2c5d0acbe57c2ebc117c4602a030b625f9..83019cab1e04559469e8b8dcd115aad4c3ce1a9d 100644 --- a/src/main/java/org/olat/user/UserManager.java +++ b/src/main/java/org/olat/user/UserManager.java @@ -84,9 +84,25 @@ public abstract class UserManager extends BasicManager { */ public abstract User createUser(String firstName, String lastName, String eMail); + /** + * Find all user database keys where the given property name matches the property + * value (exact match) + * + * @param propName + * @param propValue + * @return + */ public abstract List<Long> findUserKeyWithProperty(String propName, String propValue); - public abstract Identity findIdentityKeyWithProperty(String propName, String propValue); + /** + * Find all identities where the given property name matches the property + * value (exact match) + * + * @param propName + * @param propValue + * @return The list of identities or NULL if nothing found + */ + public abstract List<Identity> findIdentitiesWithProperty(String propName, String propValue); /** * Find the identity (and the user) that match the given email address. The diff --git a/src/main/java/org/olat/user/UserManagerImpl.java b/src/main/java/org/olat/user/UserManagerImpl.java index a818d2659ba880ec3640b7468614c3d30103c85f..4cf8b9a35394377d7cd0d20037c0f78b76dc0d35 100644 --- a/src/main/java/org/olat/user/UserManagerImpl.java +++ b/src/main/java/org/olat/user/UserManagerImpl.java @@ -159,7 +159,7 @@ public class UserManagerImpl extends UserManager { } @Override - public Identity findIdentityKeyWithProperty(String propName, String propValue) { + public List<Identity> findIdentitiesWithProperty(String propName, String propValue) { StringBuilder sb = new StringBuilder("select identity from ").append(IdentityImpl.class.getName()).append(" identity ") .append(" inner join fetch identity.user user ") .append(" where user.").append(propName).append("=:propValue"); @@ -170,7 +170,7 @@ public class UserManagerImpl extends UserManager { if(userKeys.isEmpty()) { return null; } - return userKeys.get(0); + return userKeys; } /** diff --git a/src/main/java/org/olat/user/WebDAVPasswordController.java b/src/main/java/org/olat/user/WebDAVPasswordController.java index 517e67822ee9450d8c24d5ffda55334afc599d23..0527c7a643d1726949e1929b592ce6930e72f62f 100644 --- a/src/main/java/org/olat/user/WebDAVPasswordController.java +++ b/src/main/java/org/olat/user/WebDAVPasswordController.java @@ -87,7 +87,16 @@ public class WebDAVPasswordController extends FormBasicController { accessDataFlc = FormLayoutContainer.createDefaultFormLayout("flc_access_data", getTranslator()); layoutContainer.add(accessDataFlc); - uifactory.addStaticTextElement("pwdav.username", "pwdav.username", ureq.getIdentity().getName(), accessDataFlc); + + StringBuilder sb = new StringBuilder(); + sb.append(getIdentity().getName()); + if(StringHelper.containsNonWhitespace(getIdentity().getUser().getEmail())) { + sb.append(", ").append(getIdentity().getUser().getEmail()); + } + if(StringHelper.containsNonWhitespace(getIdentity().getUser().getInstitutionalEmail())) { + sb.append(", ").append(getIdentity().getUser().getInstitutionalEmail()); + } + uifactory.addStaticTextElement("pwdav.username", "pwdav.username", sb.toString(), accessDataFlc); boolean hasOlatToken = false; boolean hasWebDAVToken = false; diff --git a/src/main/java/org/olat/user/_content/homepagedisplay.html b/src/main/java/org/olat/user/_content/homepagedisplay.html index 0928758db8b52372a48012df1110e619846bc975..f9a3b2ed6c5f3f2dee1338b024ee0ce2141625b6 100644 --- a/src/main/java/org/olat/user/_content/homepagedisplay.html +++ b/src/main/java/org/olat/user/_content/homepagedisplay.html @@ -49,8 +49,8 @@ <div class="o_visitingcard_link o_extlink clearfix o_block_large_bottom"> <h5>$r.translate("extlink")</h5> <div class="o_copy_code o_nowrap"> - <a href="javascript:;" id="o_extlink" data-original-title="" title=""><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"></i></a> - $extLink + <a href="javascript:;" id="o_extlink" data-original-title="" title=""><i class="o_icon o_icon-lg o_icon-fw o_icon_qrcode"> </i></a> + <input type="text" value="$extLink" onclick="this.select()"/> <script type="text/javascript"> /* <![CDATA[ */ jQuery(function() { diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties index 86b7a6f281cd825a60f4bde637f28841759953d4..26632eae8835d2db4f43975a3abe7b898ff6f6fa 100644 --- a/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties @@ -1,4 +1,4 @@ -#Thu Sep 03 11:09:03 CEST 2015 +#Thu Aug 03 10:54:35 CEST 2017 Failed=File upload failed. NoImage=This file format cannot be uploaded as image. ULLimitExceeded=Your image must not exceed {0} kByte. @@ -65,7 +65,7 @@ interval.two-hourly=Every two hours interval.weekly=Weekly landing.pages=Landing page logo.header=Enterprise logo (Formats .jpg .jpeg .png .gif only) -logo.select=$:ul.select +logo.select=$\:ul.select mail.intern.only=Send e-mails to the OpenOLAT internal inbox mail.send.copy=Send e-mails to the OpenOLAT internal inbox and the address {0} mail.system=E-mail delivery diff --git a/src/main/java/org/olat/user/propertyhandlers/EmailProperty.java b/src/main/java/org/olat/user/propertyhandlers/EmailProperty.java index 07744787e48f1dcdee8be5092a90de7fcce01a58..372c016d1819a77b5ece54d047093c60a3ab2378 100644 --- a/src/main/java/org/olat/user/propertyhandlers/EmailProperty.java +++ b/src/main/java/org/olat/user/propertyhandlers/EmailProperty.java @@ -99,9 +99,10 @@ public class EmailProperty extends Generic127CharTextPropertyHandler { //special validator in case of bulkChange, wizard in first step allows entry of ${userProperty} (velocity-style) //to validate the input a special isValidValue is used. if (usageIdentifyer.equals(UserBulkChangeStep00.class.getCanonicalName())){ - tElem.setItemValidatorProvider(new ItemValidatorProvider(){ + tElem.setItemValidatorProvider(new ItemValidatorProvider() { + @Override public boolean isValidValue(String value, ValidationError validationError, Locale locale2) { - UserBulkChangeManager ubcMan = UserBulkChangeManager.getInstance(); + UserBulkChangeManager ubcMan = CoreSpringFactory.getImpl(UserBulkChangeManager.class); Context vcContext = new VelocityContext(); if (user==null){ vcContext = ubcMan.getDemoContext(locale2); diff --git a/src/main/java/org/olat/user/propertyhandlers/GenericUnique127CharTextPropertyHandler.java b/src/main/java/org/olat/user/propertyhandlers/GenericUnique127CharTextPropertyHandler.java index 3c3c85ade21846500b6201844bcd82f236056f5f..ac38b1a8c6f94bd17888cbcd889b4d6d2649fc76 100644 --- a/src/main/java/org/olat/user/propertyhandlers/GenericUnique127CharTextPropertyHandler.java +++ b/src/main/java/org/olat/user/propertyhandlers/GenericUnique127CharTextPropertyHandler.java @@ -47,10 +47,15 @@ public class GenericUnique127CharTextPropertyHandler extends Generic127CharTextP if(formItem instanceof TextElement) { String value = ((TextElement)formItem).getValue(); if(!isUnique(user, value)) { - Identity propId = UserManager.getInstance().findIdentityKeyWithProperty(getName(), value); - String email = propId.getUser().getProperty(UserConstants.EMAIL, null); - formItem.setErrorKey("general.error.unique", new String[]{ email }); - allOk &= false; + List<Identity> found = UserManager.getInstance().findIdentitiesWithProperty(getName(), value); + Identity propId = null; + if(found.size() > 0) { + // only display first one + propId = found.get(0); + String email = propId.getUser().getProperty(UserConstants.EMAIL, null); + formItem.setErrorKey("general.error.unique", new String[]{ email }); + allOk &= false; + } } } @@ -62,11 +67,16 @@ public class GenericUnique127CharTextPropertyHandler extends Generic127CharTextP boolean allOk = super.isValidValue(user, value, validationError, locale); if(!isUnique(user, value)) { - Identity propId = UserManager.getInstance().findIdentityKeyWithProperty(getName(), value); - String email = propId.getUser().getProperty(UserConstants.EMAIL, null); - validationError.setErrorKey("general.error.unique"); - validationError.setArgs(new String[]{ email }); - allOk &= false; + List<Identity> found = UserManager.getInstance().findIdentitiesWithProperty(getName(), value); + Identity propId = null; + if(found.size() > 0) { + // only display first one + propId = found.get(0); + String email = propId.getUser().getProperty(UserConstants.EMAIL, null); + validationError.setErrorKey("general.error.unique"); + validationError.setArgs(new String[]{ email }); + allOk &= false; + } } return allOk; diff --git a/src/main/java/org/olat/user/propertyhandlers/UserPropertiesConfigImpl.java b/src/main/java/org/olat/user/propertyhandlers/UserPropertiesConfigImpl.java index 535d29bfec2e75b3881f673a78a02a42226c50b6..7e0e016131d88605d35dfdc283da9dd66483054a 100644 --- a/src/main/java/org/olat/user/propertyhandlers/UserPropertiesConfigImpl.java +++ b/src/main/java/org/olat/user/propertyhandlers/UserPropertiesConfigImpl.java @@ -199,7 +199,7 @@ public class UserPropertiesConfigImpl implements UserPropertiesConfig, Initializ "Could not find user property usage configuration for usageIdentifyer::" + usageIdentifyer + ", please check yout olat_userconfig.xml file. Using default configuration instead.", null); if (currentUsageConfig == null) { - throw new OLATRuntimeException("Missing default user property usage configuratoin in olat_userconfig.xml", null); + throw new OLATRuntimeException("Missing default user property usage configuration in olat_userconfig.xml", null); } } return currentUsageConfig; diff --git a/src/main/java/org/olat/user/propertyhandlers/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/user/propertyhandlers/_i18n/LocalStrings_fr.properties index b900b8f4cadb8575d7bd02a5918bb5a289e62970..6ae839cd25a4f1e91e5f772460bbff0e3dd12065 100644 --- a/src/main/java/org/olat/user/propertyhandlers/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/user/propertyhandlers/_i18n/LocalStrings_fr.properties @@ -354,7 +354,7 @@ general.error.max.127=Valeur contient plus que 127 signes general.error.max.32=Valeur contient plus que 32 signes general.error.unique=Cette valeur est d\u00E9j\u00E0 utilis\u00E9e par cet utilisateur {0}. S'il vous pla\u00EEt entrer une valeur unique. gsph.doselect=S\u00E9lectionner -gsph.selectionerror=Fa\u00EEtes un choix s'il-vous-pla\u00EEt +gsph.selectionerror=Fa\u00EEtes un choix s'il vous pla\u00EEt gsphc.addoption=+ gsphc.ismulti=S\u00E9lection multiple gsphc.issingle=S\u00E9lection simple diff --git a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml index a6b5119c5445d8e6462183301017e7c05942c68a..d3513bdb50cb61eb67abcc610301048a6c9ea953 100644 --- a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml +++ b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" + xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/context + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - <!-- - Configure the users properties, forms and tables + <!-- + Configure the users properties, forms and tables --> <bean id="org.olat.user.UserPropertiesConfig" class="org.olat.user.propertyhandlers.UserPropertiesConfigImpl" init-method="init"> <property name="maxNumOfInterests" value="${user.interests.max.number:5}" /> @@ -48,7 +48,7 @@ <ref bean="userPropertyGenericYear" /> <ref bean="userPropertyTypeOfUser" /> <ref bean="userPropertySocialSecurityNumber" /> - + <ref bean="userPropertyRank" /> <ref bean="userPropertyDegree" /> <ref bean="userPropertyPosition" /> @@ -60,7 +60,7 @@ <ref bean="userPropertyOfficeZipCode" /> <ref bean="userPropertyOfficeCity" /> <ref bean="userPropertyOfficeCountry" /> - <ref bean="userPropertyOfficeMobilePhone" /> + <ref bean="userPropertyOfficeMobilePhone" /> <ref bean="userPropertyGenericText" /> <ref bean="userPropertyGenericText2" /> @@ -71,31 +71,31 @@ <ref bean="userPropertyGenericUniqueText" /> <ref bean="userPropertyGenericUniqueText2" /> <ref bean="userPropertyGenericUniqueText3" /> - + <ref bean="userPropertyGenericEmail" /> - + <ref bean="userPropertyGenericCheckbox" /> <ref bean="userPropertyGenericCheckbox2" /> <ref bean="userPropertyGenericCheckbox3" /> - + <ref bean="userPropertyGenericSelect" /> <ref bean="userPropertyGenericSelect2" /> <ref bean="userPropertyGenericSelect3" /> - + <ref bean="userPropertyCreationDateDisplay" /> <ref bean="userPropertylastLoginDateDisplay" /> - + <!-- example <ref bean="userPropertyAttrEduPersonAffiliation" /> <ref bean="userPropertyAttrSwissEduPersonStudyLevel" /> --> </list> </property> - + <property name="userPropertyUsageContexts"> <map> - - <!-- + + <!-- Forms that show user properties --> <entry key="org.olat.user.ProfileFormController"> @@ -164,7 +164,7 @@ </bean> </entry> - <!-- + <!-- Indexed for fulltext search (only the fields that a user selects to publish are indexed) --> <entry key="org.olat.search.service.document.IdentityDocument"> @@ -226,11 +226,11 @@ which should not be revealed by a search. --> <ref bean="userPropertyInstitutionalEmail" /> <ref bean="userPropertyStudySubject" /> - </set> + </set> </property> </bean> </entry> - + <entry key="org.olat.course.member.MemberSearchForm"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -249,11 +249,11 @@ <ref bean="userPropertyInstitutionalName" /> <ref bean="userPropertyInstitutionalUserIdentifier" /> <ref bean="userPropertyInstitutionalEmail" /> - </set> + </set> </property> </bean> </entry> - + <entry key="org.olat.course.nodes.pf.ui.PFCoachController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -280,11 +280,11 @@ <ref bean="userPropertyInstitutionalName" /> <ref bean="userPropertyInstitutionalUserIdentifier" /> <ref bean="userPropertyInstitutionalEmail" /> - </set> + </set> </property> </bean> </entry> - + <entry key="org.olat.course.member.MemberListController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -303,7 +303,7 @@ <ref bean="userPropertyInstitutionalName" /> <ref bean="userPropertyInstitutionalUserIdentifier" /> <ref bean="userPropertyInstitutionalEmail" /> - </set> + </set> </property> <property name="mandatoryProperties"> <set> @@ -314,7 +314,7 @@ </property> </bean> </entry> - + <entry key="org.olat.modules.fo.ui.ForumUserListController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -324,7 +324,7 @@ </list> </property> <property name="adminViewOnlyProperties"> - <set></set> + <set></set> </property> <property name="mandatoryProperties"> <set> @@ -334,7 +334,7 @@ </property> </bean> </entry> - + <entry key="org.olat.modules.lecture.ui.TeacherRollCallController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="List of users in roll call" /> @@ -346,7 +346,7 @@ </list> </property> <property name="adminViewOnlyProperties"> - <set></set> + <set></set> </property> <property name="mandatoryProperties"> <set> @@ -357,7 +357,7 @@ </property> </bean> </entry> - + <entry key="org.olat.modules.lecture.ui.ParticipantListRepositoryController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="List of users in lecture blocks overview" /> @@ -369,7 +369,7 @@ </list> </property> <property name="adminViewOnlyProperties"> - <set></set> + <set></set> </property> <property name="mandatoryProperties"> <set> @@ -380,7 +380,7 @@ </property> </bean> </entry> - + <entry key="org.olat.group.ui.main.MemberInfoController"> <!-- First name and last name are already shown --> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> @@ -394,7 +394,7 @@ </property> </bean> </entry> - + <entry key="org.olat.resource.accesscontrol.ui.OrdersAdminController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Booking list" /> @@ -418,7 +418,7 @@ </property> </bean> </entry> - + <entry key="org.olat.course.nodes.cl.ui.CheckListAssessmentController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Table for check lists" /> @@ -442,7 +442,7 @@ </property> </bean> </entry> - + <entry key="org.olat.course.nodes.gta.ui.GTACoachedGroupGradingController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Assessment table in the group task." /> @@ -466,7 +466,7 @@ </property> </bean> </entry> - + <entry key="org.olat.commons.memberlist.ui.MembersPrintController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Print view in the members course element and group member tool" /> @@ -475,11 +475,11 @@ <ref bean="userPropertyFirstName" /> <ref bean="userPropertyLastName" /> <ref bean="userPropertyEmail" /> - + </list> </property> <property name="adminViewOnlyProperties"> - <set></set> + <set></set> </property> <property name="mandatoryProperties"> <set> @@ -499,12 +499,12 @@ <ref bean="userPropertyFirstName" /> <ref bean="userPropertyLastName" /> <ref bean="userPropertyInstitutionalName" /> - <ref bean="userPropertyOrgUnit" /> + <ref bean="userPropertyOrgUnit" /> </list> </property> </bean> </entry> - + <entry key="org.olat.commons.memberlist.ui.MembersTableController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="List view and Excel export in the members course element and group member tool" /> @@ -586,7 +586,7 @@ </property> </bean> </entry> - + <entry key="org.olat.admin.user.UsermanagerUserSearchForm"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -640,9 +640,9 @@ <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> <list> - <!-- - don't add email as form elemente here, email is already - collected in the previous step of the registration workflow + <!-- + don't add email as form elemente here, email is already + collected in the previous step of the registration workflow --> <ref bean="userPropertyFirstName" /> <ref bean="userPropertyLastName" /> @@ -656,7 +656,7 @@ </property> </bean> </entry> - + <!-- OAuthRegistrationController is used in the OAuth registration process --> <entry key="org.olat.login.oauth.ui.OAuthRegistrationController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> @@ -677,9 +677,30 @@ </property> </bean> </entry> - - - <!-- + + <!-- ShibbolethRegistrationUserPropertiesFrom is used in the Shibboleth registration process --> + <entry key="org.olat.shibboleth.ShibbolethRegistrationUserPropertiesFrom"> + <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> + <property name="description" value="Registration form for Shibboleth users" /> + <property name="propertyHandlers"> + <list> + <ref bean="userPropertyFirstName" /> + <ref bean="userPropertyLastName" /> + <ref bean="userPropertyEmail" /> + </list> + </property> + <property name="mandatoryProperties"> + <set> + <ref bean="userPropertyFirstName" /> + <ref bean="userPropertyLastName" /> + <ref bean="userPropertyEmail" /> + </set> + </property> + </bean> + </entry> + + + <!-- Tables that show user properties --> <entry key="org.olat.admin.user.UserTableDataModel"> @@ -726,23 +747,23 @@ </property> </bean> </entry> - + <entry key="org.olat.admin.user.delete.UserDeleteTableModel"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> <list> <ref bean="userPropertyLastName" /> - <ref bean="userPropertyFirstName" /> - <ref bean="userPropertyEmail" /> + <ref bean="userPropertyFirstName" /> + <ref bean="userPropertyEmail" /> </list> </property> <property name="mandatoryProperties"> <set> <ref bean="userPropertyLastName" /> - <ref bean="userPropertyFirstName" /> + <ref bean="userPropertyFirstName" /> <ref bean="userPropertyEmail" /> </set> - </property> + </property> </bean> </entry> @@ -791,7 +812,7 @@ </property> </bean> </entry> - + <entry key="org.olat.admin.securitygroup.gui.IdentitiesOfGroupTableDataModel"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -896,8 +917,8 @@ </property> </bean> </entry> - - + + <entry key="org.olat.course.archiver.ScoreAccountingHelper"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -931,7 +952,7 @@ </property> </bean> </entry> - + <entry key="org.olat.course.assessment.EfficiencyStatementController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Efficiency-Statements" /> @@ -939,10 +960,10 @@ <list> <ref bean="userPropertyFirstName" /> <ref bean="userPropertyLastName" /> - <ref bean="userPropertyEmail" /> + <ref bean="userPropertyEmail" /> <ref bean="userPropertyInstitutionalName" /> - <ref bean="userPropertyInstitutionalUserIdentifier" /> - <ref bean="userPropertyInstitutionalEmail" /> + <ref bean="userPropertyInstitutionalUserIdentifier" /> + <ref bean="userPropertyInstitutionalEmail" /> </list> </property> </bean> @@ -964,7 +985,7 @@ </property> </bean> </entry> - + <entry key="org.olat.group.ui.wizard.MemberListWizardController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -992,10 +1013,10 @@ <ref bean="userPropertyOrgUnit" /> <ref bean="userPropertyStudySubject" /> </list> - </property> + </property> </bean> </entry> - + <entry key="de.bps.olat.modules.cl.ChecklistManageCheckpointsController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="List of users in the check list course building block" /> @@ -1005,7 +1026,7 @@ <ref bean="userPropertyLastName" /> <ref bean="userPropertyInstitutionalUserIdentifier" /> </list> - </property> + </property> <property name="userViewReadOnlyProperties"> <set> <ref bean="userPropertyFirstName" /> @@ -1023,10 +1044,10 @@ <set> <ref bean="userPropertyInstitutionalUserIdentifier" /> </set> - </property> + </property> </bean> </entry> - + <entry key="org.olat.admin.user.UserShortDescription"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Short description of a user" /> @@ -1034,9 +1055,9 @@ <list> <ref bean="userPropertyFirstName" /> <ref bean="userPropertyLastName" /> - <ref bean="userPropertyEmail" /> + <ref bean="userPropertyEmail" /> </list> - </property> + </property> </bean> </entry> @@ -1051,7 +1072,7 @@ <ref bean="userPropertyEmail" /> <ref bean="userPropertyInstitutionalName" /> <ref bean="userPropertyInstitutionalUserIdentifier" /> - <ref bean="userPropertyInstitutionalEmail" /> + <ref bean="userPropertyInstitutionalEmail" /> </list> </property> <property name="mandatoryProperties"> @@ -1062,8 +1083,8 @@ </set> </property> </bean> - </entry> - + </entry> + <entry key="org.olat.course.assessment.AssessedIdentitiesTableDataModel"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Assessment tool" /> @@ -1072,16 +1093,16 @@ <ref bean="userPropertyLastName" /> <ref bean="userPropertyFirstName" /> </list> - </property> + </property> <property name="mandatoryProperties"> <set> <ref bean="userPropertyLastName" /> <ref bean="userPropertyFirstName" /> </set> - </property> + </property> </bean> </entry> - + <entry key="org.olat.modules.coach.ui.UserListController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Coaching tool" /> @@ -1090,16 +1111,16 @@ <ref bean="userPropertyLastName" /> <ref bean="userPropertyFirstName" /> </list> - </property> + </property> <property name="mandatoryProperties"> <set> <ref bean="userPropertyLastName" /> <ref bean="userPropertyFirstName" /> </set> - </property> + </property> </bean> </entry> - + <entry key="org.olat.course.assessment.ui.tool.AssessmentToReviewSmallController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Small preview in assessment tool" /> @@ -1108,16 +1129,16 @@ <ref bean="userPropertyLastName" /> <ref bean="userPropertyFirstName" /> </list> - </property> + </property> <property name="mandatoryProperties"> <set> <ref bean="userPropertyFirstName" /> <ref bean="userPropertyLastName" /> </set> - </property> + </property> </bean> </entry> - + <entry key="org.olat.admin.user.bulkChange.UserBulkChangeStep00"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -1132,9 +1153,9 @@ <ref bean="userPropertyInstitutionalUserIdentifier" /> <ref bean="userPropertyInstitutionalEmail" /> <ref bean="userPropertyOrgUnit" /> - <ref bean="userPropertyStudySubject" /> + <ref bean="userPropertyStudySubject" /> </list> - </property> + </property> <property name="mandatoryProperties"> <set> <ref bean="userPropertyFirstName" /> @@ -1143,8 +1164,8 @@ </set> </property> </bean> - </entry> - + </entry> + <!-- the property handler list is limited to 12 entries --> <!-- in this case the key doesn't represent a class --> <entry key="userPropertyLogConfiguration"> @@ -1157,16 +1178,16 @@ <!-- <ref bean="userPropertyBirthDay" /> <ref bean="userPropertyGender" /> --> <!-- - Example IdentityAttributes matching to the usertracking LoggingObject - + Example IdentityAttributes matching to the usertracking LoggingObject + <ref bean="userPropertyAttrSwissEduPersonStudyLevel" /> - <ref bean="userPropertyAttrEduPersonAffiliation" /> + <ref bean="userPropertyAttrEduPersonAffiliation" /> --> </list> - </property> + </property> </bean> </entry> - + <entry key="org.olat.user.restapi.UserWebService"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="propertyHandlers"> @@ -1228,36 +1249,36 @@ </property> </bean> </entry> - + <entry key="org.olat.ims.lti.LTIManager"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Can be used for LTI" /> <property name="propertyHandlers"> <list> <ref bean="userPropertyInstitutionalName" /> - <ref bean="userPropertyInstitutionalUserIdentifier" /> - <ref bean="userPropertyInstitutionalEmail" /> + <ref bean="userPropertyInstitutionalUserIdentifier" /> + <ref bean="userPropertyInstitutionalEmail" /> <ref bean="userPropertyOrgUnit" /> <ref bean="userPropertyStudySubject" /> </list> </property> </bean> </entry> - + <!-- User properties used for group-mail-function --> <entry key="org.olat.group.ui.run.BusinessGroupSendToChooserForm"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value=" " /> <property name="propertyHandlers"> <list> - <ref bean="userPropertyLastName" /> + <ref bean="userPropertyLastName" /> <ref bean="userPropertyFirstName" /> </list> - </property> + </property> </bean> - </entry> - - + </entry> + + <!-- User properties used in Businesscards (mitgleidersite) --> <entry key="com.frentix.olat.user.UserBusinessCardController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> @@ -1265,15 +1286,15 @@ <property name="propertyHandlers"> <list> <ref bean="userPropertyFirstName" /> - <ref bean="userPropertyLastName" /> + <ref bean="userPropertyLastName" /> <ref bean="userPropertyOrgUnit" /> <ref bean="userPropertyTelOffice" /> - <ref bean="userPropertyEmail" /> + <ref bean="userPropertyEmail" /> </list> - </property> + </property> </bean> - </entry> - + </entry> + <!-- User properties used for the mail-footer line together with i18nkey: "footer.with.userdata" --> <entry key="org.olat.core.util.mail.MailHelper"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> @@ -1281,12 +1302,12 @@ <property name="propertyHandlers"> <list> <ref bean="userPropertyFirstName" /> - <ref bean="userPropertyLastName" /> + <ref bean="userPropertyLastName" /> <ref bean="userPropertyInstitutionalName" /> </list> - </property> + </property> </bean> - </entry> + </entry> <!-- User properties used for the mail-notifications line together with i18nkey: "user.formatted" --> <entry key="org.olat.core.commons.services.notifications.NotificationHelper"> @@ -1295,12 +1316,12 @@ <property name="propertyHandlers"> <list> <ref bean="userPropertyFirstName" /> - <ref bean="userPropertyLastName" /> + <ref bean="userPropertyLastName" /> </list> - </property> + </property> </bean> </entry> - + <entry key="org.olat.admin.landingpages.LandingPagesModule"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Properties used in the administration of landing pages. " /> @@ -1320,17 +1341,17 @@ <ref bean="userPropertyOrgUnit" /> <ref bean="userPropertyStudySubject" /> </list> - </property> + </property> </bean> </entry> - + <entry key="org.olat.modules.coach.ui.UserSearchForm"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Properties used in the user search of the coaching tool." /> <property name="propertyHandlers"> <list> <ref bean="userPropertyFirstName" /> - <ref bean="userPropertyLastName" /> + <ref bean="userPropertyLastName" /> <ref bean="userPropertyEmail" /> <ref bean="userPropertyZipCode" /> <ref bean="userPropertyRegion" /> @@ -1342,17 +1363,17 @@ <ref bean="userPropertyOrgUnit" /> <ref bean="userPropertyStudySubject" /> </list> - </property> + </property> </bean> </entry> - + <entry key="org.olat.modules.lecture.ui.coach.LecturesSearchFormController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Properties used in the user search for lectures of the coaching tool." /> <property name="propertyHandlers"> <list> <ref bean="userPropertyFirstName" /> - <ref bean="userPropertyLastName" /> + <ref bean="userPropertyLastName" /> <ref bean="userPropertyEmail" /> <ref bean="userPropertyInstitutionalName" /> <ref bean="userPropertyInstitutionalUserIdentifier" /> @@ -1365,19 +1386,19 @@ <ref bean="userPropertyFirstName" /> <ref bean="userPropertyLastName" /> </set> - </property> + </property> </bean> </entry> - + <entry key="org.olat.modules.portfolio.ui.PortfolioHomeController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Properties used in the portfolio v2.0." /> <property name="propertyHandlers"> <list> <ref bean="userPropertyFirstName" /> - <ref bean="userPropertyLastName" /> + <ref bean="userPropertyLastName" /> </list> - </property> + </property> <property name="mandatoryProperties"> <set> <ref bean="userPropertyFirstName" /> @@ -1386,10 +1407,10 @@ </property> <property name="adminViewOnlyProperties"> <set></set> - </property> + </property> </bean> </entry> - + <entry key="org.olat.modules.reminder.rule.UserPropertyRuleSPI"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Properties used in the reminder rules." /> @@ -1405,10 +1426,10 @@ <ref bean="userPropertyOrgUnit" /> <ref bean="userPropertyStudySubject" /> </list> - </property> + </property> </bean> </entry> - + <entry key="org.olat.course.reminder.ui.CourseSendReminderListController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Properties used in the send reminder list" /> @@ -1428,10 +1449,10 @@ <set> <ref bean="userPropertyInstitutionalUserIdentifier" /> </set> - </property> + </property> </bean> </entry> - + <!-- Default configuration in case nothing else matches. --> @@ -1456,9 +1477,9 @@ </property> </bean> </entry> ---> +--> </map> </property> - + </bean> </beans> \ No newline at end of file diff --git a/src/main/java/org/olat/user/propertyhandlers/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/propertyhandlers/ui/_i18n/LocalStrings_de.properties index d41613a7cf7240c8f27d850a239136a14a0b3c2f..1d6916c1def83c296f9ffa192dc8f39d88a8e5c0 100644 --- a/src/main/java/org/olat/user/propertyhandlers/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/user/propertyhandlers/ui/_i18n/LocalStrings_de.properties @@ -1,50 +1,51 @@ -upc.properties=Properties +#Mon Jul 17 21:18:30 CEST 2017 +error.phone.invalid=Nummer ist nicht g\u00FCltig +error.sms.change.confirm.token=Invalid +sms.change.confirm=SMS Code \u00FCberpr\u00FCfen +sms.change.confirm.descr=$org.olat.core.commons.services.sms.ui\:sms.token.number.explain +sms.change.confirm.token=SMS Best\u00E4tigungscode +sms.change.number.descr=Die Nummer muss best\u00E4tigt werden. W\u00E4hlen Sie den unten stehenden Button, um einen SMS Code zu schicken\: +sms.change.number.hint=+41 12 345 67 89 +sms.change.number.title=Nummer \u00E4ndern +sms.phone.hint=\u00DCber diese Nummer kann das Passwort per SMS zur\u00FCckgesetzt werden. +sms.phone.not.available=Keine Nummer vorhanden +sms.phone.number.changed=Ihre Nummer wurde erfolgreich \u00FCberpr\u00FCft.<br>Bitte speichern Sie Ihr Profil, um den Prozess abzuschliessen. +sms.phone.number.example=$org.olat.core.commons.services.sms.ui\:sms.phone.number.example +sms.send=SMS Authentifizierung starten +sms.title={0} \u00E4ndern +sms.token=Ihr Best\u00E4tigungscode ist {0} +upc.active=Aktiv +upc.adminonly=Admin only +upc.context.edit=Context bearbeiten +upc.context.propcount=Anzahl Properties upc.contexts=Contexts -upc.reset=Reset -upc.name=Name +upc.deact_confirmationtext=Wollen Sie dieses Property wirklich deaktivieren? Deaktivierte Properties werden aus allen Contexten entfernt\! +upc.deact_confirmationtitle=Deaktivieren? +upc.deact_infotext=Sie haben ein wichtiges UserProperty aus diesem Context entfernt\! Sind sie sich sicher? +upc.defaulttranslation=Standard\u00FCbersetzung +upc.deletable=L\u00F6schbar upc.description=Beschreibung +upc.down=Ab upc.edit=Bearbeiten +upc.edittranslate=\u00DCbersetzung bearbeiten upc.group=Gruppe -upc.deletable=L\u00F6schbar +upc.handlerconfigtitle=Handler Konfiguration upc.hndlconfig=Handler config -upc.translate=\u00DCbersetzen -upc.edittranslate=\u00DCbersetzung bearbeiten -upc.active=Aktiv -upc.context.propcount=Anzahl Properties -upc.context.edit=Context bearbeiten +upc.include=Verwenden upc.mandatory=Zwingend -upc.adminonly=Admin only -upc.userreadonly=User readonly upc.move=Reihenfolge -upc.include=Verwenden -upc.up=Auf -upc.down=Ab -upc.handlerconfigtitle=Handler Konfiguration -upc.deact_confirmationtext=Wollen Sie dieses Property wirklich deaktivieren? Deaktivierte Properties werden aus allen Contexten entfernt! -upc.deact_confirmationtitle=Deaktivieren? -upc.deact_infotext=Sie haben ein wichtiges UserProperty aus diesem Context entfernt! Sind sie sich sicher? -upc.reset.configs=Vordefinierte Konfiguration laden\: -upc.reset.configs.note=Notiz\: Beim Laden eines Presets werden unbekannte UserProperties nicht deaktiviert... +upc.name=Name +upc.properties=Properties +upc.reset=Reset +upc.reset.config.baks=BAKS +upc.reset.config.business=Business upc.reset.config.done=Vordefinierte Konfiguration wurde geladen... -upc.reset.config.olatdefault=OLAT Default upc.reset.config.minimal=Minimal +upc.reset.config.olatdefault=OLAT Default upc.reset.config.school=School -upc.reset.config.business=Business -upc.reset.config.baks=BAKS -upc.defaulttranslation=Standard\u00FCbersetzung -sms.title={0} \u00E4ndern -sms.send=SMS Authentifizierung starten -sms.phone.hint=\u00DCber diese Nummer kann das Passwort per SMS zur\u00FCckgesetzt werden. -sms.phone.number.changed=Ihre Nummer wurde erfolgreich \u00FCberpr\u00FCft.<br>Bitte speichern Sie Ihr Profil, um den Prozess abzuschliessen. -sms.phone.number.example=$org.olat.core.commons.services.sms.ui\:sms.phone.number.example -sms.change.number.title=Nummer \u00E4ndern -sms.change.number.hint=+41 12 345 67 89 -sms.change.number.descr=Die Nummer muss best\u00E4tigt werden. W\u00E4hlen Sie den unten stehenden Button, um einen SMS Code zu schicken: -sms.phone.not.available=Keine Nummer vorhanden -sms.change.confirm.descr=$org.olat.core.commons.services.sms.ui\:sms.token.number.explain -sms.change.confirm.token=SMS Best\u00E4tigungscode -sms.change.confirm=SMS Code \u00FCberpr\u00FCfen -sms.token=Ihr Best\u00E4tigungscode ist {0} -error.sms.change.confirm.token=Invalid -error.phone.invalid=Nummer ist nicht g\u00FCltig - +upc.reset.configs=Vordefinierte Konfiguration laden\: +upc.reset.configs.note=Notiz\: Beim Laden eines Presets werden unbekannte UserProperties nicht deaktiviert... +upc.translate=\u00DCbersetzen +upc.up=Auf +upc.userreadonly=User readonly +warning.message.not.send=Die SMS konnte nicht gesendet werden. diff --git a/src/main/java/org/olat/user/propertyhandlers/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/user/propertyhandlers/ui/_i18n/LocalStrings_pt_BR.properties index 10dee2ca1352690aca4bd354be69d9d0836d5e36..c96dfab09cdb6b6887de2060e48f57ef206d2210 100644 --- a/src/main/java/org/olat/user/propertyhandlers/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/user/propertyhandlers/ui/_i18n/LocalStrings_pt_BR.properties @@ -1,4 +1,4 @@ -#Thu Mar 16 22:38:32 CET 2017 +#Tue Sep 05 23:26:47 CEST 2017 error.phone.invalid=N\u00FAmero inv\u00E1lido error.sms.change.confirm.token=O c\u00F3digo n\u00E3o \u00E9 v\u00E1lido sms.change.confirm=Insira o c\u00F3digo SMS @@ -48,3 +48,4 @@ upc.reset.configs.note=Nota\: Ao carregar uma predefini\u00E7\u00E3o, UserProper upc.translate=Traduzir upc.up=Subir upc.userreadonly=Somente leitura para usu\u00E1rio +warning.message.not.send=O SMS n\u00E3o pode ser enviado diff --git a/src/main/java/org/olat/user/restapi/UserWebService.java b/src/main/java/org/olat/user/restapi/UserWebService.java index 96e429d6ab00049bf1cc350fc3ec704856258dd0..3ede085b6c96e30f7d8d7d5529026786f8642840 100644 --- a/src/main/java/org/olat/user/restapi/UserWebService.java +++ b/src/main/java/org/olat/user/restapi/UserWebService.java @@ -22,6 +22,7 @@ package org.olat.user.restapi; import static org.olat.restapi.security.RestSecurityHelper.getIdentity; import static org.olat.restapi.security.RestSecurityHelper.getLocale; import static org.olat.restapi.security.RestSecurityHelper.getUserRequest; +import static org.olat.restapi.security.RestSecurityHelper.isAuthor; import static org.olat.restapi.security.RestSecurityHelper.isUserManager; import static org.olat.user.restapi.UserVOFactory.formatDbUserProperty; import static org.olat.user.restapi.UserVOFactory.get; @@ -130,17 +131,19 @@ public class UserWebService { * Don't forget the right escaping in the URL!<br> * You can make a search with the user properties like this:<br> * users?telMobile=39847592&login=test + * <br >/ The lookup is possible for authors, usermanagers and system administrators. Normal + * users are not allowed to use the lookup service. * * @response.representation.200.qname {http://www.example.com}userVO - * @response.representation.200.mediaType application/xml, application/json - * @response.representation.200.doc The list of all users in the OLAT system - * @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes} + * @response.representation.200.mediaType application/xml, application/json + * @response.representation.200.doc The list of all users in the OLAT system + * @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes} * @response.representation.401.doc The roles of the authenticated user are not sufficient * @param login The login (search with like) * @param authProvider An authentication provider (optional) * @param authUsername An specific username from the authentication provider - * @param uriInfo The URI infos - * @param httpRequest The HTTP request + * @param uriInfo The URI infos + * @param httpRequest The HTTP request * @return An array of users */ @GET @@ -149,8 +152,12 @@ public class UserWebService { @QueryParam("authProvider") String authProvider, @QueryParam("authUsername") String authUsername, @QueryParam("statusVisibleLimit") String statusVisibleLimit, @Context UriInfo uriInfo, @Context HttpServletRequest httpRequest) { - - if(!isUserManager(httpRequest)) { + + // User lookup allowd for authors, usermanagers and admins. For + // usernamanger and up are considered "administrative" when it comes to + // lookup of the user properties + boolean isAdministrativeUser = isUserManager(httpRequest); + if(!isAdministrativeUser && !isAuthor(httpRequest)) { return Response.serverError().status(Status.UNAUTHORIZED).build(); } @@ -175,7 +182,7 @@ public class UserWebService { if(!params.isEmpty()) { UserManager um = UserManager.getInstance(); Locale locale = getLocale(httpRequest); - List<UserPropertyHandler> propertyHandlers = um.getUserPropertyHandlersFor(PROPERTY_HANDLER_IDENTIFIER, false); + List<UserPropertyHandler> propertyHandlers = um.getUserPropertyHandlersFor(PROPERTY_HANDLER_IDENTIFIER, isAdministrativeUser); for(UserPropertyHandler handler:propertyHandlers) { if(!params.containsKey(handler.getName())) continue; @@ -188,7 +195,7 @@ public class UserWebService { } Integer status = Identity.STATUS_VISIBLE_LIMIT; - if("all".equalsIgnoreCase(statusVisibleLimit)) { + if(isAdministrativeUser && "all".equalsIgnoreCase(statusVisibleLimit)) { status = null; } identities = BaseSecurityManager.getInstance().getIdentitiesByPowerSearch(login, userProps, true, null, null, authProviders, null, null, null, null, status); diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index c25b07a7255bfff54105d4599c2d1c2e2672dd1a..b82a337e9e482d855fb4a93274a0b39cd4f8cf9e 100644 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -48,7 +48,7 @@ <mapping-file>org/olat/core/util/mail/model/DBMailRecipient.hbm.xml</mapping-file> <mapping-file>org/olat/core/logging/activity/LoggingObject.hbm.xml</mapping-file> <mapping-file>org/olat/course/db/impl/CourseDBEntryImpl.hbm.xml</mapping-file> - + <!-- Start upgraders mapping --> <mapping-file>org/olat/upgrade/model/BGAreaUpgrade.hbm.xml</mapping-file> <mapping-file>org/olat/upgrade/model/BGContextImpl.hbm.xml</mapping-file> @@ -63,8 +63,8 @@ <class>org.olat.upgrade.model.EPMapUpgradeToGroupRelation</class> <class>org.olat.upgrade.model.InvitationUpgrade</class> <!-- End upgraders mapping --> - - + + <class>org.olat.basesecurity.IdentityShort</class> <class>org.olat.basesecurity.model.GroupImpl</class> <class>org.olat.basesecurity.model.GrantImpl</class> @@ -93,7 +93,9 @@ <class>org.olat.course.nodes.cl.model.DBCheck</class> <class>org.olat.course.nodes.gta.model.TaskImpl</class> <class>org.olat.course.nodes.gta.model.TaskLightImpl</class> + <class>org.olat.course.nodes.gta.model.TaskDueDateImpl</class> <class>org.olat.course.nodes.gta.model.TaskListImpl</class> + <class>org.olat.course.nodes.gta.model.TaskRevisionDateImpl</class> <class>org.olat.course.certificate.model.CertificateImpl</class> <class>org.olat.course.certificate.model.CertificateStandalone</class> <class>org.olat.course.certificate.model.CertificateLightImpl</class> @@ -132,6 +134,7 @@ <class>org.olat.resource.accesscontrol.model.FreeAccessMethod</class> <class>org.olat.resource.accesscontrol.model.TokenAccessMethod</class> <class>org.olat.resource.accesscontrol.model.ResourceReservationImpl</class> + <class>org.olat.resource.accesscontrol.provider.auto.model.AdvanceOrderImpl</class> <class>org.olat.resource.accesscontrol.provider.paypal.model.PaypalAccessMethod</class> <class>org.olat.instantMessaging.model.InstantMessageImpl</class> <class>org.olat.instantMessaging.model.ImPreferencesImpl</class> @@ -159,8 +162,8 @@ <class>org.olat.modules.gotomeeting.model.GoToOrganizerImpl</class> <class>org.olat.modules.gotomeeting.model.GoToRegistrantImpl</class> <class>org.olat.modules.lecture.model.ReasonImpl</class> - <class>org.olat.modules.lecture.model.LectureBlockLog</class> <class>org.olat.modules.lecture.model.LectureBlockImpl</class> + <class>org.olat.modules.lecture.model.LectureBlockAuditLogImpl</class> <class>org.olat.modules.lecture.model.LectureBlockToGroupImpl</class> <class>org.olat.modules.lecture.model.LectureBlockRollCallImpl</class> <class>org.olat.modules.lecture.model.LectureParticipantSummaryImpl</class> @@ -204,6 +207,7 @@ <class>org.olat.ims.lti.model.LTIOutcomeImpl</class> <class>org.olat.portfolio.model.InvitationImpl</class> <class>org.olat.portfolio.model.structel.EPStructureElementToGroupRelation</class> + <class>org.olat.shibboleth.manager.ShibbolethAutoAccessMethod</class> <class>org.olat.user.UserImpl</class> <properties> <property name="hibernate.generate_statistics" value="true"/> diff --git a/src/main/resources/database/mysql/alter_11_5_x_to_12_0_0.sql b/src/main/resources/database/mysql/alter_11_5_x_to_12_0_0.sql index 3e30baf7177cc995fd48746aa78ab6d4b51ad233..84b3cf4b96a3d6cc1e1f7dce914f5884d81dbb7c 100644 --- a/src/main/resources/database/mysql/alter_11_5_x_to_12_0_0.sql +++ b/src/main/resources/database/mysql/alter_11_5_x_to_12_0_0.sql @@ -73,8 +73,7 @@ create table o_lecture_block ( l_descr mediumtext, l_preparation mediumtext, l_location varchar(255), - l_comment mediumtext, - l_log mediumtext, + l_comment mediumtext, l_start_date datetime not null, l_end_date datetime not null, l_compulsory bit default 1, @@ -113,8 +112,7 @@ create table o_lecture_block_roll_call ( id bigint not null auto_increment, creationdate datetime not null, lastmodified datetime not null, - l_comment mediumtext, - l_log mediumtext, + l_comment mediumtext, l_lectures_attended varchar(128), l_lectures_absent varchar(128), l_lectures_attended_num bigint not null default 0, @@ -191,5 +189,76 @@ alter table o_lecture_entry_config ENGINE = InnoDB; alter table o_lecture_entry_config add constraint lec_entry_config_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); +create table o_lecture_block_audit_log ( + id bigint not null auto_increment, + creationdate datetime not null, + l_action varchar(32), + l_val_before mediumtext, + l_val_after mediumtext, + l_message mediumtext, + fk_lecture_block bigint, + fk_roll_call bigint, + fk_entry bigint, + fk_identity bigint, + fk_author bigint, + primary key (id) +); +alter table o_lecture_block_audit_log ENGINE = InnoDB; + +create index idx_lec_audit_entry_idx on o_lecture_block_audit_log(fk_entry); +create index idx_lec_audit_ident_idx on o_lecture_block_audit_log(fk_identity); + + +alter table o_rem_reminder add column r_email_subject varchar(255); +update o_rem_reminder set r_email_subject=r_description; + + +alter table o_qti_assessment_marks add column q_hidden_rubrics mediumtext default null; + + +alter table o_gta_task add column g_submission_date datetime default null; +alter table o_gta_task add column g_submission_revisions_date datetime default null; +alter table o_gta_task add column g_collection_date datetime default null; + +alter table o_gta_task add column g_assignment_due_date datetime default null; +alter table o_gta_task add column g_submission_due_date datetime default null; +alter table o_gta_task add column g_revisions_due_date datetime default null; +alter table o_gta_task add column g_solution_due_date datetime default null; + +alter table o_gta_task add column g_acceptation_date datetime default null; +alter table o_gta_task add column g_solution_date datetime default null; +alter table o_gta_task add column g_graduation_date datetime default null; + +alter table o_gta_task add column g_submission_ndocs bigint default null; +alter table o_gta_task add column g_submission_revisions_ndocs bigint default null; +alter table o_gta_task add column g_collection_ndocs bigint default null; + +create table o_gta_task_revision_date ( + id bigint not null auto_increment, + creationdate datetime not null, + g_status varchar(36) not null, + g_rev_loop bigint not null, + g_date datetime not null, + fk_task bigint not null, + primary key (id) +); +alter table o_gta_task_revision_date ENGINE = InnoDB; + +alter table o_gta_task_revision_date add constraint gtaskrev_to_task_idx foreign key (fk_task) references o_gta_task (id); + +alter table o_gta_task add column g_allow_reset_date datetime default null; +alter table o_gta_task add column fk_allow_reset_identity bigint default null; + +alter table o_gta_task add constraint gtaskreset_to_allower_idx foreign key (fk_allow_reset_identity) references o_bs_identity (id); + + +alter table o_info_message add column attachmentpath varchar(1024) default null; + + +alter table o_as_entry add column lastcoachmodified datetime default null; +alter table o_as_entry add column lastusermodified datetime default null; + +alter table o_as_eff_statement add column lastcoachmodified datetime default null; +alter table o_as_eff_statement add column lastusermodified datetime default null; diff --git a/src/main/resources/database/mysql/alter_12_0_0_to_12_0_1.sql b/src/main/resources/database/mysql/alter_12_0_0_to_12_0_1.sql new file mode 100644 index 0000000000000000000000000000000000000000..d971c31a359b284600b8f21d12c426b3b8310408 --- /dev/null +++ b/src/main/resources/database/mysql/alter_12_0_0_to_12_0_1.sql @@ -0,0 +1,7 @@ +alter table o_feed modify f_external_feed_url varchar(4000); +alter table o_feed modify f_external_image_url varchar(4000); +alter table o_feed modify f_description varchar(4000); +alter table o_feed modify f_image_name varchar(1024); + +alter table o_feed_item modify f_external_url varchar(4000); +alter table o_feed_item modify f_external_link varchar(4000); diff --git a/src/main/resources/database/mysql/alter_12_0_x_to_12_1_0.sql b/src/main/resources/database/mysql/alter_12_0_x_to_12_1_0.sql new file mode 100644 index 0000000000000000000000000000000000000000..5e437d42c636c4d271f4e225e8e7fa8f64eb74bd --- /dev/null +++ b/src/main/resources/database/mysql/alter_12_0_x_to_12_1_0.sql @@ -0,0 +1,24 @@ +-- auto access controll +create table o_ac_auto_advance_order ( + id bigint not null auto_increment, + creationdate datetime not null, + lastmodified datetime not null, + a_identifier_key varchar(64) not null, + a_identifier_value varchar(64) not null, + a_status varchar(32) not null, + a_status_modified datetime not null, + fk_identity int8 not null, + fk_method int8 not null, + primary key (id) +); + +alter table o_ac_auto_advance_order ENGINE = InnoDB; + +create index idx_ac_aao_id_idx on o_ac_auto_advance_order(id); +create index idx_ac_aao_identifier_idx on o_ac_auto_advance_order(a_identifier_key, a_identifier_value); +create index idx_ac_aao_ident_idx on o_ac_auto_advance_order(fk_identity); +alter table o_ac_auto_advance_order add constraint aao_ident_idx foreign key (fk_identity) references o_bs_identity (id); + + +-- lectures +alter table o_lecture_block_roll_call add column l_absence_supervisor_noti_date datetime default null; \ No newline at end of file diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql index 57b6ad7bb5a0d857406c6a5fac193aa91c41c16e..12d5f246b39c9c04dba71bd43c2f7ffd728ea763 100644 --- a/src/main/resources/database/mysql/setupDatabase.sql +++ b/src/main/resources/database/mysql/setupDatabase.sql @@ -295,7 +295,7 @@ create table if not exists o_user ( u_genericcheckboxproperty varchar(255), u_genericcheckboxproperty2 varchar(255), u_genericcheckboxproperty3 varchar(255), - + fk_identity bigint, primary key (user_id) ); @@ -462,8 +462,8 @@ create table if not exists o_bs_membership ( create table if not exists o_plock ( plock_id bigint not null, version mediumint unsigned not null, - creationdate datetime, - asset varchar(255) not null unique, + creationdate datetime, + asset varchar(255) not null unique, primary key (plock_id) ); @@ -484,21 +484,21 @@ create table if not exists o_lifecycle ( ); create table if not exists oc_lock ( - lock_id bigint not null, - version mediumint unsigned not null, - creationdate datetime, - identity_fk bigint not null, - asset varchar(120) not null unique, + lock_id bigint not null, + version mediumint unsigned not null, + creationdate datetime, + identity_fk bigint not null, + asset varchar(120) not null unique, primary key (lock_id) ); create table if not exists o_readmessage ( - id bigint not null, + id bigint not null, version mediumint unsigned not null, creationdate datetime, - identity_id bigint not null, - forum_id bigint not null, - message_id bigint not null, + identity_id bigint not null, + forum_id bigint not null, + message_id bigint not null, primary key (id) ); @@ -568,7 +568,7 @@ create table if not exists o_checkpoint_results ( lastmodified datetime not null, result bool not null, checkpoint_fk bigint, - identity_fk bigint, + identity_fk bigint, primary key (checkpoint_result_id) ); @@ -591,7 +591,7 @@ create table if not exists o_projectbroker_project ( mailNotificationEnabled boolean not null, projectgroup_fk bigint not null, projectbroker_fk bigint not null, - candidategroup_fk bigint not null, + candidategroup_fk bigint not null, primary key (project_id) ); @@ -603,27 +603,27 @@ create table if not exists o_projectbroker_customfields ( ); create table if not exists o_usercomment ( - comment_id bigint not null, - version mediumint unsigned not null, - creationdate datetime, - resname varchar(50) not null, - resid bigint not null, - ressubpath varchar(2048), + comment_id bigint not null, + version mediumint unsigned not null, + creationdate datetime, + resname varchar(50) not null, + resid bigint not null, + ressubpath varchar(2048), creator_id bigint not null, - commenttext longtext, - parent_key bigint, + commenttext longtext, + parent_key bigint, primary key (comment_id) ); create table if not exists o_userrating ( - rating_id bigint not null, - version mediumint unsigned not null, - creationdate datetime, + rating_id bigint not null, + version mediumint unsigned not null, + creationdate datetime, lastmodified datetime, - resname varchar(50) not null, - resid bigint not null, - ressubpath varchar(2048), + resname varchar(50) not null, + resid bigint not null, + ressubpath varchar(2048), creator_id bigint not null, - rating integer not null, + rating integer not null, primary key (rating_id) ); @@ -783,6 +783,7 @@ create table if not exists o_info_message ( modificationdate datetime, title varchar(2048), message longtext, + attachmentpath varchar(1024), resname varchar(50) NOT NULL, resid bigint NOT NULL, ressubpath varchar(2048), @@ -864,7 +865,7 @@ create table if not exists o_ep_struct_el ( target_resid bigint, target_ressubpath varchar(2048), target_businesspath varchar(2048), - style varchar(128), + style varchar(128), status varchar(32), viewmode varchar(32), fk_struct_root_id bigint, @@ -872,7 +873,7 @@ create table if not exists o_ep_struct_el ( fk_map_source_id bigint, fk_group_id bigint, fk_olatresource bigint not null, - primary key (structure_id) + primary key (structure_id) ); create table if not exists o_ep_struct_struct_link ( link_id bigint not null, @@ -1004,6 +1005,19 @@ create table if not exists o_ac_offer_access ( primary key (offer_method_id) ); +create table o_ac_auto_advance_order ( + id bigint not null auto_increment, + creationdate datetime not null, + lastmodified datetime not null, + a_identifier_key varchar(64) not null, + a_identifier_value varchar(64) not null, + a_status varchar(32) not null, + a_status_modified datetime not null, + fk_identity int8 not null, + fk_method int8 not null, + primary key (id) +); + -- access cart create table if not exists o_ac_order ( order_id bigint NOT NULL, @@ -1126,6 +1140,8 @@ create table if not exists o_as_eff_statement ( id bigint not null, version mediumint unsigned not null, lastmodified datetime, + lastcoachmodified datetime, + lastusermodified datetime, creationdate datetime, passed bit default null, score float(65,30), @@ -1160,6 +1176,8 @@ create table o_as_entry ( id bigint not null auto_increment, creationdate datetime not null, lastmodified datetime not null, + lastcoachmodified datetime, + lastusermodified datetime, a_attemtps bigint default null, a_score float(65,30) default null, a_passed bit default null, @@ -1437,7 +1455,7 @@ create table o_qti_assessmenttest_session ( q_duration bigint, q_score float(65,30) default null, q_manual_score float(65,30) default null, - q_passed bit default null, + q_passed bit default null, q_storage varchar(1024), fk_reference_entry bigint not null, fk_entry bigint, @@ -1483,6 +1501,7 @@ create table o_qti_assessment_marks ( creationdate datetime not null, lastmodified datetime not null, q_marks mediumtext default null, + q_hidden_rubrics mediumtext default null, fk_reference_entry bigint not null, fk_entry bigint, q_subident varchar(64), @@ -1854,13 +1873,38 @@ create table o_gta_task ( g_status varchar(36), g_rev_loop mediumint not null default 0, g_assignment_date datetime, + g_submission_date datetime, + g_submission_ndocs bigint, + g_submission_revisions_date datetime, + g_submission_revisions_ndocs bigint, + g_collection_date datetime, + g_collection_ndocs bigint, + g_acceptation_date datetime, + g_solution_date datetime, + g_graduation_date datetime, + g_allow_reset_date datetime, + g_assignment_due_date datetime, + g_submission_due_date datetime, + g_revisions_due_date datetime, + g_solution_due_date datetime, g_taskname varchar(1024), fk_tasklist bigint not null, fk_identity bigint, fk_businessgroup bigint, + fk_allow_reset_identity bigint, primary key (id) ); +create table o_gta_task_revision_date ( + id bigint not null auto_increment, + creationdate datetime not null, + g_status varchar(36) not null, + g_rev_loop bigint not null, + g_date datetime not null, + fk_task bigint not null, + primary key (id) +); + create table o_rem_reminder ( id bigint not null, creationdate datetime not null, @@ -1869,6 +1913,7 @@ create table o_rem_reminder ( r_start datetime, r_sendtime varchar(16), r_configuration mediumtext, + r_email_subject varchar(255), r_email_body mediumtext, fk_creator bigint not null, fk_entry bigint not null, @@ -1929,12 +1974,12 @@ create table o_feed ( f_resourceable_id bigint, f_resourceable_type varchar(64), f_title varchar(1024), - f_description varchar(1024), + f_description varchar(4000), f_author varchar(255), - f_image_name varchar(255), + f_image_name varchar(1024), f_external boolean, - f_external_feed_url varchar(1024), - f_external_image_url varchar(1024), + f_external_feed_url varchar(4000), + f_external_image_url varchar(4000), primary key (id) ); @@ -1947,7 +1992,7 @@ create table o_feed_item ( f_content mediumtext, f_author varchar(255), f_guid varchar(255), - f_external_link varchar(1024), + f_external_link varchar(4000), f_draft boolean, f_publish_date datetime, f_width bigint, @@ -1955,7 +2000,7 @@ create table o_feed_item ( f_filename varchar(1024), f_type varchar(255), f_length bigint, - f_external_url varchar(1024), + f_external_url varchar(4000), fk_feed_id bigint not null, fk_identity_author_id bigint, fk_identity_modified_id bigint, @@ -1982,8 +2027,7 @@ create table o_lecture_block ( l_descr mediumtext, l_preparation mediumtext, l_location varchar(255), - l_comment mediumtext, - l_log mediumtext, + l_comment mediumtext, l_start_date datetime not null, l_end_date datetime not null, l_compulsory bit default 1, @@ -2011,8 +2055,7 @@ create table o_lecture_block_roll_call ( id bigint not null auto_increment, creationdate datetime not null, lastmodified datetime not null, - l_comment mediumtext, - l_log mediumtext, + l_comment mediumtext, l_lectures_attended varchar(128), l_lectures_absent varchar(128), l_lectures_attended_num bigint not null default 0, @@ -2020,6 +2063,7 @@ create table o_lecture_block_roll_call ( l_absence_reason mediumtext, l_absence_authorized bit default null, l_absence_appeal_date datetime, + l_absence_supervisor_noti_date datetime, fk_lecture_block bigint not null, fk_identity bigint not null, primary key (id) @@ -2070,6 +2114,20 @@ create table o_lecture_entry_config ( primary key (id) ); +create table o_lecture_block_audit_log ( + id bigint not null auto_increment, + creationdate datetime not null, + l_action varchar(32), + l_val_before mediumtext, + l_val_after mediumtext, + l_message mediumtext, + fk_lecture_block bigint, + fk_roll_call bigint, + fk_entry bigint, + fk_identity bigint, + fk_author bigint, + primary key (id) +); -- user view create view o_bs_identity_short_v as ( @@ -2131,7 +2189,7 @@ create or replace view o_ep_notifications_rating_v as ( page.title as page_title, urating.creator_id as author_id, urating.creationdate as creation_date, - urating.lastmodified as last_modified + urating.lastmodified as last_modified from o_userrating as urating inner join o_olatresource as rating_resource on (rating_resource.resid = urating.resid and rating_resource.resname = urating.resname) inner join o_ep_struct_el as map on (map.fk_olatresource = rating_resource.resource_id) @@ -2154,7 +2212,7 @@ create or replace view o_ep_notifications_comment_v as ( ); create view o_gp_business_to_repository_v as ( - select + select grp.group_id as grp_id, repoentry.repositoryentry_id as re_id, repoentry.displayname as re_displayname @@ -2185,9 +2243,9 @@ create or replace view o_re_membership_v as ( re.repositoryentry_id as fk_entry_id from o_repositoryentry as re inner join o_re_to_group relgroup on (relgroup.fk_entry_id=re.repositoryentry_id and relgroup.r_defgroup=1) - inner join o_bs_group_member as bmember on (bmember.fk_group_id=relgroup.fk_group_id) + inner join o_bs_group_member as bmember on (bmember.fk_group_id=relgroup.fk_group_id) ); - + -- contacts create view o_gp_contactkey_v as ( select @@ -2344,6 +2402,7 @@ alter table o_ac_order_line ENGINE = InnoDB; alter table o_ac_transaction ENGINE = InnoDB; alter table o_ac_reservation ENGINE = InnoDB; alter table o_ac_paypal_transaction ENGINE = InnoDB; +alter table o_ac_auto_advance_order ENGINE = InnoDB; alter table o_as_eff_statement ENGINE = InnoDB; alter table o_as_user_course_infos ENGINE = InnoDB; alter table o_as_mode_course ENGINE = InnoDB; @@ -2379,6 +2438,7 @@ alter table o_cl_checkbox ENGINE = InnoDB; alter table o_cl_check ENGINE = InnoDB; alter table o_gta_task_list ENGINE = InnoDB; alter table o_gta_task ENGINE = InnoDB; +alter table o_gta_task_revision_date ENGINE = InnoDB; alter table o_cer_template ENGINE = InnoDB; alter table o_cer_certificate ENGINE = InnoDB; alter table o_rem_reminder ENGINE = InnoDB; @@ -2411,6 +2471,7 @@ alter table o_lecture_block_roll_call ENGINE = InnoDB; alter table o_lecture_reminder ENGINE = InnoDB; alter table o_lecture_participant_summary ENGINE = InnoDB; alter table o_lecture_entry_config ENGINE = InnoDB; +alter table o_lecture_block_audit_log ENGINE = InnoDB; -- rating alter table o_userrating add constraint FKF26C8375236F20X foreign key (creator_id) references o_bs_identity (id); @@ -2571,6 +2632,11 @@ create index paypal_pay_key_idx on o_ac_paypal_transaction (pay_key); create index paypal_pay_trx_id_idx on o_ac_paypal_transaction (ipn_transaction_id); create index paypal_pay_s_trx_id_idx on o_ac_paypal_transaction (ipn_sender_transaction_id); +create index idx_ac_aao_id_idx on o_ac_auto_advance_order(id); +create index idx_ac_aao_identifier_idx on o_ac_auto_advance_order(a_identifier_key, a_identifier_value); +create index idx_ac_aao_ident_idx on o_ac_auto_advance_order(fk_identity); +alter table o_ac_auto_advance_order add constraint aao_ident_idx foreign key (fk_identity) references o_bs_identity (id); + -- reservations alter table o_ac_reservation add constraint idx_rsrv_to_rsrc_rsrc foreign key (fk_resource) references o_olatresource (resource_id); alter table o_ac_reservation add constraint idx_rsrv_to_rsrc_identity foreign key (fk_identity) references o_bs_identity (id); @@ -2597,9 +2663,12 @@ create index idx_checkbox_uuid_idx on o_cl_checkbox (c_checkboxid); alter table o_gta_task add constraint gtask_to_tasklist_idx foreign key (fk_tasklist) references o_gta_task_list (id); alter table o_gta_task add constraint gtask_to_identity_idx foreign key (fk_identity) references o_bs_identity (id); alter table o_gta_task add constraint gtask_to_bgroup_idx foreign key (fk_businessgroup) references o_gp_business (group_id); +alter table o_gta_task add constraint gtaskreset_to_allower_idx foreign key (fk_allow_reset_identity) references o_bs_identity (id); alter table o_gta_task_list add constraint gta_list_to_repo_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); +alter table o_gta_task_revision_date add constraint gtaskrev_to_task_idx foreign key (fk_task) references o_gta_task (id); + -- reminders alter table o_rem_reminder add constraint rem_reminder_to_repo_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); alter table o_rem_reminder add constraint rem_reminder_to_creator_idx foreign key (fk_creator) references o_bs_identity (id); @@ -2898,6 +2967,9 @@ alter table o_lecture_participant_summary add constraint lec_part_ident_idx fore alter table o_lecture_entry_config add constraint lec_entry_config_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); +create index idx_lec_audit_entry_idx on o_lecture_block_audit_log(fk_entry); +create index idx_lec_audit_ident_idx on o_lecture_block_audit_log(fk_identity); + -- o_logging_table create index log_target_resid_idx on o_loggingtable(targetresid); create index log_ptarget_resid_idx on o_loggingtable(parentresid); diff --git a/src/main/resources/database/oracle/alter_11_5_x_to_12_0_0.sql b/src/main/resources/database/oracle/alter_11_5_x_to_12_0_0.sql index 5f1d9ae5c0693ff063e6b873bbfc2d60500342ed..0b060d8af1b7a04e2886884b1772a6990b4007a6 100644 --- a/src/main/resources/database/oracle/alter_11_5_x_to_12_0_0.sql +++ b/src/main/resources/database/oracle/alter_11_5_x_to_12_0_0.sql @@ -70,8 +70,7 @@ create table o_lecture_block ( l_descr clob, l_preparation clob, l_location varchar2(255 char), - l_comment clob, - l_log clob, + l_comment clob, l_start_date date not null, l_end_date date not null, l_compulsory number default 1 not null, @@ -113,8 +112,7 @@ create table o_lecture_block_roll_call ( id number(20) generated always as identity, creationdate date not null, lastmodified date not null, - l_comment clob, - l_log clob, + l_comment clob, l_lectures_attended varchar2(128 char), l_lectures_absent varchar2(128 char), l_lectures_attended_num number(20) default 0 not null, @@ -193,4 +191,78 @@ create table o_lecture_entry_config ( alter table o_lecture_entry_config add constraint lec_entry_config_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); +create table o_lecture_block_audit_log ( + id number(20) generated always as identity, + creationdate date not null, + l_action varchar2(32 char), + l_val_before CLOB, + l_val_after CLOB, + l_message CLOB, + fk_lecture_block number(20), + fk_roll_call number(20), + fk_entry number(20), + fk_identity number(20), + fk_author number(20), + primary key (id) +); + +create index idx_lec_audit_entry_idx on o_lecture_block_audit_log(fk_entry); +create index idx_lec_audit_ident_idx on o_lecture_block_audit_log(fk_identity); + + +alter table o_rem_reminder add r_email_subject varchar2(255 char); +update o_rem_reminder set r_email_subject=r_description; + + +alter table o_qti_assessment_marks add q_hidden_rubrics clob default null; + + +alter table o_gta_task add g_submission_date date default null; +alter table o_gta_task add g_submission_revisions_date date default null; +alter table o_gta_task add g_collection_date date default null; + +alter table o_gta_task add g_assignment_due_date date default null; +alter table o_gta_task add g_submission_due_date date default null; +alter table o_gta_task add g_revisions_due_date date default null; +alter table o_gta_task add g_solution_due_date date default null; + +alter table o_gta_task add g_acceptation_date date default null; +alter table o_gta_task add g_solution_date date default null; +alter table o_gta_task add g_graduation_date date default null; + +alter table o_gta_task add g_submission_ndocs number(20) default null; +alter table o_gta_task add g_submission_revisions_ndocs number(20) default null; +alter table o_gta_task add g_collection_ndocs number(20) default null; + +create table o_gta_task_revision_date ( + id number(20) generated always as identity, + creationdate date not null, + g_status varchar2(36 char) not null, + g_rev_loop number(20) not null, + g_date date not null, + fk_task number(20) not null, + primary key (id) +); + +alter table o_gta_task_revision_date add constraint gtaskrev_to_task_idx foreign key (fk_task) references o_gta_task (id); +create index idx_gtaskrev_to_task_idx on o_gta_task_revision_date (fk_task); + +alter table o_gta_task add g_allow_reset_date date default null; +alter table o_gta_task add fk_allow_reset_identity number(20) default null; + +alter table o_gta_task add constraint gtaskreset_to_allower_idx foreign key (fk_allow_reset_identity) references o_bs_identity (id); +create index idx_gtaskreset_to_allower_idx on o_gta_task (fk_allow_reset_identity); + + +alter table alter table o_info_message add attachmentpath varchar(1024) default null; + + +alter table o_as_entry add lastcoachmodified date default null; +alter table o_as_entry add lastusermodified date default null; + +alter table o_as_eff_statement add column lastcoachmodified date default null; +alter table o_as_eff_statement add column lastusermodified date default null; + + + diff --git a/src/main/resources/database/oracle/alter_12_0_0_to_12_0_1.sql b/src/main/resources/database/oracle/alter_12_0_0_to_12_0_1.sql new file mode 100644 index 0000000000000000000000000000000000000000..d971c31a359b284600b8f21d12c426b3b8310408 --- /dev/null +++ b/src/main/resources/database/oracle/alter_12_0_0_to_12_0_1.sql @@ -0,0 +1,7 @@ +alter table o_feed modify f_external_feed_url varchar(4000); +alter table o_feed modify f_external_image_url varchar(4000); +alter table o_feed modify f_description varchar(4000); +alter table o_feed modify f_image_name varchar(1024); + +alter table o_feed_item modify f_external_url varchar(4000); +alter table o_feed_item modify f_external_link varchar(4000); diff --git a/src/main/resources/database/oracle/alter_12_0_x_to_12_1_0.sql b/src/main/resources/database/oracle/alter_12_0_x_to_12_1_0.sql new file mode 100644 index 0000000000000000000000000000000000000000..4153a925f529e73f2fa8cd65d88ef3e167774192 --- /dev/null +++ b/src/main/resources/database/oracle/alter_12_0_x_to_12_1_0.sql @@ -0,0 +1,22 @@ +-- auto access controll +create table o_ac_auto_advance_order ( + id number(20) generated always as identity, + creationdate date not null, + lastmodified date not null, + a_identifier_key varchar(64) not null, + a_identifier_value varchar(64) not null, + a_status varchar(32) not null, + a_status_modified date not null, + fk_identity number(20) not null, + fk_method number(20) not null, + primary key (id) +); + +create index idx_ac_aao_id_idx on o_ac_auto_advance_order(id); +create index idx_ac_aao_identifier_idx on o_ac_auto_advance_order(a_identifier_key, a_identifier_value); +create index idx_ac_aao_ident_idx on o_ac_auto_advance_order(fk_identity); +alter table o_ac_auto_advance_order add constraint aao_ident_idx foreign key (fk_identity) references o_bs_identity (id); + + +-- lectures +alter table o_lecture_block_roll_call add l_absence_supervisor_noti_date date default null; \ No newline at end of file diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql index 62060d19ceb3cb1aaf4dcabba16f78c68a7864f8..34d63b3a9f3f5bd048a936144a2d1c045bc9d7b1 100644 --- a/src/main/resources/database/oracle/setupDatabase.sql +++ b/src/main/resources/database/oracle/setupDatabase.sql @@ -324,7 +324,7 @@ CREATE TABLE o_user ( u_genericcheckboxproperty varchar2(255 char), u_genericcheckboxproperty2 varchar2(255 char), u_genericcheckboxproperty3 varchar2(255 char), - + fk_identity number(20), PRIMARY KEY (user_id) ); @@ -701,6 +701,7 @@ CREATE TABLE o_info_message ( modificationdate date, title varchar2(2048 char), message clob, + attachmentpath varchar(1024), resname varchar(50 char) NOT NULL, resid number(20) NOT NULL, ressubpath varchar2(2048 char), @@ -758,7 +759,7 @@ create table o_ep_struct_el ( target_resid number(20), target_ressubpath varchar(2048 char), target_businesspath varchar(2048 char), - style varchar(128 char), + style varchar(128 char), status varchar(32 char), viewmode varchar(32 char), fk_struct_root_id number(20), @@ -766,7 +767,7 @@ create table o_ep_struct_el ( fk_map_source_id number(20), fk_ownergroup number(20), fk_olatresource number(20) not null, - primary key (structure_id) + primary key (structure_id) ); create table o_ep_struct_struct_link ( @@ -961,7 +962,7 @@ create table o_ac_order_line ( fk_order_part_id number(20), fk_offer_id number(20), primary key (order_item_id) -); +); create table o_ac_transaction ( transaction_id number(20) NOT NULL, @@ -1019,6 +1020,19 @@ create table o_ac_paypal_transaction ( primary key (transaction_id) ); +create table o_ac_auto_advance_order ( + id number(20) generated always as identity, + creationdate date not null, + lastmodified date not null, + a_identifier_key varchar(64) not null, + a_identifier_value varchar(64) not null, + a_status varchar(32) not null, + a_status_modified date not null, + fk_identity number(20) not null, + fk_method number(20) not null, + primary key (id) +); + CREATE TABLE o_stat_lastupdated ( lastupdated date not null, from_datetime date not null, @@ -1153,6 +1167,8 @@ create table o_as_eff_statement ( id number(20) not null, version number(20) not null, lastmodified date, + lastcoachmodified date, + lastusermodified date, creationdate date, passed number, score float(4), @@ -1188,6 +1204,8 @@ create table o_as_entry ( id number(20) GENERATED ALWAYS AS IDENTITY, creationdate date not null, lastmodified date not null, + lastcoachmodified date, + lastusermodified date, a_attemtps number(20) default null, a_score decimal default null, a_passed number default null, @@ -1510,6 +1528,7 @@ create table o_qti_assessment_marks ( creationdate date not null, lastmodified date not null, q_marks clob default null, + q_hidden_rubrics clob default null, fk_reference_entry number(20) not null, fk_entry number(20), q_subident varchar2(64 char), @@ -1878,12 +1897,37 @@ create table o_gta_task ( g_rev_loop number(20) default 0 not null, g_taskname varchar2(1024 char), g_assignment_date date, + g_submission_date date, + g_submission_ndocs number(20), + g_submission_revisions_date date, + g_submission_revisions_ndocs number(20), + g_collection_date date, + g_collection_ndocs number(20), + g_acceptation_date date, + g_solution_date date, + g_graduation_date date, + g_allow_reset_date date, + g_assignment_due_date date, + g_submission_due_date date, + g_revisions_due_date date, + g_solution_due_date date, fk_tasklist number(20) not null, fk_identity number(20), fk_businessgroup number(20), + fk_allow_reset_identity number(20), primary key (id) ); +create table o_gta_task_revision_date ( + id number(20) generated always as identity, + creationdate date not null, + g_status varchar2(36 char) not null, + g_rev_loop number(20) not null, + g_date date not null, + fk_task number(20) not null, + primary key (id) +); + create table o_rem_reminder ( id number(20) not null, creationdate date not null, @@ -1892,6 +1936,7 @@ create table o_rem_reminder ( r_start date, r_sendtime varchar(16), r_configuration clob, + r_email_subject varchar(255), r_email_body clob, fk_creator number(20) not null, fk_entry number(20) not null, @@ -1965,13 +2010,13 @@ create table o_sms_message_log ( ); -- webfeed -create table o_feed ( +create table o_feed ( id number(20) generated always as identity, creationdate date not null, lastmodified date not null, f_resourceable_id number(20), f_resourceable_type varchar(64), - f_title varchar(1024), + f_title varchar(1024), f_description varchar(1024), f_author varchar(255), f_image_name varchar(255), @@ -2025,8 +2070,7 @@ create table o_lecture_block ( l_descr clob, l_preparation clob, l_location varchar2(255 char), - l_comment clob, - l_log clob, + l_comment clob, l_start_date date not null, l_end_date date not null, l_compulsory number default 1 not null, @@ -2054,8 +2098,7 @@ create table o_lecture_block_roll_call ( id number(20) generated always as identity, creationdate date not null, lastmodified date not null, - l_comment clob, - l_log clob, + l_comment clob, l_lectures_attended varchar2(128 char), l_lectures_absent varchar2(128 char), l_lectures_attended_num number(20) default 0 not null, @@ -2063,6 +2106,7 @@ create table o_lecture_block_roll_call ( l_absence_reason clob, l_absence_authorized number default null, l_absence_appeal_date date, + l_absence_supervisor_noti_date date, fk_lecture_block number(20) not null, fk_identity number(20) not null, primary key (id) @@ -2113,6 +2157,21 @@ create table o_lecture_entry_config ( primary key (id) ); +create table o_lecture_block_audit_log ( + id number(20) generated always as identity, + creationdate date not null, + l_action varchar2(32 char), + l_val_before CLOB, + l_val_after CLOB, + l_message CLOB, + fk_lecture_block number(20), + fk_roll_call number(20), + fk_entry number(20), + fk_identity number(20), + fk_author number(20), + primary key (id) +); + -- user view create view o_bs_identity_short_v as ( select @@ -2173,7 +2232,7 @@ create or replace view o_ep_notifications_rating_v as ( page.title as page_title, urating.creator_id as author_id, urating.creationdate as creation_date, - urating.lastmodified as last_modified + urating.lastmodified as last_modified from o_userrating urating inner join o_olatresource rating_resource on (rating_resource.resid = urating.resid and rating_resource.resname = urating.resname) inner join o_ep_struct_el map on (map.fk_olatresource = rating_resource.resource_id) @@ -2197,7 +2256,7 @@ create or replace view o_ep_notifications_comment_v as ( ); create view o_gp_business_to_repository_v as ( - select + select grp.group_id as grp_id, repoentry.repositoryentry_id as re_id, repoentry.displayname as re_displayname @@ -2228,7 +2287,7 @@ create or replace view o_re_membership_v as ( re.repositoryentry_id as fk_entry_id from o_repositoryentry re inner join o_re_to_group relgroup on (relgroup.fk_entry_id=re.repositoryentry_id and relgroup.r_defgroup=1) - inner join o_bs_group_member bmember on (bmember.fk_group_id=relgroup.fk_group_id) + inner join o_bs_group_member bmember on (bmember.fk_group_id=relgroup.fk_group_id) ); -- contacts @@ -2630,6 +2689,11 @@ create index paypal_pay_key_idx on o_ac_paypal_transaction (pay_key); create index paypal_pay_trx_id_idx on o_ac_paypal_transaction (ipn_transaction_id); create index paypal_pay_s_trx_id_idx on o_ac_paypal_transaction (ipn_sender_transaction_id); +create index idx_ac_aao_id_idx on o_ac_auto_advance_order(id); +create index idx_ac_aao_identifier_idx on o_ac_auto_advance_order(a_identifier_key, a_identifier_value); +create index idx_ac_aao_ident_idx on o_ac_auto_advance_order(fk_identity); +alter table o_ac_auto_advance_order add constraint aao_ident_idx foreign key (fk_identity) references o_bs_identity (id); + -- reservations alter table o_ac_reservation add constraint idx_rsrv_to_rsrc_rsrc foreign key (fk_resource) references o_olatresource (resource_id); create index idx_rsrv_to_rsrc_idx on o_ac_reservation(fk_resource); @@ -2667,10 +2731,15 @@ alter table o_gta_task add constraint gtask_to_identity_idx foreign key (fk_iden create index idx_gtask_to_identity_idx on o_gta_task (fk_identity); alter table o_gta_task add constraint gtask_to_bgroup_idx foreign key (fk_businessgroup) references o_gp_business (group_id); create index idx_gtask_to_bgroup_idx on o_gta_task (fk_businessgroup); +alter table o_gta_task add constraint gtaskreset_to_allower_idx foreign key (fk_allow_reset_identity) references o_bs_identity (id); +create index idx_gtaskreset_to_allower_idx on o_gta_task (fk_allow_reset_identity); alter table o_gta_task_list add constraint gta_list_to_repo_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); create index idx_gta_list_to_repo_entry_idx on o_gta_task_list (fk_entry); +alter table o_gta_task_revision_date add constraint gtaskrev_to_task_idx foreign key (fk_task) references o_gta_task (id); +create index idx_gtaskrev_to_task_idx on o_gta_task_revision_date (fk_task); + -- reminders alter table o_rem_reminder add constraint rem_reminder_to_repo_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); create index idx_reminder_to_repo_entry_idx on o_rem_reminder (fk_entry); @@ -3092,6 +3161,9 @@ create index idx_lec_part_ident_idx on o_lecture_participant_summary(fk_identity alter table o_lecture_entry_config add constraint lec_entry_config_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); +create index idx_lec_audit_entry_idx on o_lecture_block_audit_log(fk_entry); +create index idx_lec_audit_ident_idx on o_lecture_block_audit_log(fk_identity); + -- o_logging_table create index log_target_resid_idx on o_loggingtable(targetresid); create index log_ptarget_resid_idx on o_loggingtable(parentresid); diff --git a/src/main/resources/database/postgresql/alter_11_5_x_to_12_0_0.sql b/src/main/resources/database/postgresql/alter_11_5_x_to_12_0_0.sql index a093b29fb06518f1692779ec979bc6cb4b647f02..4a0d80df14799fc36f04fbc90af4b907e923731b 100644 --- a/src/main/resources/database/postgresql/alter_11_5_x_to_12_0_0.sql +++ b/src/main/resources/database/postgresql/alter_11_5_x_to_12_0_0.sql @@ -69,8 +69,7 @@ create table o_lecture_block ( l_descr text, l_preparation text, l_location varchar(255), - l_comment text, - l_log text, + l_comment text, l_start_date timestamp not null, l_end_date timestamp not null, l_compulsory bool default true, @@ -112,8 +111,7 @@ create table o_lecture_block_roll_call ( id bigserial not null, creationdate timestamp not null, lastmodified timestamp not null, - l_comment text, - l_log text, + l_comment text, l_lectures_attended varchar(128), l_lectures_absent varchar(128), l_lectures_attended_num int8 not null default 0, @@ -193,4 +191,77 @@ alter table o_lecture_entry_config add constraint lec_entry_config_entry_idx for create index idx_lec_entry_conf_entry_idx on o_lecture_entry_config(fk_entry); +create table o_lecture_block_audit_log ( + id bigserial not null, + creationdate timestamp not null, + l_action varchar(32), + l_val_before text, + l_val_after text, + l_message text, + fk_lecture_block int8, + fk_roll_call int8, + fk_entry int8, + fk_identity int8, + fk_author int8, + primary key (id) +); + +create index idx_lec_audit_entry_idx on o_lecture_block_audit_log(fk_entry); +create index idx_lec_audit_ident_idx on o_lecture_block_audit_log(fk_identity); + + +alter table o_rem_reminder add column r_email_subject varchar(255); +update o_rem_reminder set r_email_subject=r_description; + + +alter table o_qti_assessment_marks add column q_hidden_rubrics text default null; + + +alter table o_gta_task add column g_submission_date timestamp default null; +alter table o_gta_task add column g_submission_revisions_date timestamp default null; +alter table o_gta_task add column g_collection_date timestamp default null; + +alter table o_gta_task add column g_assignment_due_date timestamp default null; +alter table o_gta_task add column g_submission_due_date timestamp default null; +alter table o_gta_task add column g_revisions_due_date timestamp default null; +alter table o_gta_task add column g_solution_due_date timestamp default null; + +alter table o_gta_task add column g_acceptation_date timestamp default null; +alter table o_gta_task add column g_solution_date timestamp default null; +alter table o_gta_task add column g_graduation_date timestamp default null; + +alter table o_gta_task add column g_submission_ndocs int8 default null; +alter table o_gta_task add column g_submission_revisions_ndocs int8 default null; +alter table o_gta_task add column g_collection_ndocs int8 default null; + +create table o_gta_task_revision_date ( + id bigserial not null, + creationdate timestamp not null, + g_status varchar(36) not null, + g_rev_loop int8 not null, + g_date timestamp not null, + fk_task int8 not null, + primary key (id) +); + +alter table o_gta_task_revision_date add constraint gtaskrev_to_task_idx foreign key (fk_task) references o_gta_task (id); +create index idx_gtaskrev_to_task_idx on o_gta_task_revision_date (fk_task); + +alter table o_gta_task add column g_allow_reset_date timestamp default null; +alter table o_gta_task add column fk_allow_reset_identity int8 default null; + +alter table o_gta_task add constraint gtaskreset_to_allower_idx foreign key (fk_allow_reset_identity) references o_bs_identity (id); +create index idx_gtaskreset_to_allower_idx on o_gta_task (fk_allow_reset_identity); + + +alter table o_info_message add column attachmentpath varchar(1024) default null; + + +alter table o_as_entry add column lastcoachmodified timestamp default null; +alter table o_as_entry add column lastusermodified timestamp default null; + +alter table o_as_eff_statement add column lastcoachmodified timestamp default null; +alter table o_as_eff_statement add column lastusermodified timestamp default null; + + diff --git a/src/main/resources/database/postgresql/alter_12_0_0_to_12_0_1.sql b/src/main/resources/database/postgresql/alter_12_0_0_to_12_0_1.sql new file mode 100644 index 0000000000000000000000000000000000000000..d1a10e4af315915a981162db2384332a42913fde --- /dev/null +++ b/src/main/resources/database/postgresql/alter_12_0_0_to_12_0_1.sql @@ -0,0 +1,7 @@ +alter table o_feed alter column f_external_feed_url type character varying(4000); +alter table o_feed alter column f_external_image_url type character varying(4000); +alter table o_feed alter column f_description type character varying(4000); +alter table o_feed alter column f_image_name type character varying(1024); + +alter table o_feed_item alter column f_external_url type character varying(4000); +alter table o_feed_item alter column f_external_link type character varying(4000); diff --git a/src/main/resources/database/postgresql/alter_12_0_x_to_12_1_0.sql b/src/main/resources/database/postgresql/alter_12_0_x_to_12_1_0.sql new file mode 100644 index 0000000000000000000000000000000000000000..5550754b7d2a6f3d5009aec663beb8a3e7cdd9a3 --- /dev/null +++ b/src/main/resources/database/postgresql/alter_12_0_x_to_12_1_0.sql @@ -0,0 +1,22 @@ +-- auto access controll +create table o_ac_auto_advance_order ( + id bigserial, + creationdate timestamp not null, + lastmodified timestamp not null, + a_identifier_key varchar(64) not null, + a_identifier_value varchar(64) not null, + a_status varchar(32) not null, + a_status_modified timestamp not null, + fk_identity int8 not null, + fk_method int8 not null, + primary key (id) +); + +create index idx_ac_aao_id_idx on o_ac_auto_advance_order(id); +create index idx_ac_aao_identifier_idx on o_ac_auto_advance_order(a_identifier_key, a_identifier_value); +create index idx_ac_aao_ident_idx on o_ac_auto_advance_order(fk_identity); +alter table o_ac_auto_advance_order add constraint aao_ident_idx foreign key (fk_identity) references o_bs_identity (id); + + +-- lectures +alter table o_lecture_block_roll_call add column l_absence_supervisor_noti_date timestamp default null; \ No newline at end of file diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql index 202eb2940bd4e8ae815e91a9851f38616def6188..f303e12abcb40e9e12db20135a9ae7ad950ed6cd 100644 --- a/src/main/resources/database/postgresql/setupDatabase.sql +++ b/src/main/resources/database/postgresql/setupDatabase.sql @@ -455,10 +455,10 @@ create table o_bs_membership ( ); create table o_plock ( - plock_id int8 not null, + plock_id int8 not null, version int4 not null, - creationdate timestamp, - asset varchar(255) not null unique, + creationdate timestamp, + asset varchar(255) not null unique, primary key (plock_id) ); @@ -479,22 +479,22 @@ create table o_lifecycle ( ); create table oc_lock ( - lock_id int8 not null, + lock_id int8 not null, version int4 not null, - creationdate timestamp, - identity_fk int8 not null, - asset varchar(120) not null unique, + creationdate timestamp, + identity_fk int8 not null, + asset varchar(120) not null unique, primary key (lock_id) ); alter table oc_lock add constraint FK9E30F4B66115906D foreign key (identity_fk) references o_bs_identity; create table o_readmessage ( - id int8 not null, + id int8 not null, version int4 not null, creationdate timestamp, - identity_id int8 not null, - forum_id int8 not null, - message_id int8 not null, + identity_id int8 not null, + forum_id int8 not null, + message_id int8 not null, primary key (id) ); @@ -564,7 +564,7 @@ create table o_checkpoint_results ( lastmodified timestamp not null, result bool not null, checkpoint_fk int8, - identity_fk int8, + identity_fk int8, primary key (checkpoint_result_id) ); @@ -599,27 +599,27 @@ create table o_projectbroker_customfields ( ); create table o_usercomment ( - comment_id int8 not null, - version int4 not null, - creationdate timestamp, - resname varchar(50) not null, - resid int8 not null, - ressubpath varchar(2048), + comment_id int8 not null, + version int4 not null, + creationdate timestamp, + resname varchar(50) not null, + resid int8 not null, + ressubpath varchar(2048), creator_id int8 not null, - commenttext text, - parent_key int8, + commenttext text, + parent_key int8, primary key (comment_id) ); create table o_userrating ( - rating_id int8 not null, - version int4 not null, - creationdate timestamp, + rating_id int8 not null, + version int4 not null, + creationdate timestamp, lastmodified timestamp, - resname varchar(50) not null, - resid int8 not null, - ressubpath varchar(2048), + resname varchar(50) not null, + resid int8 not null, + ressubpath varchar(2048), creator_id int8 not null, - rating int4 not null, + rating int4 not null, primary key (rating_id) ); create table o_info_message ( @@ -629,6 +629,7 @@ create table o_info_message ( modificationdate timestamp, title varchar(2048), message text, + attachmentpath varchar(1024), resname varchar(50) NOT NULL, resid int8 NOT NULL, ressubpath varchar(2048), @@ -704,7 +705,7 @@ create table o_ep_struct_el ( target_resid int8, target_ressubpath varchar(2048), target_businesspath varchar(2048), - style varchar(128), + style varchar(128), status varchar(32), viewmode varchar(32), fk_struct_root_id int8, @@ -712,7 +713,7 @@ create table o_ep_struct_el ( fk_map_source_id int8, fk_group_id int8, fk_olatresource int8 not null, - primary key (structure_id) + primary key (structure_id) ); create table o_ep_struct_struct_link ( link_id int8 not null, @@ -868,6 +869,19 @@ create table o_ac_offer_access ( primary key (offer_method_id) ); +create table o_ac_auto_advance_order ( + id bigserial, + creationdate timestamp not null, + lastmodified timestamp not null, + a_identifier_key varchar(64) not null, + a_identifier_value varchar(64) not null, + a_status varchar(32) not null, + a_status_modified timestamp not null, + fk_identity int8 not null, + fk_method int8 not null, + primary key (id) +); + -- access cart create table o_ac_order ( order_id int8 NOT NULL, @@ -1122,6 +1136,8 @@ create table o_as_eff_statement ( id int8 not null, version int4 not null, lastmodified timestamp, + lastcoachmodified timestamp, + lastusermodified timestamp, creationdate timestamp, passed boolean, score float4, @@ -1158,6 +1174,8 @@ create table o_as_entry ( id bigserial, creationdate timestamp not null, lastmodified timestamp not null, + lastcoachmodified timestamp, + lastusermodified timestamp, a_attemtps int8 default null, a_score decimal default null, a_passed bool default null, @@ -1482,6 +1500,7 @@ create table o_qti_assessment_marks ( creationdate timestamp not null, lastmodified timestamp not null, q_marks text default null, + q_hidden_rubrics text default null, fk_reference_entry int8 not null, fk_entry int8, q_subident varchar(64), @@ -1851,13 +1870,38 @@ create table o_gta_task ( g_status varchar(36), g_rev_loop int4 not null default 0, g_assignment_date timestamp, + g_submission_date timestamp, + g_submission_ndocs int8, + g_submission_revisions_date timestamp, + g_submission_revisions_ndocs int8, + g_collection_date timestamp, + g_collection_ndocs int8, + g_acceptation_date timestamp, + g_solution_date timestamp, + g_graduation_date timestamp, + g_allow_reset_date timestamp, + g_assignment_due_date timestamp, + g_submission_due_date timestamp, + g_revisions_due_date timestamp, + g_solution_due_date timestamp, g_taskname varchar(1024), fk_tasklist int8 not null, fk_identity int8, fk_businessgroup int8, + fk_allow_reset_identity int8, primary key (id) ); +create table o_gta_task_revision_date ( + id bigserial not null, + creationdate timestamp not null, + g_status varchar(36) not null, + g_rev_loop int8 not null, + g_date timestamp not null, + fk_task int8 not null, + primary key (id) +); + create table o_rem_reminder ( id int8 not null, creationdate timestamp not null, @@ -1866,6 +1910,7 @@ create table o_rem_reminder ( r_start timestamp, r_sendtime varchar(16), r_configuration text, + r_email_subject varchar(255), r_email_body text, fk_creator int8 not null, fk_entry int8 not null, @@ -1926,12 +1971,12 @@ create table o_feed ( f_resourceable_id bigint, f_resourceable_type varchar(64), f_title varchar(1024), - f_description varchar(1024), + f_description varchar(4000), f_author varchar(255), - f_image_name varchar(255), + f_image_name varchar(1024), f_external boolean, - f_external_feed_url varchar(1024), - f_external_image_url varchar(1024), + f_external_feed_url varchar(4000), + f_external_image_url varchar(4000), primary key (id) ); @@ -1944,7 +1989,7 @@ create table o_feed_item ( f_content text, f_author varchar(255), f_guid varchar(255), - f_external_link varchar(1024), + f_external_link varchar(4000), f_draft boolean, f_publish_date timestamp, f_width int8, @@ -1952,7 +1997,7 @@ create table o_feed_item ( f_filename varchar(1024), f_type varchar(255), f_length bigint, - f_external_url varchar(1024), + f_external_url varchar(4000), fk_feed_id bigint, fk_identity_author_id int8, fk_identity_modified_id int8, @@ -1980,8 +2025,7 @@ create table o_lecture_block ( l_descr text, l_preparation text, l_location varchar(255), - l_comment text, - l_log text, + l_comment text, l_start_date timestamp not null, l_end_date timestamp not null, l_compulsory bool default true, @@ -2009,8 +2053,7 @@ create table o_lecture_block_roll_call ( id bigserial not null, creationdate timestamp not null, lastmodified timestamp not null, - l_comment text, - l_log text, + l_comment text, l_lectures_attended varchar(128), l_lectures_absent varchar(128), l_lectures_attended_num int8 not null default 0, @@ -2018,6 +2061,7 @@ create table o_lecture_block_roll_call ( l_absence_reason text, l_absence_authorized bool default null, l_absence_appeal_date timestamp, + l_absence_supervisor_noti_date timestamp, fk_lecture_block int8 not null, fk_identity int8 not null, primary key (id) @@ -2068,6 +2112,21 @@ create table o_lecture_entry_config ( primary key (id) ); +create table o_lecture_block_audit_log ( + id bigserial not null, + creationdate timestamp not null, + l_action varchar(32), + l_val_before text, + l_val_after text, + l_message text, + fk_lecture_block int8, + fk_roll_call int8, + fk_entry int8, + fk_identity int8, + fk_author int8, + primary key (id) +); + -- user view create view o_bs_identity_short_v as ( select @@ -2128,7 +2187,7 @@ create or replace view o_ep_notifications_rating_v as ( page.title as page_title, urating.creator_id as author_id, urating.creationdate as creation_date, - urating.lastmodified as last_modified + urating.lastmodified as last_modified from o_userrating as urating inner join o_olatresource as rating_resource on (rating_resource.resid = urating.resid and rating_resource.resname = urating.resname) inner join o_ep_struct_el as map on (map.fk_olatresource = rating_resource.resource_id) @@ -2151,7 +2210,7 @@ create or replace view o_ep_notifications_comment_v as ( ); create view o_gp_business_to_repository_v as ( - select + select grp.group_id as grp_id, repoentry.repositoryentry_id as re_id, repoentry.displayname as re_displayname @@ -2182,9 +2241,9 @@ create or replace view o_re_membership_v as ( re.repositoryentry_id as fk_entry_id from o_repositoryentry as re inner join o_re_to_group relgroup on (relgroup.fk_entry_id=re.repositoryentry_id and relgroup.r_defgroup=true) - inner join o_bs_group_member as bmember on (bmember.fk_group_id=relgroup.fk_group_id) + inner join o_bs_group_member as bmember on (bmember.fk_group_id=relgroup.fk_group_id) ); - + -- contacts create view o_gp_contactkey_v as ( select @@ -2479,6 +2538,11 @@ create index paypal_pay_key_idx on o_ac_paypal_transaction (pay_key); create index paypal_pay_trx_id_idx on o_ac_paypal_transaction (ipn_transaction_id); create index paypal_pay_s_trx_id_idx on o_ac_paypal_transaction (ipn_sender_transaction_id); +create index idx_ac_aao_id_idx on o_ac_auto_advance_order(id); +create index idx_ac_aao_identifier_idx on o_ac_auto_advance_order(a_identifier_key, a_identifier_value); +create index idx_ac_aao_ident_idx on o_ac_auto_advance_order(fk_identity); +alter table o_ac_auto_advance_order add constraint aao_ident_idx foreign key (fk_identity) references o_bs_identity (id); + -- reservations alter table o_ac_reservation add constraint idx_rsrv_to_rsrc_rsrc foreign key (fk_resource) references o_olatresource (resource_id); create index idx_rsrv_to_rsrc_idx on o_ac_reservation(fk_resource); @@ -2516,10 +2580,15 @@ alter table o_gta_task add constraint gtask_to_identity_idx foreign key (fk_iden create index idx_gtask_to_identity_idx on o_gta_task (fk_identity); alter table o_gta_task add constraint gtask_to_bgroup_idx foreign key (fk_businessgroup) references o_gp_business (group_id); create index idx_gtask_to_bgroup_idx on o_gta_task (fk_businessgroup); +alter table o_gta_task add constraint gtaskreset_to_allower_idx foreign key (fk_allow_reset_identity) references o_bs_identity (id); +create index idx_gtaskreset_to_allower_idx on o_gta_task (fk_allow_reset_identity); alter table o_gta_task_list add constraint gta_list_to_repo_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); create index idx_gta_list_to_repo_entry_idx on o_gta_task_list (fk_entry); +alter table o_gta_task_revision_date add constraint gtaskrev_to_task_idx foreign key (fk_task) references o_gta_task (id); +create index idx_gtaskrev_to_task_idx on o_gta_task_revision_date (fk_task); + -- reminders alter table o_rem_reminder add constraint rem_reminder_to_repo_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); create index idx_reminder_to_repo_entry_idx on o_rem_reminder (fk_entry); @@ -2945,6 +3014,9 @@ create index idx_lec_part_ident_idx on o_lecture_participant_summary(fk_identity alter table o_lecture_entry_config add constraint lec_entry_config_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); create index idx_lec_entry_conf_entry_idx on o_lecture_entry_config(fk_entry); +create index idx_lec_audit_entry_idx on o_lecture_block_audit_log(fk_entry); +create index idx_lec_audit_ident_idx on o_lecture_block_audit_log(fk_identity); + -- o_logging_table create index log_target_resid_idx on o_loggingtable(targetresid); create index log_ptarget_resid_idx on o_loggingtable(parentresid); diff --git a/src/main/resources/infinispan-config.xml b/src/main/resources/infinispan-config.xml index 641b6389bdd508e4962de6f9a18507f6485194a2..2c79538a86bc896884ba28223f1b3ed1e619e46e 100644 --- a/src/main/resources/infinispan-config.xml +++ b/src/main/resources/infinispan-config.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns="urn:infinispan:config:7.2" - xsi:schemaLocation="urn:infinispan:config:7.2 http://www.infinispan.org/schemas/infinispan-config-7.2.xsd"> + xmlns="urn:infinispan:config:8.0" + xsi:schemaLocation="urn:infinispan:config:8.2 http://www.infinispan.org/schemas/infinispan-config-8.2.xsd"> <cache-container name="NonTransactionalCacheManager" default-cache="default"> <jmx duplicate-domains="true" /> @@ -10,14 +10,14 @@ <local-cache name="MapperService@mapper" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="10000" strategy="LRU" /> + <eviction size="10000" strategy="LRU" /> <expiration max-idle="300000" interval="5000" /> </local-cache> <local-cache name="OpenMeetingsManager@session" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="10000" strategy="LRU" /> + <eviction size="10000" strategy="LRU" /> <expiration max-idle="300000" interval="5000" /> </local-cache> @@ -31,28 +31,28 @@ <local-cache name="CalendarManager@calendar" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="500" strategy="LRU" /> + <eviction size="500" strategy="LRU" /> <expiration max-idle="900000" interval="5000" /> </local-cache> <local-cache name="AssessmentManager@newpersisting" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="20000" strategy="LRU" /> + <eviction size="20000" strategy="LRU" /> <expiration max-idle="900000" interval="5000" /> </local-cache> <local-cache name="QTIHelper@QTI_xml_Documents" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="200" strategy="LRU" /> + <eviction size="200" strategy="LRU" /> <expiration max-idle="180000" interval="15000" /> </local-cache> <local-cache name="WebDAVManager@webdav" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="2013" strategy="LIRS" /> + <eviction size="2013" strategy="LIRS" /> <expiration max-idle="300000" interval="5000" /> <!-- max-idle same as session time out for WebDAV session in UserSessionManager --> </local-cache> @@ -60,84 +60,84 @@ <local-cache name="UserManager@username" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="20000" strategy="LIRS" /> + <eviction size="20000" strategy="LIRS" /> <expiration max-idle="2700000" interval="15000" /> </local-cache> <local-cache name="UserManager@userfullname" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="20000" strategy="LIRS" /> + <eviction size="20000" strategy="LIRS" /> <expiration max-idle="2700000" interval="15000" /> </local-cache> <local-cache name="Velocity@templates" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="7700" strategy="LRU" /> + <eviction size="7700" strategy="LRU" /> <expiration max-idle="-1" lifespan="-1" interval="-1" /> </local-cache> <local-cache name="LoginModule@blockafterfailedattempts" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="10000" strategy="LRU" /> + <eviction size="10000" strategy="LRU" /> <expiration max-idle="300000" lifespan="300000" interval="5000" /> </local-cache> <local-cache name="NotificationHelper@userPropertiesCache" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="2000" strategy="LRU" /> + <eviction size="2000" strategy="LRU" /> <expiration max-idle="120000" interval="15000" /> </local-cache> <local-cache name="GlossaryItemManager@glossary" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="500" strategy="LRU" /> + <eviction size="500" strategy="LRU" /> <expiration max-idle="3600000" interval="15000" /> </local-cache> <local-cache name="WikiManager@wiki" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="500" strategy="LRU" /> + <eviction size="500" strategy="LRU" /> <expiration max-idle="3600000" interval="15000" /> </local-cache> <local-cache name="CollaborationToolsFactory@tools" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="5000" strategy="LRU" /> + <eviction size="5000" strategy="LRU" /> <expiration max-idle="1800000" interval="15000" /> </local-cache> <local-cache name="CourseFactory@courses" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="1000" strategy="LRU" /> + <eviction size="1000" strategy="LRU" /> <expiration max-idle="3600000" interval="15000" /> </local-cache> <local-cache name="ProjectBrokerManager@pb" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="100" strategy="LRU" /> + <eviction size="100" strategy="LRU" /> <expiration max-idle="3600000" interval="15000" /> </local-cache> <local-cache name="FeedManager@feed" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="1000" strategy="LRU" /> + <eviction size="1000" strategy="LRU" /> <expiration max-idle="900000" interval="15000" /> </local-cache> <local-cache name="Path@feed" statistics="true"> <locking isolation="READ_COMMITTED" concurrency-level="1000" acquire-timeout="15000" striping="false" /> <transaction mode="NONE" auto-commit="true" /> - <eviction max-entries="1000" strategy="LRU" /> + <eviction size="1000" strategy="LRU" /> <expiration max-idle="900000" interval="15000" /> </local-cache> </cache-container> diff --git a/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs-local.xml b/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs-local.xml index be95079b37585b56cf42c98ab8edefb79c7ea904..6074d263ce5bdc20bbe7f209b5b803402bc08091 100644 --- a/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs-local.xml +++ b/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs-local.xml @@ -6,8 +6,8 @@ ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. --> <infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns="urn:infinispan:config:8.0" - xsi:schemaLocation="urn:infinispan:config:8.0 http://www.infinispan.org/schemas/infinispan-config-8.0.xsd"> + xmlns="urn:infinispan:config:8.2" + xsi:schemaLocation="urn:infinispan:config:8.2 http://www.infinispan.org/schemas/infinispan-config-8.2.xsd"> <!-- This configuration is suitable for non-clustered environments, where only single instance accesses the DB --> <cache-container name="SampleCacheManager" statistics="false" default-cache="the-default-cache" shutdown-hook="DEFAULT"> @@ -18,14 +18,14 @@ <!-- Default configuration is appropriate for entity/collection caching. --> <local-cache-configuration name="entity" statistics="false" statistics-available="false"> <transaction mode="NONE" /> - <eviction max-entries="10000" strategy="LRU"/> + <eviction size="10000" strategy="LRU"/> <expiration max-idle="100000" interval="5000"/> </local-cache-configuration> <!-- A config appropriate for query caching. Does not replicate queries. --> <local-cache-configuration name="local-query" statistics="false" statistics-available="false"> <transaction mode="NONE" /> - <eviction max-entries="10000" strategy="LRU"/> + <eviction size="10000" strategy="LRU"/> <expiration max-idle="100000" interval="5000"/> </local-cache-configuration> diff --git a/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml b/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml index be95079b37585b56cf42c98ab8edefb79c7ea904..6074d263ce5bdc20bbe7f209b5b803402bc08091 100644 --- a/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml +++ b/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml @@ -6,8 +6,8 @@ ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. --> <infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns="urn:infinispan:config:8.0" - xsi:schemaLocation="urn:infinispan:config:8.0 http://www.infinispan.org/schemas/infinispan-config-8.0.xsd"> + xmlns="urn:infinispan:config:8.2" + xsi:schemaLocation="urn:infinispan:config:8.2 http://www.infinispan.org/schemas/infinispan-config-8.2.xsd"> <!-- This configuration is suitable for non-clustered environments, where only single instance accesses the DB --> <cache-container name="SampleCacheManager" statistics="false" default-cache="the-default-cache" shutdown-hook="DEFAULT"> @@ -18,14 +18,14 @@ <!-- Default configuration is appropriate for entity/collection caching. --> <local-cache-configuration name="entity" statistics="false" statistics-available="false"> <transaction mode="NONE" /> - <eviction max-entries="10000" strategy="LRU"/> + <eviction size="10000" strategy="LRU"/> <expiration max-idle="100000" interval="5000"/> </local-cache-configuration> <!-- A config appropriate for query caching. Does not replicate queries. --> <local-cache-configuration name="local-query" statistics="false" statistics-available="false"> <transaction mode="NONE" /> - <eviction max-entries="10000" strategy="LRU"/> + <eviction size="10000" strategy="LRU"/> <expiration max-idle="100000" interval="5000"/> </local-cache-configuration> diff --git a/src/main/resources/org/olat/modules/portfolio/ui/export/rasterize.js b/src/main/resources/org/olat/modules/portfolio/ui/export/rasterize.js new file mode 100644 index 0000000000000000000000000000000000000000..07a05b0df9e7e70c5218abef41651a0d52a31d91 --- /dev/null +++ b/src/main/resources/org/olat/modules/portfolio/ui/export/rasterize.js @@ -0,0 +1,26 @@ +var page = require('webpage').create(), + system = require('system'), + address, output; + +if (system.args.length != 3) { + console.log('Usage: rasterize.js URL filename'); + phantom.exit(1); +} else { + address = system.args[1]; + output = system.args[2]; + page.viewportSize = { width: 600, height: 600 }; + page.paperSize = { format: 'A4', orientation: 'portrait', margin: '1cm' }; + + page.open(address, function (status) { + if (status !== 'success') { + console.log('Unable to load the address!'); + phantom.exit(1); + } else { + // Finally render as PDF + window.setTimeout(function () { + page.render(output); + phantom.exit(); + }, 200); + } + }); +} \ No newline at end of file diff --git a/src/main/webapp/static/images/openolat/openolat_comeniusedumed_2017.png b/src/main/webapp/static/images/openolat/openolat_comeniusedumed_2017.png new file mode 100644 index 0000000000000000000000000000000000000000..6a2bdcce154eed89e2e9a99a477a1a4f23468086 Binary files /dev/null and b/src/main/webapp/static/images/openolat/openolat_comeniusedumed_2017.png differ diff --git a/src/main/webapp/static/js/functions.js b/src/main/webapp/static/js/functions.js index 3c5b326b1977f1ee73d562db59a552f59dc95c19..37886d5936085d2be2496ff48cf0fecbab04bf6b 100644 --- a/src/main/webapp/static/js/functions.js +++ b/src/main/webapp/static/js/functions.js @@ -225,6 +225,34 @@ var BFormatter = { } catch(e) { if (window.console) console.log("error in BFormatter.formatLatexFormulas: ", e); } + }, + // Align columns of different tables with the same column count + // Note: it is best to set the width of the fixed sized colums via css + // (e.g. to 1% to make them as small as possible). Table must set to max-size:100% + // to not overflow. New width of table can be larger than before because the largest + // width of each column is applied to all tables. With max-size the browsers magically + // fix this overflow problem. + alignTableColumns : function(tableArray) { + try { + var cellWidths = new Array(); + // find all widest cells + jQuery(tableArray).each(function() { + for(j = 0; j < jQuery(this)[0].rows[0].cells.length; j++){ + var cell = jQuery(this)[0].rows[0].cells[j]; + if(!cellWidths[j] || cellWidths[j] < cell.clientWidth) { + cellWidths[j] = cell.clientWidth; + } + } + }); + // set same width to columns of all tables + jQuery(tableArray).each(function() { + for(j = 0; j < jQuery(this)[0].rows[0].cells.length; j++){ + jQuery(this)[0].rows[0].cells[j].style.width = cellWidths[j]+'px'; + } + }); + } catch(e) { + if (window.console) console.log("error in BFormatter.alignTableColumns: ", e); + } } }; @@ -1280,12 +1308,42 @@ function o_removeIframe(id) { jQuery('#' + id).remove(); } +/** + * Opens the form-dirty dialog. Use the callback to add code that should be executed in case the user + * presses the "ignore button" (Code that executes the original action the user initiated) + */ +function o_showFormDirtyDialog(onIgnoreCallback) { + // open our form-dirty dialog + o_scrollToElement('#o_top'); + jQuery("#o_form_dirty_message").modal('show'); + jQuery("#o_form_dirty_message .o_form_dirty_ignore").on("click", function() { + // Remove dialog and all listeners for dirty button + jQuery("#o_form_dirty_message").modal('hide'); + jQuery("#o_form_dirty_message .o_form_dirty_ignore").off(); + // Execute the ignore callback with original user action + onIgnoreCallback(); + }); + return false; +} + function o_ffXHREvent(formNam, dispIdField, dispId, eventIdField, eventInt, dirtyCheck, push, submit) { - if(dirtyCheck) { - if(!o2cl()) return false; + if(dirtyCheck && o2c==1) { + // Copy function arguments and set the dirtyCheck to false for execution in callback. + // Note that the argument list is dynamic, there are potentially more arguments than + // listed in the function (e.g. in QTI2) + var callbackArguments = Array.prototype.slice.call(arguments); + callbackArguments[5] = false; + var onIgnoreCallback = function() { + // fire original event when the "ok, delete anyway" button was pressed + o_ffXHREvent.apply(window, callbackArguments); + } + return o_showFormDirtyDialog(onIgnoreCallback); } else { if(!o2cl_noDirtyCheck()) return false; - } + } + // Start event execution, start server to prevend concurrent executions of other events. + // o_afterserver() called when AJAX call terminates + o_beforeserver(); var data = new Object(); if(submit) { @@ -1364,11 +1422,23 @@ function o_ffXHRNFEvent(formNam, dispIdField, dispId, eventIdField, eventInt) { } function o_XHREvent(targetUrl, dirtyCheck, push) { - if(dirtyCheck) { - if(!o2cl()) return false; + if(dirtyCheck && o2c==1) { + // Copy function arguments and set the dirtyCheck to false for execution in callback. + // Note that the argument list is dynamic, there are potentially more arguments than + // listed in the function + var callbackArguments = Array.prototype.slice.call(arguments); + callbackArguments[1] = false; + var onIgnoreCallback = function() { + // fire original event when the "ok, delete anyway" button was pressed + o_XHREvent.apply(window, callbackArguments); + } + return o_showFormDirtyDialog(onIgnoreCallback); } else { if(!o2cl_noDirtyCheck()) return false; } + // Start event execution, start server to prevend concurrent executions of other events. + // o_afterserver() called when AJAX call terminates + o_beforeserver(); var data = new Object(); if(arguments.length > 3) { @@ -1476,6 +1546,30 @@ function o_toggleMark(el) { } } +//try to mimic the FileUtils.normalizeFilename method +function o_normalizeFilename(filename) { + filename = filename.replace(/\s/g, "_") + var replaceByUnderscore = [ "/", ",", ":", "(", ")" ]; + for(var i=replaceByUnderscore.length; i-->0; ) { + filename = filename.split(replaceByUnderscore[i]).join("_"); + } + + var beautifyGermanUnicode = [ "\u00C4", "\u00D6", "\u00DC", "\u00E4", "\u00F6", "\u00E6", "\u00FC", "\u00DF", "\u00F8", "\u2205" ], + beautifyGermanReplacement = [ "Ae", "Oe", "Ue", "ae", "oe", "ae", "ue", "ss", "o", "o" ]; + for(var i=beautifyGermanUnicode.length; i-->0; ) { + filename = filename.split(beautifyGermanUnicode[i]).join(beautifyGermanReplacement[i]); + } + + try {//if something is not supported by the browser + filename = filename.normalize('NFKD'); + filename = filename.replace("/\p{InCombiningDiacriticalMarks}+/g",""); + filename = filename.replace("/\W+/g", ""); + } catch(e) { + if(window.console) console.log(e); + } + return filename; +} + // // param formId a String with flexi form id function setFlexiFormDirtyByListener(e){ diff --git a/src/main/webapp/static/js/jquery/maphilight/README b/src/main/webapp/static/js/jquery/maphilight/README new file mode 100644 index 0000000000000000000000000000000000000000..0c71769ea811868e40790e4ad9f984a2472c6a42 --- /dev/null +++ b/src/main/webapp/static/js/jquery/maphilight/README @@ -0,0 +1,2 @@ +There is a change in the javscript: +"background-size": this.width + 'px ' + this.height + 'px', \ No newline at end of file diff --git a/src/main/webapp/static/js/jquery/maphilight/jquery.maphilight.js b/src/main/webapp/static/js/jquery/maphilight/jquery.maphilight.js index c87dcbc42a3f3e11ef49063b2057e50a23b8dcff..9ab89bd3a3687d558cf5add1e21f3d9ff1a8b0d6 100644 --- a/src/main/webapp/static/js/jquery/maphilight/jquery.maphilight.js +++ b/src/main/webapp/static/js/jquery/maphilight/jquery.maphilight.js @@ -245,6 +245,7 @@ wrap = $('<div></div>').css({ display:'block', background:'url("'+this.src+'")', + "background-size": this.width + 'px ' + this.height + 'px', position:'relative', padding:0, width:this.width, diff --git a/src/main/webapp/static/js/jquery/maphilight/jquery.maphilight.min.js b/src/main/webapp/static/js/jquery/maphilight/jquery.maphilight.min.js deleted file mode 100644 index ec9d0214fd494c951f9480ac159c07c5eb23da3e..0000000000000000000000000000000000000000 --- a/src/main/webapp/static/js/jquery/maphilight/jquery.maphilight.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(G){var B,J,C,K,N,M,I,E,H,A,L;J=!!document.createElement("canvas").getContext;B=(function(){var P=document.createElement("div");P.innerHTML='<v:shape id="vml_flag1" adj="1" />';var O=P.firstChild;O.style.behavior="url(#default#VML)";return O?typeof O.adj=="object":true})();if(!(J||B)){G.fn.maphilight=function(){return this};return }if(J){E=function(O){return Math.max(0,Math.min(parseInt(O,16),255))};H=function(O,P){return"rgba("+E(O.substr(0,2))+","+E(O.substr(2,2))+","+E(O.substr(4,2))+","+P+")"};C=function(O){var P=G('<canvas style="width:'+O.width+"px;height:"+O.height+'px;"></canvas>').get(0);P.getContext("2d").clearRect(0,0,P.width,P.height);return P};var F=function(Q,O,R,P,S){P=P||0;S=S||0;Q.beginPath();if(O=="rect"){Q.rect(R[0]+P,R[1]+S,R[2]-R[0],R[3]-R[1])}else{if(O=="poly"){Q.moveTo(R[0]+P,R[1]+S);for(i=2;i<R.length;i+=2){Q.lineTo(R[i]+P,R[i+1]+S)}}else{if(O=="circ"){Q.arc(R[0]+P,R[1]+S,R[2],0,Math.PI*2,false)}}}Q.closePath()};K=function(Q,T,U,X,O){var S,P=Q.getContext("2d");if(X.shadow){P.save();if(X.shadowPosition=="inside"){F(P,T,U);P.clip()}var R=Q.width*100;var W=Q.height*100;F(P,T,U,R,W);P.shadowOffsetX=X.shadowX-R;P.shadowOffsetY=X.shadowY-W;P.shadowBlur=X.shadowRadius;P.shadowColor=H(X.shadowColor,X.shadowOpacity);var V=X.shadowFrom;if(!V){if(X.shadowPosition=="outside"){V="fill"}else{V="stroke"}}if(V=="stroke"){P.strokeStyle="rgba(0,0,0,1)";P.stroke()}else{if(V=="fill"){P.fillStyle="rgba(0,0,0,1)";P.fill()}}P.restore();if(X.shadowPosition=="outside"){P.save();F(P,T,U);P.globalCompositeOperation="destination-out";P.fillStyle="rgba(0,0,0,1);";P.fill();P.restore()}}P.save();F(P,T,U);if(X.fill){P.fillStyle=H(X.fillColor,X.fillOpacity);P.fill()}if(X.stroke){P.strokeStyle=H(X.strokeColor,X.strokeOpacity);P.lineWidth=X.strokeWidth;P.stroke()}P.restore();if(X.fade){G(Q).css("opacity",0).animate({opacity:1},100)}};N=function(O){O.getContext("2d").clearRect(0,0,O.width,O.height)}}else{C=function(O){return G('<var style="zoom:1;overflow:hidden;display:block;width:'+O.width+"px;height:"+O.height+'px;"></var>').get(0)};K=function(P,T,U,X,O){var V,W,R,S;for(var Q in U){U[Q]=parseInt(U[Q],10)}V='<v:fill color="#'+X.fillColor+'" opacity="'+(X.fill?X.fillOpacity:0)+'" />';W=(X.stroke?'strokeweight="'+X.strokeWidth+'" stroked="t" strokecolor="#'+X.strokeColor+'"':'stroked="f"');R='<v:stroke opacity="'+X.strokeOpacity+'"/>';if(T=="rect"){S=G('<v:rect name="'+O+'" filled="t" '+W+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+U[0]+"px;top:"+U[1]+"px;width:"+(U[2]-U[0])+"px;height:"+(U[3]-U[1])+'px;"></v:rect>')}else{if(T=="poly"){S=G('<v:shape name="'+O+'" filled="t" '+W+' coordorigin="0,0" coordsize="'+P.width+","+P.height+'" path="m '+U[0]+","+U[1]+" l "+U.join(",")+' x e" style="zoom:1;margin:0;padding:0;display:block;position:absolute;top:0px;left:0px;width:'+P.width+"px;height:"+P.height+'px;"></v:shape>')}else{if(T=="circ"){S=G('<v:oval name="'+O+'" filled="t" '+W+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+(U[0]-U[2])+"px;top:"+(U[1]-U[2])+"px;width:"+(U[2]*2)+"px;height:"+(U[2]*2)+'px;"></v:oval>')}}}S.get(0).innerHTML=V+R;G(P).append(S)};N=function(P){var O=G("<div>"+P.innerHTML+"</div>");O.children("[name=highlighted]").remove();P.innerHTML=O.html()}}M=function(P){var O,Q=P.getAttribute("coords").split(",");for(O=0;O<Q.length;O++){Q[O]=parseFloat(Q[O])}return[P.getAttribute("shape").toLowerCase().substr(0,4),Q]};L=function(Q,P){var O=G(Q);return G.extend({},P,G.metadata?O.metadata():false,O.data("maphilight"))};A=function(O){if(!O.complete){return false}if(typeof O.naturalWidth!="undefined"&&O.naturalWidth===0){return false}return true};I={position:"absolute",left:0,top:0,padding:0,border:0};var D=false;G.fn.maphilight=function(O){O=G.extend({},G.fn.maphilight.defaults,O);if(!J&&!D){G(window).ready(function(){document.namespaces.add("v","urn:schemas-microsoft-com:vml");var Q=document.createStyleSheet();var P=["shape","rect","oval","circ","fill","stroke","imagedata","group","textbox"];G.each(P,function(){Q.addRule("v\\:"+this,"behavior: url(#default#VML); antialias:true")})});D=true}return this.each(function(){var U,R,Y,Q,T,V,X,S,W;U=G(this);if(!A(this)){return window.setTimeout(function(){U.maphilight(O)},200)}Y=G.extend({},O,G.metadata?U.metadata():false,U.data("maphilight"));W=U.get(0).getAttribute("usemap");if(!W){return }Q=G('map[name="'+W.substr(1)+'"]');if(!(U.is('img,input[type="image"]')&&W&&Q.size()>0)){return }if(U.hasClass("maphilighted")){var P=U.parent();U.insertBefore(P);P.remove();G(Q).unbind(".maphilight").find("area[coords]").unbind(".maphilight")}R=G("<div></div>").css({display:"block",background:'url("'+this.src+'")',position:"relative",padding:0,width:this.width,height:this.height});if(Y.wrapClass){if(Y.wrapClass===true){R.addClass(G(this).attr("class"))}else{R.addClass(Y.wrapClass)}}U.before(R).css("opacity",0).css(I).remove();if(B){U.css("filter","Alpha(opacity=0)")}R.append(U);T=C(this);G(T).css(I);T.height=this.height;T.width=this.width;X=function(c){var a,b;b=L(this,Y);if(!b.neverOn&&!b.alwaysOn){a=M(this);K(T,a[0],a[1],b,"highlighted");if(b.groupBy){var Z;if(/^[a-zA-Z][\-a-zA-Z]+$/.test(b.groupBy)){Z=Q.find("area["+b.groupBy+'="'+G(this).attr(b.groupBy)+'"]')}else{Z=Q.find(b.groupBy)}var d=this;Z.each(function(){if(this!=d){var f=L(this,Y);if(!f.neverOn&&!f.alwaysOn){var e=M(this);K(T,e[0],e[1],f,"highlighted")}}})}if(!J){G(T).append("<v:rect></v:rect>")}}};G(Q).bind("alwaysOn.maphilight",function(){if(V){N(V)}if(!J){G(T).empty()}G(Q).find("area[coords]").each(function(){var Z,a;a=L(this,Y);if(a.alwaysOn){if(!V&&J){V=C(U[0]);G(V).css(I);V.width=U[0].width;V.height=U[0].height;U.before(V)}a.fade=a.alwaysOnFade;Z=M(this);if(J){K(V,Z[0],Z[1],a,"")}else{K(T,Z[0],Z[1],a,"")}}})});G(Q).trigger("alwaysOn.maphilight").find("area[coords]").bind("mouseover.maphilight",X).bind("mouseout.maphilight",function(Z){N(T)});U.before(T);U.addClass("maphilighted")})};G.fn.maphilight.defaults={fill:true,fillColor:"000000",fillOpacity:0.2,stroke:true,strokeColor:"ff0000",strokeOpacity:1,strokeWidth:1,fade:true,alwaysOn:false,neverOn:false,groupBy:false,wrapClass:true,shadow:false,shadowX:0,shadowY:0,shadowRadius:6,shadowColor:"000000",shadowOpacity:0.8,shadowPosition:"outside",shadowFrom:false}})(jQuery); \ No newline at end of file diff --git a/src/main/webapp/static/js/jquery/openolat/jquery.paint.js b/src/main/webapp/static/js/jquery/openolat/jquery.paint.js index 9f5f9048e6f80145145611a17437eda87998bcde..9a9e1b8ecf3412db0123a86148359367690633fd 100644 --- a/src/main/webapp/static/js/jquery/openolat/jquery.paint.js +++ b/src/main/webapp/static/js/jquery/openolat/jquery.paint.js @@ -116,8 +116,8 @@ }; /* Drawing on Paint App */ - tmp_ctx.lineWidth = document.getElementById("width_range").value; - //tmp_ctx.lineWidth = 5; + //tmp_ctx.lineWidth = document.getElementById("width_range").value; + tmp_ctx.lineWidth = 10; tmp_ctx.lineJoin = 'round'; tmp_ctx.lineCap = 'round'; tmp_ctx.strokeStyle = 'blue'; @@ -193,47 +193,27 @@ undo_arr.push(image); undo_count = 0; //NEWTHING } - - /* - document.getElementById("undo").addEventListener("click", function(){ - if( undo_arr.length > 1 ) { - if ( undo_count + 1 < undo_arr.length ) { - if ( undo_count + 2 == undo_arr.length ) { - if (confirm("Do you really want to UNDO ??? WARNING ! You will not be able to REDO this step ")) { - undo_count++; - UndoFunc(undo_count); - } - } else { - undo_count++; - UndoFunc(undo_count); - } - - if ( undo_count + 1 == undo_arr.length ) { - undo_count = 0; undo_arr = []; undo_arr.push(empty_canv); - } - } - //else { undo_count = 0; undo_arr = []; undo_arr.push(empty_canv); } + + jQuery("#width_range_ui").slider({ + min: 1, + max: 100, + value: 20, + change: function(event, ui) { + tmp_ctx.lineWidth = ui.value / 2; + drawBrush(); } }); - - document.getElementById("redo").addEventListener("click", function(){ - if ( undo_count > 0 ) { - undo_count--; - UndoFunc(undo_count); + jQuery("#opacity_range_ui").slider({ + min: 1, + max: 100, + value: 100, + change: function(event, ui) { + tmp_ctx.globalAlpha = ui.value / 100; + drawBrush(); } }); - */ - - jQuery("#width_range").on("input change", function() { - tmp_ctx.lineWidth = document.getElementById("width_range").value / 2; - drawBrush(); - }); + drawBrush(); - jQuery("#opacity_range").on("change", function() { - tmp_ctx.globalAlpha = document.getElementById("opacity_range").value / 100; - drawBrush(); - }); - //NEWTHING jQuery("#clear").on("click", function() { var mainWin = o_getMainWin(); @@ -270,6 +250,7 @@ $('#paintModal').on('hidden.bs.modal', function (event) { jQuery("#paintModal").remove(); }); + o_scrollToElement('#o_top'); }); var onPaintBrush = function() { diff --git a/src/main/webapp/static/js/jquery/qti/jquery.choice.js b/src/main/webapp/static/js/jquery/qti/jquery.choice.js new file mode 100644 index 0000000000000000000000000000000000000000..3919b153b030483c5313bbea7e15ee89c7ed41b3 --- /dev/null +++ b/src/main/webapp/static/js/jquery/qti/jquery.choice.js @@ -0,0 +1,50 @@ +(function ($) { + $.fn.choiceInteraction = function(options) { + var settings = $.extend({ + responseIdentifier: null, + formDispatchFieldId: null, + maxChoices: 0, + }, options ); + + try { + if(settings.maxChoices > 0) { + choice(this, settings); + updateDisabledStates(settings); + } + } catch(e) { + if(window.console) console.log(e); + } + return this; + }; + + function choice($obj, settings) { + var choices = jQuery('#qti_container_' + settings.responseIdentifier + " input[type=checkbox]"); + choices.on('click', function(index, el) { + updateDisabledStates(settings); + }); + }; + + function updateDisabledStates(settings) { + var choices = jQuery('#qti_container_' + settings.responseIdentifier + " input[type=checkbox]"); + var numChecked = 0; + choices.each(function(index, inputElement) { + if (inputElement.checked) { + numChecked++; + } + }); + + if(numChecked >= settings.maxChoices) { + choices.each(function(index, inputElement) { + if (inputElement.checked) { + inputElement.disabled = false; + } else { + inputElement.disabled = true; + } + }); + } else { + choices.each(function(index, inputElement) { + inputElement.disabled = false; + }); + } + } +}( jQuery )); \ No newline at end of file diff --git a/src/main/webapp/static/js/jquery/qti/jquery.hotspot.responsive.js b/src/main/webapp/static/js/jquery/qti/jquery.hotspot.responsive.js new file mode 100644 index 0000000000000000000000000000000000000000..44a97f49c65197f5e43d5a71586ebd369bbaa125 --- /dev/null +++ b/src/main/webapp/static/js/jquery/qti/jquery.hotspot.responsive.js @@ -0,0 +1,77 @@ +/* +* rwdImageMaps jQuery plugin v1.6 +* +* Allows image maps to be used in a responsive design by recalculating the area coordinates to match the actual image size on load and window.resize +* +* Copyright (c) 2016 Matt Stow +* https://github.com/stowball/jQuery-rwdImageMaps +* http://mattstow.com +* Licensed under the MIT license +*/ +;(function($) { + $.fn.rwdImageMaps = function() { + var $img = this; + + var rwdImageMap = function() { + $img.each(function() { + if (typeof($(this).attr('usemap')) == 'undefined') + return; + + var that = this, + $that = $(that); + + // Since WebKit doesn't know the height until after the image has loaded, perform everything in an onload copy + $('<img />').on('load', function() { + var attrW = 'width', + attrH = 'height', + w = $that.attr(attrW), + h = $that.attr(attrH); + + if (!w || !h) { + var temp = new Image(); + temp.src = $that.attr('src'); + if (!w) + w = temp.width; + if (!h) + h = temp.height; + } + + var wPercent = $that.width()/100, + hPercent = $that.height()/100, + map = $that.attr('usemap').replace('#', ''), + c = 'coords'; + + $('map[name="' + map + '"]').find('area').each(function() { + var $this = $(this); + if (!$this.data(c)) + $this.data(c, $this.attr(c)); + + var coords = $this.data(c).split(','), + coordsPercent = new Array(coords.length); + + for (var i = 0; i < coordsPercent.length; ++i) { + if (i % 2 === 0) + coordsPercent[i] = parseInt(((coords[i]/w)*100)*wPercent); + else + coordsPercent[i] = parseInt(((coords[i]/h)*100)*hPercent); + } + $this.attr(c, coordsPercent.toString()); + }); + + $that.maphilight({ + fillColor: 'bbbbbb', + fillOpacity: 0.5, + strokeColor: '666666', + strokeOpacity: 0.8, + strokeWidth: 3, + alwaysOn: true + }); + + }).attr('src', $that.attr('src')); + }); + }; + $(window).resize(rwdImageMap).trigger('resize'); + + return this; + }; +})(jQuery); diff --git a/src/main/webapp/static/js/js.plugins.min.js b/src/main/webapp/static/js/js.plugins.min.js index 1818ed625d8e0dfdb143ec3e4710f47552d429e4..c579ab10a6e0fb8f0d00b5c1bbd4844b8a50ca15 100644 --- a/src/main/webapp/static/js/js.plugins.min.js +++ b/src/main/webapp/static/js/js.plugins.min.js @@ -5,7 +5,7 @@ * Dual licensed under the MIT or GPL Version 2 licenses. * */ -jQuery.periodic=function(l,h){if(jQuery.isFunction(l)){h=l;l={}}var c=jQuery.extend({},jQuery.periodic.defaults,{ajax_complete:j,increment:g,reset:f,cancel:i},l);c.cur_period=c.period;c.tid=false;var e="";b();return c;function b(){i();c.tid=setTimeout(function(){h.call(c);g();if(c.tid){b()}},c.cur_period)}function j(n,m){if(m==="success"&&e!==n.responseText){e=n.responseText;f()}}function g(){c.cur_period*=c.decay;if(c.cur_period<c.period){f()}else{if(c.cur_period>c.max_period){c.cur_period=c.max_period;if(c.on_max!==undefined){c.on_max.call(c)}}}}function f(){c.cur_period=c.period;b()}function i(){clearTimeout(c.tid);c.tid=null}function k(){}function a(){}function d(){}};jQuery.periodic.defaults={period:4000,max_period:1800000,decay:1.5,on_max:undefined};var Hashtable=(function(){var p="function";var n=(typeof Array.prototype.splice==p)?function(s,r){s.splice(r,1)}:function(u,t){var s,v,r;if(t===u.length-1){u.length=t}else{s=u.slice(t+1);u.length=t;for(v=0,r=s.length;v<r;++v){u[t+v]=s[v]}}};function a(t){var r;if(typeof t=="string"){return t}else{if(typeof t.hashCode==p){r=t.hashCode();return(typeof r=="string")?r:a(r)}else{if(typeof t.toString==p){return t.toString()}else{try{return String(t)}catch(s){return Object.prototype.toString.call(t)}}}}}function g(r,s){return r.equals(s)}function e(r,s){return(typeof s.equals==p)?s.equals(r):(r===s)}function c(r){return function(s){if(s===null){throw new Error("null is not a valid "+r)}else{if(typeof s=="undefined"){throw new Error(r+" must not be undefined")}}}}var q=c("key"),l=c("value");function d(u,s,t,r){this[0]=u;this.entries=[];this.addEntry(s,t);if(r!==null){this.getEqualityFunction=function(){return r}}}var h=0,j=1,f=2;function o(r){return function(t){var s=this.entries.length,v,u=this.getEqualityFunction(t);while(s--){v=this.entries[s];if(u(t,v[0])){switch(r){case h:return true;case j:return v;case f:return[s,v[1]]}}}return false}}function k(r){return function(u){var v=u.length;for(var t=0,s=this.entries.length;t<s;++t){u[v+t]=this.entries[t][r]}}}d.prototype={getEqualityFunction:function(r){return(typeof r.equals==p)?g:e},getEntryForKey:o(j),getEntryAndIndexForKey:o(f),removeEntryForKey:function(s){var r=this.getEntryAndIndexForKey(s);if(r){n(this.entries,r[0]);return r[1]}return null},addEntry:function(r,s){this.entries[this.entries.length]=[r,s]},keys:k(0),values:k(1),getEntries:function(s){var u=s.length;for(var t=0,r=this.entries.length;t<r;++t){s[u+t]=this.entries[t].slice(0)}},containsKey:o(h),containsValue:function(s){var r=this.entries.length;while(r--){if(s===this.entries[r][1]){return true}}return false}};function m(s,t){var r=s.length,u;while(r--){u=s[r];if(t===u[0]){return r}}return null}function i(r,s){var t=r[s];return(t&&(t instanceof d))?t:null}function b(t,r){var w=this;var v=[];var u={};var x=(typeof t==p)?t:a;var s=(typeof r==p)?r:null;this.put=function(B,C){q(B);l(C);var D=x(B),E,A,z=null;E=i(u,D);if(E){A=E.getEntryForKey(B);if(A){z=A[1];A[1]=C}else{E.addEntry(B,C)}}else{E=new d(D,B,C,s);v[v.length]=E;u[D]=E}return z};this.get=function(A){q(A);var B=x(A);var C=i(u,B);if(C){var z=C.getEntryForKey(A);if(z){return z[1]}}return null};this.containsKey=function(A){q(A);var z=x(A);var B=i(u,z);return B?B.containsKey(A):false};this.containsValue=function(A){l(A);var z=v.length;while(z--){if(v[z].containsValue(A)){return true}}return false};this.clear=function(){v.length=0;u={}};this.isEmpty=function(){return !v.length};var y=function(z){return function(){var A=[],B=v.length;while(B--){v[B][z](A)}return A}};this.keys=y("keys");this.values=y("values");this.entries=y("getEntries");this.remove=function(B){q(B);var C=x(B),z,A=null;var D=i(u,C);if(D){A=D.removeEntryForKey(B);if(A!==null){if(!D.entries.length){z=m(v,C);n(v,z);delete u[C]}}}return A};this.size=function(){var A=0,z=v.length;while(z--){A+=v[z].entries.length}return A};this.each=function(C){var z=w.entries(),A=z.length,B;while(A--){B=z[A];C(B[0],B[1])}};this.putAll=function(H,C){var B=H.entries();var E,F,D,z,A=B.length;var G=(typeof C==p);while(A--){E=B[A];F=E[0];D=E[1];if(G&&(z=w.get(F))){D=C(F,z,D)}w.put(F,D)}};this.clone=function(){var z=new b(t,r);z.putAll(w);return z}}return b})();(function(b){b.fn.ooLog=function(f,d,e){var c=null;b(this).each(function(){c=b(this).data("_ooLog");if(c==undefined){c=new a();b(this).data("_ooLog",c)}});if(f==undefined){return c}else{if(typeof f==="string"){if(c){c.log(f,d,e)}}}};function a(){return this}a.prototype={isDebugEnabled:function(){return o_info.JSTracingLogDebugEnabled},log:function(e,c,d){if(!this.isDebugEnabled()){return}jQuery.post(o_info.JSTracingUri,{level:e,logMsg:c,jsFile:d})}}})(jQuery);(function(b){b.fn.ooTranslator=function(){var d=null;b(document).each(function(){d=b(document).data("_ooTranslator");if(d==undefined){d=new a();b(document).data("_ooTranslator",d)}});return d};function a(){return this}a.prototype={mapperUrl:null,translators:null,initialize:function(d){this.mapperUrl=d;this.translators=new Object()},getTranslator:function(d,f){if(this.translators[d]==null){this.translators[d]=new Object()}if(this.translators[d][f]==null){var e=this.mapperUrl+"/"+d+"/"+f+"/translations.js";jQuery.ajax(e,{async:false,dataType:"json",success:function(g,i,h){jQuery(document).ooTranslator()._createTranslator(g,d,f)}})}return this.translators[d][f]},_createTranslator:function(e,d,f){this.translators[d][f]=new c().initialize(e,d,f)}};function c(){return this}c.prototype={localizationData:null,bundle:null,locale:null,initialize:function(f,d,e){this.bundle=e;this.locale=d;this.localizationData=f;return this},translate:function(d){if(this.localizationData[d]){return this.localizationData[d]}else{return this.bundle+":"+d}}}})(jQuery);+function(b){var a=function(){this.addExtraElements();this.state={busy:false,brandW:0,sitesW:0,sitesDirty:false,sites:{collapsed:this.isSitesCollapsed(),extended:this.isSitesExtended},tabsW:0,tabsDirty:false,tabs:{collapsed:this.isTabsCollapsed(),extended:this.isTabsExtended()},toolsW:0,toolsDirty:false,tools:{collapsed:this.isToolsCollapsed(),extended:this.isToolsExtended()},offCanvasWidth:0,moreW:0};var c=b("#o_offcanvas_right").css("width");if(c){this.state.offCanvasWidth=parseInt(c.replace(/[^\d.]/g,""));this.initListners();this.calculateWidth();this.optimize()}};a.prototype.initListners=function(){b(window).resize(b.proxy(this.onResizeCallback,this));b(document).on("oo.nav.sites.modified",b.proxy(function(){this.state.sitesDirty=true},this));b(document).on("oo.nav.tabs.modified",b.proxy(function(){this.state.tabsDirty=true},this));b(document).on("oo.nav.tools.modified",b.proxy(function(){this.state.toolsDirty=true},this));b(document).on("oo.dom.replacement.after",b.proxy(this.onDOMreplacementCallback,this));b(window).on("orientationchange",b.proxy(this.hideRight,this));b("#o_navbar_right-toggle").on("click",b.proxy(this.toggleRight,this));b("#o_offcanvas_right .o_offcanvas_close").on("click",b.proxy(this.hideRight,this));b("#o_navbar_more").on("shown.bs.dropdown",this.onDropdownShown);b("#o_navbar_more").on("hidden.bs.dropdown",this.onDropdownHidden)};a.prototype.onResizeCallback=function(){if(!this.state.busy){this.state.busy=true;this.calculateWidth();this.optimize();this.state.busy=false}};a.prototype.onDOMreplacementCallback=function(){if(!this.state.busy&&(this.state.sitesDirty||this.state.tabsDirty||this.state.toolsDirty)){this.state.busy=true;this.cleanupMoreDropdown();this.calculateWidth();this.optimize();this.state.sitesDirty=false;this.state.tabsDirty=false;this.state.toolsDirty=false;this.state.busy=false}};a.prototype.onDropdownShown=function(c){var f=b("#o_navbar_more .dropdown-menu");if(f.length){var d=f.offset().left;if(d<0){f.removeClass("dropdown-menu-right")}}};a.prototype.onDropdownHidden=function(c){var d=b("#o_navbar_more .dropdown-menu");d.addClass("dropdown-menu-right")};a.prototype.calculateWidth=function(){var c=b("#o_navbar_container .o_navbar-collapse");this.state.navbarW=c.innerWidth();this.state.brandW=b(".o_navbar-brand").outerWidth(true);this.state.sitesW=this.getSites().outerWidth(true);this.state.tabsW=this.getTabs().outerWidth(true);this.state.toolsW=this.getTools().outerWidth(false);this.state.moreW=b("#o_navbar_more:visible").outerWidth(true)};a.prototype.getOverflow=function(c){var d=this.state.navbarW;d-=this.state.sitesW;d-=this.state.tabsW;d-=this.state.toolsW;d-=this.state.brandW;d-=this.state.moreW;d-=25;return -d};a.prototype.optimize=function(h){var c=this.getOverflow();var k=this.getSites();var l=this.getTabs();var g=this.getTools();var n=this.getMoreDropdown();var f=this.getOffcanvasRight();this.updateState();while(c>0&&(!this.state.tabs.collapsed||!this.state.sites.collapsed||!this.state.tools.collapsed)){if(!this.state.tabs.collapsed){this.collapse(l,n,"li","o_dropdown_tab")}else{if(!this.state.sites.collapsed){this.collapse(k,n,"li","o_dropdown_site")}else{if(!this.state.tools.collapsed){this.collapse(g,f,".o_navbar_tool:not(#o_navbar_imclient, #o_navbar_search_opener, #o_navbar_my_menu)","o_tool_right")}}}this.calculateWidth();c=this.getOverflow();this.updateState()}while(c<0&&(!this.state.tabs.extended||!this.state.sites.extended||!this.state.tools.extended)){if(!this.state.tools.extended){var m=this.extend(f,g.children("#o_navbar_imclient, #o_navbar_search_opener, #o_navbar_my_menu").first(),".o_tool_right","o_tool_right",true);if(!m){break}}if(!this.state.sites.extended){var j=this.extend(n,k,"li","o_dropdown_site");if(!j){break}}else{if(!this.state.tabs.extended){var d=this.extend(n,l,"li","o_dropdown_tab");if(!d){break}}}this.calculateWidth();c=this.getOverflow();this.updateState()}if(this.state.sites.extended&&this.state.tabs.extended){var i=b("#o_navbar_more");i.css("display","none")}this.checkToolsOrder()};a.prototype.updateState=function(){this.state.sites.collapsed=this.isSitesCollapsed();this.state.sites.extended=this.isSitesExtended();this.state.tabs.collapsed=this.isTabsCollapsed();this.state.tabs.extended=this.isTabsExtended();this.state.tools.collapsed=this.isToolsCollapsed();this.state.tools.extended=this.isToolsExtended()};a.prototype.collapse=function(g,d,c,f){var e=g.find(c);if(e.length){e=e.last()}if(e.length){f&&e.addClass(f);if(d){e.prependTo(d)}}this.updateDropdownToggle(g)};a.prototype.extend=function(g,d,c,i,f){var e=g.find(c);if(e.length){e=e.first()}var j=false;if(e.length){if(d&&d.length){if(f){d.before(e)}else{e.appendTo(d)}this.updateDropdownToggle(g);this.calculateWidth();var h=this.getOverflow();if(h>0){e.prependTo(g)}else{i&&e.removeClass(i);j=true}}}this.updateDropdownToggle(g);return j};a.prototype.updateDropdownToggle=function(c){var d=c.parents(".o_dropdown_toggle");if(!d.length){return}if(c.children().length){d.css("display","block")}else{d.css("display","none")}};a.prototype.addExtraElements=function(){var d=b("#o_navbar_container .o_navbar-collapse");var c=b("#o_navbar_more");if(c.length==0){c=b('<ul id="o_navbar_more" class="nav o_navbar-nav o_dropdown_toggle"><li><a class="dropdown-toggle" data-toggle="dropdown" href="#"">'+o_info.i18n_topnav_more+' <b class="caret"></b></a><ul class="dropdown-menu dropdown-menu-right"></ul></li></ul>');c.appendTo(d)}this.getSites().append('<li class="divider o_dropdown_site"></li>');b("#o_navbar_help .o_icon, #o_navbar_print .o_icon").addClass("o_icon-fw")};a.prototype.cleanupMoreDropdown=function(){if(!this.state.sitesDirty){var f=this.getSites();var d=this.getMoreDropdown().children(".o_dropdown_site");d.appendTo(f)}else{this.getSites().append('<li class="divider o_dropdown_site"></li>')}if(!this.state.tabsDirty){var e=this.getTabs();var c=this.getMoreDropdown().children(".o_dropdown_tab");c.prependTo(e)}this.getMoreDropdown().empty()};a.prototype.checkToolsOrder=function(){var f=this.getTools();var e=f.find("#o_navbar_help");var d=f.find("#o_navbar_print");var c=f.find("#o_navbar_imclient");if(c&&d){c.after(d)}if(c&&e){c.after(e)}};a.prototype.showRight=function(){if(!this.isOffcanvasVisible()&&!this.offcanvasTransitioning){this.offcanvasTransitioning=true;var d=this;var c=b("#o_offcanvas_right");c.show().transition({x:-d.state.offCanvasWidth},function(){b("body").addClass("o_offcanvas_right_visible");var e=b.proxy(d.hideRightOnClick,d);setTimeout(function(){b("html").on("click",e);d.offcanvasTransitioning=false},10)})}};a.prototype.hideRightOnClick=function(c){if("INPUT"!=c.target.nodeName){this.hideRight()}};a.prototype.hideRight=function(){if(this.isOffcanvasVisible()&&!this.offcanvasTransitioning){this.offcanvasTransitioning=true;b("html").off("click",b.proxy(this.hideRight,this));var d=this;var c=b("#o_offcanvas_right");c.transition({x:d.state.offCanvasWidth},function(){c.hide();b("body").removeClass("o_offcanvas_right_visible");d.offcanvasTransitioning=false})}};a.prototype.toggleRight=function(){if(this.isOffcanvasVisible()){this.hideRight()}else{this.showRight()}};a.prototype.isOffcanvasVisible=function(){return b("#o_offcanvas_right:visible").length};a.prototype.getSites=function(){return b("#o_navbar_container .o_navbar_sites")};a.prototype.getTabs=function(){return b("#o_navbar_container .o_navbar_tabs")};a.prototype.getTools=function(){return b("#o_navbar_container #o_navbar_tools_permanent")};a.prototype.getMoreDropdown=function(){return b("#o_navbar_more .dropdown-menu")};a.prototype.getOffcanvasRight=function(){return b("#o_offcanvas_right_container .o_navbar-right")};a.prototype.isSitesCollapsed=function(){return !this.getSites().children("li").not(".divider").length};a.prototype.isSitesExtended=function(){return !this.getMoreDropdown().children(".o_dropdown_site").not(".divider").length};a.prototype.isTabsCollapsed=function(){return !this.getTabs().children("li").length};a.prototype.isTabsExtended=function(){return !this.getMoreDropdown().children(".o_dropdown_tab").length};a.prototype.isToolsCollapsed=function(){return !this.getTools().children(".o_navbar_tool").not("#o_navbar_imclient, #o_navbar_search_opener, #o_navbar_my_menu").length};a.prototype.isToolsExtended=function(){return !this.getOffcanvasRight().children(".o_tool_right").length};b(document).ready(function(){var d=b("#o_navbar_wrapper");if(d){var c=new a();window.OPOL.navbar=c}})}(jQuery);+function(b){b.fn.ooBgCarrousel=function(){return new a()};var a=function(){};a.prototype.initCarrousel=function(g){this.settings=b.extend({query:null,images:[],shuffle:false,shuffleFirst:false,durationshow:5000,durationout:500,durationin:500,easeout:"ease",easein:"ease"},g);this.pos=null;if(this.settings.query==null||this.settings.images.length==0){return}this.initialImage=this.settings.images[0];if(this.settings.shuffle){var f=this.settings.images;for(var d,c,e=f.length;e;d=parseInt(Math.random()*e),c=f[--e],f[e]=f[d],f[d]=c){}}if(this.settings.shuffleFirst){this._replaceImage()}this.rotate()};a.prototype.rotate=function(){setTimeout(b.proxy(this._hideCurrent,this),this.settings.durationshow)};a.prototype._hideCurrent=function(){var c=b(this.settings.query);if(c&&c.size()>0){c.transition({opacity:0,duration:this.settings.durationout,easing:this.settings.easeout},b.proxy(this._showNext,this))}};a.prototype._replaceImage=function(d){if(!d){d=b(this.settings.query)}if(d&&d.size()>0){this.newImg="";this.oldImg="";if(this.pos==null){this.pos=1;this.oldImg=this.initialImage}else{this.oldImg=this.settings.images[this.pos];this.pos++;if(this.settings.images.length==this.pos){this.pos=0}}this.newImg=this.settings.images[this.pos];var c=d.css("background-image");if(c.indexOf(this.oldImg)==-1){d.transition({opacity:1,duration:0});return}var e=c.replace(this.oldImg,this.newImg);d.css("background-image",e)}};a.prototype._showNext=function(){var c=b(this.settings.query);this._replaceImage(c);c.transition({opacity:1,duration:this.settings.durationin,easing:this.settings.easein},b.proxy(this.rotate,this))}}(jQuery);!function(e){function t(){function t(e){"remove"===e&&this.each(function(e,t){var n=i(t);n&&n.remove()}),this.find("span.mceEditor,div.mceEditor").each(function(e,t){var n=tinymce.get(t.id.replace(/_parent$/,""));n&&n.remove()})}function r(e){var n,r=this;if(null!=e)t.call(r),r.each(function(t,n){var r;(r=tinymce.get(n.id))&&r.setContent(e)});else if(r.length>0&&(n=tinymce.get(r[0].id)))return n.getContent()}function i(e){var t=null;return e&&e.id&&a.tinymce&&(t=tinymce.get(e.id)),t}function o(e){return!!(e&&e.length&&a.tinymce&&e.is(":tinymce"))}var s={};e.each(["text","html","val"],function(t,a){var l=s[a]=e.fn[a],c="text"===a;e.fn[a]=function(t){var a=this;if(!o(a))return l.apply(a,arguments);if(t!==n)return r.call(a.filter(":tinymce"),t),l.apply(a.not(":tinymce"),arguments),a;var s="",u=arguments;return(c?a:a.eq(0)).each(function(t,n){var r=i(n);s+=r?c?r.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):r.getContent({save:!0}):l.apply(e(n),u)}),s}}),e.each(["append","prepend"],function(t,r){var a=s[r]=e.fn[r],l="prepend"===r;e.fn[r]=function(e){var t=this;return o(t)?e!==n?("string"==typeof e&&t.filter(":tinymce").each(function(t,n){var r=i(n);r&&r.setContent(l?e+r.getContent():r.getContent()+e)}),a.apply(t.not(":tinymce"),arguments),t):void 0:a.apply(t,arguments)}}),e.each(["remove","replaceWith","replaceAll","empty"],function(n,r){var i=s[r]=e.fn[r];e.fn[r]=function(){return t.call(this,r),i.apply(this,arguments)}}),s.attr=e.fn.attr,e.fn.attr=function(t,a){var l=this,c=arguments;if(!t||"value"!==t||!o(l))return a!==n?s.attr.apply(l,c):s.attr.apply(l,c);if(a!==n)return r.call(l.filter(":tinymce"),a),s.attr.apply(l.not(":tinymce"),c),l;var u=l[0],d=i(u);return d?d.getContent({save:!0}):s.attr.apply(e(u),c)}}var n,r,i,o=[],a=window;e.fn.tinymce=function(n){function s(){var r=[],o=0;i||(t(),i=!0),d.each(function(e,t){var i,a=t.id,s=n.oninit;a||(t.id=a=tinymce.DOM.uniqueId()),tinymce.get(a)||(i=new tinymce.Editor(a,n,tinymce.EditorManager),r.push(i),i.on("init",function(){var e,t=s;d.css("visibility",""),s&&++o==r.length&&("string"==typeof t&&(e=t.indexOf(".")===-1?null:tinymce.resolve(t.replace(/\.\w+$/,"")),t=tinymce.resolve(t)),t.apply(e||tinymce,r))}))}),e.each(r,function(e,t){t.render()})}var l,c,u,d=this,f="";if(!d.length)return d;if(!n)return window.tinymce?tinymce.get(d[0].id):null;if(d.css("visibility","hidden"),a.tinymce||r||!(l=n.script_url))1===r?o.push(s):s();else{r=1,c=l.substring(0,l.lastIndexOf("/")),l.indexOf(".min")!=-1&&(f=".min"),a.tinymce=a.tinyMCEPreInit||{base:c,suffix:f},l.indexOf("gzip")!=-1&&(u=n.language||"en",l=l+(/\?/.test(l)?"&":"?")+"js=true&core=true&suffix="+escape(f)+"&themes="+escape(n.theme||"modern")+"&plugins="+escape(n.plugins||"")+"&languages="+(u||""),a.tinyMCE_GZ||(a.tinyMCE_GZ={start:function(){function t(e){tinymce.ScriptLoader.markDone(tinymce.baseURI.toAbsolute(e))}t("langs/"+u+".js"),t("themes/"+n.theme+"/theme"+f+".js"),t("themes/"+n.theme+"/langs/"+u+".js"),e.each(n.plugins.split(","),function(e,n){n&&(t("plugins/"+n+"/plugin"+f+".js"),t("plugins/"+n+"/langs/"+u+".js"))})},end:function(){}}));var p=document.createElement("script");p.type="text/javascript",p.onload=p.onreadystatechange=function(t){t=t||window.event,2===r||"load"!=t.type&&!/complete|loaded/.test(p.readyState)||(tinymce.dom.Event.domLoaded=1,r=2,n.script_loaded&&n.script_loaded(),s(),e.each(o,function(e,t){t()}))},p.src=l,document.body.appendChild(p)}return d},e.extend(e.expr[":"],{tinymce:function(e){var t;return!!(e.id&&"tinymce"in window&&(t=tinymce.get(e.id),t&&t.editorManager===tinymce))}})}(jQuery);OPOL={};var o2c=0;var o3c=new Array();o_info.guibusy=false;o_info.linkbusy=false;o_info.scrolling=false;o_info.debug=true;var BLoader={_ajaxLoadedJS:new Array(),_isAlreadyLoadedJS:function(b){var a=true;jQuery("head script[src]").each(function(d,c){if(jQuery(c).attr("src").indexOf(b)!=-1){a=false}});if(jQuery.inArray(b,this._ajaxLoadedJS)!=-1){a=false}return !a},loadJS:function(b,c,a){if(!this._isAlreadyLoadedJS(b)){if(o_info.debug){o_log("BLoader::loadJS: loading ajax::"+a+" url::"+b)}if(a){jQuery.ajax(b,{async:false,dataType:"script",cache:true,success:function(d,f,e){}});this._ajaxLoadedJS.push(b)}else{jQuery.getScript(b)}if(o_info.debug){o_log("BLoader::loadJS: loading DONE url::"+b)}}else{if(o_info.debug){o_log("BLoader::loadJS: already loaded url::"+b)}}},executeGlobalJS:function(jsString,contextDesc){try{if(window.execScript){window.execScript(jsString)}else{window.eval(jsString)}}catch(e){if(window.console){console.log(contextDesc,"cannot execute js",jsString)}if(o_info.debug){o_logerr("BLoader::executeGlobalJS: Error when executing JS code in contextDesc::"+contextDesc+' error::"'+showerror(e)+" for: "+escape(jsString))}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::executeGlobalJS: Error when executing JS code in contextDesc::"+contextDesc+' error::"'+showerror(e)+" for: "+escape(jsString),"functions.js::BLoader::executeGlobalJS::"+contextDesc)}if(window.location.href.indexOf("o_winrndo")!=-1){window.location.reload()}else{window.location.href=window.location.href+(window.location.href.indexOf("?")!=-1?"&":"?")+"o_winrndo=1"}}},loadCSS:function(b,o,q){var r=window.document;try{if(r.createStyleSheet){var j=r.styleSheets;var d=0;var p=0;for(i=0;i<j.length;i++){var m=j[i];var g=m.href;if(g==b){d++;if(m.disabled){m.disabled=false;return}else{if(o_info.debug){o_logwarn("BLoader::loadCSS: style: "+b+" already in document and not disabled! (duplicate add)")}return}}if(m.id=="o_theme_css"){p=i}}if(d>1&&o_info.debug){o_logwarn("BLoader::loadCSS: apply styles: num of stylesheets found was not 0 or 1:"+d)}if(q){p=j.length}var f=r.createStyleSheet(b,p)}else{var c=jQuery("#"+o);if(c&&c.size()>0){if(o_info.debug){o_logwarn("BLoader::loadCSS: stylesheet already found in doc when trying to add:"+b+", with id "+o)}return}else{var a=jQuery('<link id="'+o+'" rel="stylesheet" type="text/css" href="'+b+'">');if(q){a.insertBefore(jQuery("#o_fontSize_css"))}else{a.insertBefore(jQuery("#o_theme_css"))}}}}catch(n){if(window.console){console.log(n)}if(o_info.debug){o_logerr("BLoader::loadCSS: Error when loading CSS from URL::"+b)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::loadCSS: Error when loading CSS from URL::"+b,"functions.js::BLoader::loadCSS")}}},unLoadCSS:function(a,m){var n=window.document;try{if(n.createStyleSheet){var f=n.styleSheets;var d=0;var o=a;var b=window.location.href.substring(0,window.location.href.indexOf("/",8));if(a.indexOf(b)==0){o=a.substring(b.length)}for(i=0;i<f.length;i++){var g=f[i].href;if(g==a||g==o){d++;if(!f[i].disabled){f[i].disabled=true}else{if(o_info.debug){o_logwarn("stylesheet: when removing: matching url, but already disabled! url:"+g)}}}}if(d!=1&&o_info.debug){o_logwarn("stylesheet: when removeing: num of stylesheets found was not 1:"+d)}}else{var c=jQuery("#"+m);if(c){c.href="";c.remove();c=null;return}else{if(o_info.debug){o_logwarn("no link with id found to remove, id:"+m+", url "+a)}}}}catch(j){if(o_info.debug){o_logerr("BLoader::unLoadCSS: Error when unloading CSS from URL::"+a)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::unLoadCSS: Error when unloading CSS from URL::"+a,"functions.js::BLoader::loadCSS")}}}};var BFormatter={formatLatexFormulas:function(b){try{if(typeof MathJax==="undefined"){o_mathjax()}else{if(MathJax&&MathJax.isReady){jQuery(function(){MathJax.Hub.Queue(function(){if(jQuery("#"+b+" .MathJax").length==0){MathJax.Hub.Typeset(b)}})})}else{setTimeout(function(){BFormatter.formatLatexFormulas(b)},100)}}}catch(a){if(window.console){console.log("error in BFormatter.formatLatexFormulas: ",a)}}}};function o_init(){try{o_getMainWin().o_afterserver();if(window.location.href&&window.location.href!=null&&window.location.href.indexOf("%3A")<0){var a=window.location.href;if(a!=null&&!(a.lastIndexOf("http",0)===0)&&!(a.lastIndexOf("https",0)===0)){a=o_info.serverUri+a}o_info.businessPath=a;if(!(typeof o_shareActiveSocialUrl==="undefined")){o_shareActiveSocialUrl()}}}catch(b){if(o_info.debug){o_log("error in o_init: "+showerror(b))}}}function o_initEmPxFactor(){o_info.emPxFactor=jQuery("#o_width_1em").width();if(o_info.emPxFactor==0||o_info.emPxFactor=="undefined"){o_info.emPxFactor=12;if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Could not read with of element b_width_1em, set o_info.emPxFactor to 12","functions.js")}}}function o_getMainWin(){try{if(window.OPOL){return window}else{if(window.opener&&window.opener.OPOL){return window.opener}}}catch(a){if(o_info.debug){o_logerr('Exception while getting main window. rror::"'+showerror(a))}if(window.console){console.log('Exception while getting main window. rror::"'+showerror(a),"functions.js");console.log(a)}}throw"Can not find main OpenOLAT window"}function o_beforeserver(){o_info.linkbusy=true;showAjaxBusy();if(window.suppressOlatOnUnloadOnce){window.suppressOlatOnUnloadOnce=false}else{if(window.olatonunload){olatonunload()}}}function o_afterserver(){o2c=0;o_info.linkbusy=false;removeAjaxBusy()}function o2cl(){try{if(o_info.linkbusy){return false}else{var b=(o2c==0||confirm(o_info.dirty_form));if(b){o_beforeserver()}return b}}catch(a){if(window.console){console.log(a)}return false}}function o2cl_dirtyCheckOnly(){try{if(o_info.linkbusy){return false}else{return(o2c==0||confirm(o_info.dirty_form))}}catch(a){if(window.console){console.log(a)}return false}}function o2cl_noDirtyCheck(){if(o_info.linkbusy){return false}else{o_beforeserver();return true}}function o3cl(d){if(o_info.linkbusy){return false}else{var b=o3c1.indexOf(d)>-1;var a=(b&&o3c1.length>1)||o3c1.length>0;var c=(!a||confirm(o_info.dirty_form));if(c){o_beforeserver()}return c}}function o_onc(a){var b=a.responseText;BLoader.executeGlobalJS("o_info.last_o_onc="+b+";","o_onc");o_ainvoke(o_info.last_o_onc,false)}function o_allowNextClick(){o_info.linkbusy=false;removeAjaxBusy()}function removeBusyAfterDownload(c,b,a){o2c=0;o_afterserver()}Array.prototype.search=function(c,d){var a=this.length;for(var b=0;b<a;b++){if(this[b].constructor==Array){if(this[b].search(c,d)){return true;break}}else{if(d){if(this[b].indexOf(c)!=-1){return true;break}}else{if(this[b]==c){return true;break}}}}return false};if(!Function.prototype.curry){Function.prototype.curry=function(){if(arguments.length<1){return this}var a=this;var b=Array.prototype.slice.call(arguments);return function(){return a.apply(this,b.concat(Array.prototype.slice.call(arguments)))}}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(c){if(this==null){throw new TypeError()}var d=Object(this);var a=d.length>>>0;if(a===0){return -1}var e=0;if(arguments.length>1){e=Number(arguments[1]);if(e!=e){e=0}else{if(e!=0&&e!=Infinity&&e!=-Infinity){e=(e>0||-1)*Math.floor(Math.abs(e))}}}if(e>=a){return -1}var b=e>=0?e:Math.max(a-Math.abs(e),0);for(;b<a;b++){if(b in d&&d[b]===c){return b}}return -1}}var b_onDomReplacementFinished_callbacks=new Array();function b_AddOnDomReplacementFinishedCallback(a){var b=jQuery(document).ooLog().isDebugEnabled();if(b){jQuery(document).ooLog("debug","callback stack size: "+b_onDomReplacementFinished_callbacks.length,"functions.js ADD")}if(b&&b_onDomReplacementFinished_callbacks.toSource){jQuery(document).ooLog("debug","stack content"+b_onDomReplacementFinished_callbacks.toSource(),"functions.js ADD")}b_onDomReplacementFinished_callbacks.push(a);if(b){jQuery(document).ooLog("debug","push to callback stack, func: "+a,"functions.js ADD")}}var b_changedDomEl=new Array();function b_AddOnDomReplacementFinishedUniqueCallback(a){if(a.constructor==Array){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","add: its an ARRAY! ","functions.js ADD")}if(b_onDomReplacementFinished_callbacks.search(a[0])){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","push to callback stack, already there!!: "+a[0],"functions.js ADD")}return}}b_AddOnDomReplacementFinishedCallback(a)}var o_debug_trid=0;function o_ainvoke(N){if(N==undefined){return}o_info.inainvoke=true;var I=N.cmdcnt;if(I>0){jQuery(document).trigger("oo.dom.replacement.before");b_changedDomEl=new Array();if(o_info.debug){o_debug_trid++}var y=N.cmds;for(var T=0;T<I;T++){var J=y[T];var A=J.cmd;var R=J.cda;var U=J.w;var c=this.window;var K;if(c){switch(A){case 1:var M=R.e;BLoader.executeGlobalJS(M,"o_ainvoker::jsexec");if(o_info.debug){o_log("c1: execute jscode: "+M)}case 2:var u=R.cc;var F=R.cps;for(var Q=0;Q<u;Q++){var m=F[Q];var h=m.cid;var P=m.cidvis;var H=m.cw;var x=m.hfrag;var O=m.jsol;var g=m.hdr;if(o_info.debug){o_log("c2: redraw: "+m.cname+" ("+h+") "+m.hfragsize+" bytes, listener(s): "+m.clisteners)}var W=g+"\n\n"+x;var C="";var S=false;var E="o_c"+h;var B=jQuery("#"+E);if(B==null||B.length==0){E="o_fi"+h;B=jQuery("#"+E);S=true}if(B!=null){var w=jQuery("div.o_richtext_mce textarea",B);for(var L=0;L<w.length;L++){try{var a=jQuery(w.get(L)).attr("id");if(typeof top.tinymce!=undefined){top.tinymce.remove("#"+a)}}catch(Z){if(window.console){console.log(Z)}}}if(P){B.css("display","")}else{B.css("display","none")}if(S||!H){B.replaceWith(W)}else{try{B.empty().html(W);if(W.length>0&&B.get(0).innerHTML==""){B.get(0).innerHTML=W}}catch(Z){if(window.console){console.log(Z)}if(window.console){console.log("Fragment",W)}}b_changedDomEl.push(E)}B=null;if(C!=""){C.each(function(e){BLoader.executeGlobalJS(e,"o_ainvoker::inscripts")})}if(O!=""){BLoader.executeGlobalJS(O,"o_ainvoker::jsol")}}}break;case 3:c.o2c=0;var X=R.rurl;c.o_afterserver();c.document.location.replace(X);break;case 5:c.o2c=0;var X=R.rurl;c.o_afterserver();c.document.location.replace(X);break;case 6:c.o2c=0;c.o_afterserver();break;case 7:var o=c.document.location;var z=o.protocol+"//"+o.hostname;if(o.port!=""){z+=":"+o.port}var v=R.cssrm;for(Q=0;Q<v.length;Q++){var D=v[Q];var G=D.id;var f=z+D.url;BLoader.unLoadCSS(f,G);if(o_info.debug){o_log("c7: rm css: id:"+G+" ,url:'"+f+"'")}}var V=R.cssadd;for(k=0;k<V.length;k++){var D=V[k];var G=D.id;var f=z+D.url;var n=D.pt;BLoader.loadCSS(f,G,n);if(o_info.debug){o_log("c7: add css: id:"+G+" ,url:'"+f+"'")}}var p=R.jsadd;for(l=0;l<p.length;l++){var D=p[l];var Y=D.before;if(jQuery.type(Y)==="string"){BLoader.executeGlobalJS(Y,"o_ainvoker::preJsAdd")}var f=D.url;var q=D.enc;if(jQuery.type(f)==="string"){BLoader.loadJS(f,q,true)}if(o_info.debug){o_log("c7: add js: "+f)}}break;default:if(o_info.debug){o_log("?: unknown command "+A)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in o_ainvoke(), ?: unknown command "+A,"functions.js")}break}}else{if(o_info.debug){o_log("could not find window??")}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in o_ainvoke(), could not find window??","functions.js")}}}var b=b_onDomReplacementFinished_callbacks.length;if(b_onDomReplacementFinished_callbacks.toSource&&jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","stack content"+b_onDomReplacementFinished_callbacks.toSource(),"functions.js")}for(mycounter=0;b>mycounter;mycounter++){if(mycounter>50){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stopped executing DOM replacement callback functions - to many functions::"+b_onDomReplacementFinished_callbacks.length,"functions.js")}break}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stacksize before shift: "+b_onDomReplacementFinished_callbacks.length,"functions.js")}var s=b_onDomReplacementFinished_callbacks.shift();if(typeof s.length==="number"){if(s[0]=="glosshighlighter"){var d=s[1];if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","arr fct: "+d,"functions.js")}s=d}}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Executing DOM replacement callback function #"+mycounter+" with timeout funct::"+s,"functions.js")}s();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stacksize after timeout: "+b_onDomReplacementFinished_callbacks.length,"functions.js")}}jQuery(document).trigger("oo.dom.replacement.after")}o_info.inainvoke=false}function clearAfterAjaxIframeCall(){if(o_info.linkbusy){o_afterserver()}}function showAjaxBusy(){setTimeout(function(){if(o_info.linkbusy){try{if(jQuery("#o_ajax_busy_backdrop").length==0){jQuery("#o_body").addClass("o_ajax_busy");jQuery("#o_ajax_busy").modal({show:true,backdrop:"static",keyboard:"false"});jQuery("#o_ajax_busy").after('<div id="o_ajax_busy_backdrop" class="modal-backdrop in"></div>');jQuery("#o_ajax_busy>.modal-backdrop").remove();jQuery("#o_ajax_busy_backdrop").css({"z-index":1200})}}catch(a){if(window.console){console.log(a)}}}},700)}function removeAjaxBusy(){try{jQuery("#o_body").removeClass("o_ajax_busy");jQuery("#o_ajax_busy_backdrop").remove();jQuery("#o_ajax_busy").modal("hide")}catch(a){if(window.console){console.log(a)}}}function setFormDirty(c){o2c=1;var a=document.getElementById(c);if(a!=null){var b=a.olat_fosm_0;if(b==null){b=a.olat_fosm}if(b){b.className="btn o_button_dirty"}}else{if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in setFormDirty, myForm was null for formId="+c,"functions.js")}}}function contextHelpWindow(a){helpWindow=window.open(a,"HelpWindow","height=760, width=940, left=0, top=0, location=no, menubar=no, resizable=yes, scrollbars=yes, toolbar=no");helpWindow.focus()}function o_openPopUp(b,d,c,a,f){attributes="height="+a+", width="+c+", resizable=yes, scrollbars=yes, left=100, top=100, ";if(f){attributes+="location=yes, menubar=yes, status=yes, toolbar=yes"}else{attributes+="location=no, menubar=no, status=no, toolbar=no"}var h;try{h=window.open(b,d,attributes)}catch(g){h=window.open(b,"OpenOLAT",attributes)}h.focus();if(o_info.linkbusy){o_afterserver()}}function b_handleFileUploadFormChange(e,b,d){var f=e.value;slashPos=f.lastIndexOf("/");if(slashPos!=-1){f=f.substring(slashPos+1)}slashPos=f.lastIndexOf("\\");if(slashPos!=-1){f=f.substring(slashPos+1)}b.value=f;if(d){d.className="o_button_dirty"}var c=e.form.elements;for(i=0;i<c.length;i++){var a=c[i];if(a.name==b.name&&i+1<c.length){c[i+1].focus()}}}function gotonode(a){try{if(typeof o_activateCourseNode!="undefined"){o_activateCourseNode(a)}else{if(opener&&typeof opener.o_activateCourseNode!="undefined"){opener.o_activateCourseNode(a)}else{if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in gotonode(), could not find main window","functions.js")}}}}catch(b){alert("Goto node error:"+b);if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in gotonode()::"+b.message,"functions.js")}}}function o_viewportHeight(){var a=jQuery(document).height();if(a>0){return a}else{return 600}}OPOL.getMainColumnsMaxHeight=function(){var j=0,f=0,a=0,c=0,h=0,b,g=jQuery("#o_main_left_content"),e=jQuery("#o_main_right_content"),d=jQuery("#o_main_center_content");if(g!="undefined"&&g!=null){j=g.outerHeight(true)}if(e!="undefined"&&e!=null){f=e.outerHeight(true)}if(d!="undefined"&&d!=null){a=d.outerHeight(true)}c=(j>f?j:f);c=(c>a?c:a);if(c>0){return c}b=jQuery("#o_main");if(b!="undefined"&&b!=null){h=b.height()}if(b>0){return b}return o_viewportHeight()};OPOL.adjustHeight=function(){try{var a=0;col1=jQuery("#o_main_left_content").outerHeight(true);col2=jQuery("#o_main_right_content").outerHeight(true);col3=jQuery("#o_main_center_content").outerHeight(true);a=Math.max(col1,col2,col3);if(col1!=null){jQuery("#o_main_left").css({"min-height":a+"px"})}if(col2!=null){jQuery("#o_main_right").css({"min-height":a+"px"})}if(col3!=null){jQuery("#o_main_center").css({"min-height":a+"px"})}}catch(b){if(window.console){console.log(b)}}};jQuery(window).resize(function(){clearTimeout(o_info.resizeId);o_info.resizeId=setTimeout(function(){jQuery(document).trigger("oo.window.resize.after")},500)});jQuery(document).on("oo.window.resize.after",OPOL.adjustHeight);jQuery(document).on("oo.dom.replacement.after",OPOL.adjustHeight);jQuery().ready(OPOL.adjustHeight);function o_scrollToElement(a){try{o_info.scrolling=true;jQuery("html, body").animate({scrollTop:jQuery(a).offset().top},333,function(d,c){o_info.scrolling=false})}catch(b){}}function o_popover(c,b,a){if(typeof(a)==="undefined"){a="bottom"}jQuery("#"+c).popover({placement:a,html:true,trigger:"click",container:"body",content:function(){return jQuery("#"+b).clone().html()}}).on("shown.bs.popover",function(){var d=function(f){jQuery("#"+c).popover("hide");jQuery("body").unbind("click",d)};setTimeout(function(){jQuery("body").on("click",d)},5)})}function o_popoverWithTitle(d,c,b,a){if(typeof(a)==="undefined"){a="bottom"}return jQuery("#"+d).popover({placement:a,html:true,title:b,trigger:"click",container:"body",content:function(){return jQuery("#"+c).clone().html()}}).on("shown.bs.popover",function(){var e=function(f){jQuery("#"+d).popover("destroy");jQuery("body").unbind("click",e)};setTimeout(function(){jQuery("body").on("click",e)},5)})}function o_shareLinkPopup(d,c,b){if(typeof(b)==="undefined"){b="top"}var a=jQuery("#"+d);a.popover({placement:b,html:true,trigger:"click",container:"body",content:c}).on("shown.bs.popover",function(){var e=function(f){if(jQuery(f.target).data("toggle")!=="popover"&&jQuery(f.target).parents(".popover.in").length===0){jQuery("#"+d).popover("hide");jQuery("body").unbind("click",e)}};setTimeout(function(){jQuery("body").on("click",e)},5)});a.attr("title",a.attr("data-original-title"))}function o_QRCodePopup(d,c,b){if(typeof(b)==="undefined"){b="top"}var a=jQuery("#"+d);a.popover({placement:b,html:true,trigger:"click",container:"body",content:'<div id="'+d+'_pop" class="o_qrcode"></div>'}).on("shown.bs.popover",function(){o_info.qr=o_QRCode(d+"_pop",(jQuery.isFunction(c)?c():c));var e=function(f){if(jQuery(f.target).data("toggle")!=="popover"&&jQuery(f.target).parents(".popover.in").length===0){jQuery("#"+d).popover("hide");jQuery("body").unbind("click",e)}};setTimeout(function(){jQuery("body").on("click",e)},5)}).on("hidden.bs.popover",function(){try{o_info.qr.clear();delete o_info.qr}catch(f){}});a.attr("title",a.attr("data-original-title"))}function o_QRCode(c,b){try{BLoader.loadJS(o_info.o_baseURI+"/js/jquery/qrcodejs/qrcode.min.js","utf8",true);return new QRCode(document.getElementById(c),b)}catch(a){return null}}function b_resizeIframeToMainMaxHeight(f){var d=jQuery("#"+f);if(d!="undefined"&&d!=null){var c=OPOL.getMainColumnsMaxHeight()-110;var b=o_viewportHeight()-100;b=b-d.offset().top;var e=jQuery("#b_footer");if(e!="undefined"&&e!=null){b=b-e.outerHeight(true)}var a=(b>c?b:c);d.height(a)}}var o_debu_oldcn,o_debu_oldtt;function o_debu_show(b,a){if(o_debu_oldcn){o_debu_hide(o_debu_oldcn,o_debu_oldtt)}jQuery(b).addClass("o_dev_m");jQuery(a).show();o_debu_oldtt=a;o_debu_oldcn=b}function o_debu_hide(b,a){jQuery(a).hide();jQuery(b).removeClass("o_dev_m")}function o_dbg_mark(a){var b=jQuery("#"+a);if(b){b.css("background-color","#FCFCB8");b.css("border","3px solid #00F")}}function o_dbg_unmark(a){var b=jQuery("#"+a);if(b){b.css("border","");b.css("background-color","")}}function o_clearConsole(){o_log_all="";o_log(null)}var o_log_all="";function o_log(b){if(b){o_log_all="\n"+o_debug_trid+"> "+b+o_log_all;o_log_all=o_log_all.substr(0,4000)}var a=jQuery("#o_debug_cons");if(a){if(o_log_all.length==4000){o_log_all=o_log_all+"\n... (stripped: to long)... "}a.value=o_log_all}if(!jQuery.type(window.console)==="undefined"){window.console.log(b)}}function o_logerr(a){o_log("ERROR:"+a)}function o_logwarn(a){o_log("WARN:"+a)}function showerror(c){var a="";for(var b in c){a+=b+": "+c[b]+"\n"}return"error detail:\n"+a}function o_ffEvent(f,e,d,m,n){var g,h,b,a;g=document.getElementById(e);h=g.value;g.value=d;b=document.getElementById(m);a=b.value;b.value=n;var c=jQuery("#"+f);var j=c.attr("enctype");if(j&&j.indexOf("multipart")==0){o_XHRSubmitMultipart(f)}else{if(document.forms[f].onsubmit()){document.forms[f].submit()}}g.value=h;b.value=a}function o_IQEvent(a){if(document.forms[a].onsubmit()){document.forms[a].submit()}}function o_TableMultiActionEvent(a,c){var b=jQuery("#o_mai_"+a);b.val(c);if(document.forms[a].onsubmit()){document.forms[a].submit()}b.val("")}function o_XHRSubmit(h){if(o_info.linkbusy){return false}o_beforeserver();var n=true;var a=jQuery("#"+h);var m=a.attr("enctype");if(m&&m.indexOf("multipart")==0){var g="openolat-submit-"+(""+Math.random()).substr(2);var d=o_createIFrame(g);document.body.appendChild(d);a.attr("target",d.name);return true}else{var f=a.serializeArray();if(arguments.length>1){var j=arguments.length;for(var e=1;e<j;e=e+2){if(j>e+1){var c=new Object();c.name=arguments[e];c.value=arguments[e+1];f[f.length]=c}}}var b=a.attr("action");jQuery.ajax(b,{type:"POST",data:f,cache:false,dataType:"json",success:function(r,u,q){try{o_ainvoke(r);if(n){var o=r.businessPath;var p=r.documentTitle;var t=r.historyPointId;if(o){o_pushState(t,p,o)}}}catch(s){if(window.console){console.log(s)}}finally{o_afterserver()}},error:o_onXHRError});return false}}function o_XHRSubmitMultipart(a){var c=jQuery("#"+a);var d="openolat-submit-"+(""+Math.random()).substr(2);var b=o_createIFrame(d);document.body.appendChild(b);c.attr("target",b.name);c.submit();c.attr("target","")}function o_createIFrame(b){var a=jQuery('<iframe name="'+b+'" id="'+b+'" src="about:blank" style="position: absolute; top: -9999px; left: -9999px;"></iframe>');return a[0]}function o_removeIframe(a){jQuery("#"+a).remove()}function o_ffXHREvent(h,g,b,n,p,s,o,j){if(s){if(!o2cl()){return false}}else{if(!o2cl_noDirtyCheck()){return false}}var f=new Object();if(j){var a=jQuery("#"+h);var d=a.serializeArray();var q=d.length;for(var e=0;e<q;e++){var r=d[e];if(r.name!="dispatchuri"&&r.name!="dispatchevent"){f[r.name]=r.value}}}f.dispatchuri=b;f.dispatchevent=p;if(arguments.length>8){var m=arguments.length;for(var e=8;e<m;e=e+2){if(m>e+1){f[arguments[e]]=arguments[e+1]}}}var c=jQuery("#"+h).attr("action");jQuery.ajax(c,{type:"POST",data:f,cache:false,dataType:"json",success:function(w,z,v){try{o_ainvoke(w);if(o){var t=w.businessPath;var u=w.documentTitle;var y=w.historyPointId;if(t){o_pushState(y,u,t)}}}catch(x){if(window.console){console.log(x)}}finally{o_afterserver()}},error:o_onXHRError})}function o_ffXHRNFEvent(f,e,a,h,j){var c=new Object();c.dispatchuri=a;c.dispatchevent=j;if(arguments.length>5){var g=arguments.length;for(var d=5;d<g;d=d+2){if(g>d+1){c[arguments[d]]=arguments[d+1]}}}var b=jQuery("#"+f).attr("action");jQuery.ajax(b,{type:"POST",data:c,cache:false,dataType:"json",success:function(n,o,m){}})}function o_XHREvent(f,d,a){if(d){if(!o2cl()){return false}}else{if(!o2cl_noDirtyCheck()){return false}}var c=new Object();if(arguments.length>3){var e=arguments.length;for(var b=3;b<e;b=b+2){if(e>b+1){c[arguments[b]]=arguments[b+1]}}}jQuery.ajax(f,{type:"POST",data:c,cache:false,dataType:"json",success:function(m,p,j){try{o_ainvoke(m);if(a){var g=m.businessPath;var h=m.documentTitle;var o=m.historyPointId;if(g){o_pushState(o,h,g)}}}catch(n){if(window.console){console.log(n)}}finally{o_afterserver()}},error:o_onXHRError});return false}function o_XHRNFEvent(d){var b=new Object();if(arguments.length>1){var c=arguments.length;for(var a=1;a<c;a=a+2){if(c>a+1){b[arguments[a]]=arguments[a+1]}}}jQuery.ajax(d,{type:"POST",data:b,cache:false,dataType:"json",success:function(f,g,e){},error:o_onXHRError})}function o_onXHRError(a,d,b){o_afterserver();if(401==a.status){var c=o_info.oo_noresponse.replace("reload.html",window.document.location.href);showMessageBox("error",o_info.oo_noresponse_title,c,undefined)}else{if(window.console){console.log("Error status 2",d,b,a.responseText);console.log(a)}}}function o_pushState(d,f,a){try{var b=new Object();b.businessPath=a;b.historyPointId=d;if(a!=null&&!(a.lastIndexOf("http",0)===0)&&!(a.lastIndexOf("https",0)===0)){a=o_info.serverUri+a}o_info.businessPath=a;if(!(typeof o_shareActiveSocialUrl==="undefined")){o_shareActiveSocialUrl()}if(window.history&&!(typeof window.history==="undefined")&&window.history.pushState){window.history.pushState(b,f,a)}else{window.location.hash=d}}catch(c){if(window.console){console.log(c,a)}}}function o_toggleMark(a){var b=jQuery("i",a).attr("class");if(b.indexOf("o_icon_bookmark_add")>=0){jQuery("i",a).removeClass("o_icon_bookmark_add").addClass("o_icon_bookmark")}else{jQuery("i",a).removeClass("o_icon_bookmark").addClass("o_icon_bookmark_add")}}function setFlexiFormDirtyByListener(a){setFlexiFormDirty(a.data.formId,a.data.hideMessage)}function setFlexiFormDirty(b,c){var a=o3c.indexOf(b)>-1;if(!a){o3c.push(b)}jQuery("#"+b).each(function(){var d=jQuery(this).data("FlexiSubmit");if(d!=null){jQuery("#"+d).addClass("btn o_button_dirty");o2c=(c?0:1)}})}function o_ffRegisterSubmit(b,a){jQuery("#"+b).data("FlexiSubmit",a)}function dismissInfoBox(a){javascript:jQuery("#"+a).remove();return true}function showInfoBox(g,d){var c=Math.floor(Math.random()*65536).toString(16);var f='<div id="'+c+'" class="o_alert_info"><div class="alert alert-info clearfix o_sel_info_message"><a class="o_alert_close o_sel_info_close" href="javascript:;" onclick="dismissInfoBox(\''+c+'\')"><i class="o_icon o_icon_close"> </i></a><h3><i class="o_icon o_icon_info"> </i> '+g+"</h3><p>"+d+"</p></div></div>";var a=jQuery("#o_messages").prepend(f);var e=(d.length>150)?8000:((d.length>70)?6000:4000);var b=function(){jQuery("#"+c).transition({top:"-100%"},333,function(){jQuery("#"+c).remove()})};o_info.scrolling=true;jQuery("#"+c).show().transition({top:0},333);jQuery("#"+c).click(function(h){b()});o_scrollToElement("#o_top");g=null;d=null;a=null;setTimeout(function(){try{b()}catch(h){}},e)}function showMessageBox(b,f,d,a){if(b=="info"){showInfoBox(f,d);return null}else{var c='<div id="myFunctionalModal" class="modal fade" role="dialog"><div class="modal-dialog"><div class="modal-content">';c+='<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>';c+='<h4 class="modal-title">'+f+"</h4></div>";c+='<div class="modal-body alert ';if("warn"==b){c+="alert-warning"}else{if("error"==b){c+="alert-danger"}else{c+="alert-info"}}c+='"><p>'+d+"</p></div></div></div></div>";jQuery("#myFunctionalModal").remove();jQuery("body").append(c);var e=jQuery("#myFunctionalModal").modal("show").on("hidden.bs.modal",function(g){jQuery("#myFunctionalModal").remove()});o_scrollToElement("#o_top");return e}}function o_table_toggleCheck(d,c){var a=document.forms[d].elements.tb_ms;len=a.length;if(typeof(len)=="undefined"){a.checked=c}else{var b;for(b=0;b<len;b++){a[b].checked=c}}}function onTreeStartDrag(a,b){jQuery(a.target).addClass("o_dnd_proxy")}function onTreeStopDrag(a,b){jQuery(a.target).removeClass("o_dnd_proxy")}function onTreeDrop(g,h){var a=jQuery(h.draggable[0]);var f=jQuery(this);f.css({position:"",width:""});var c=f.droppable("option","endUrl");if(c.lastIndexOf("/")==(c.length-1)){c=c.substring(0,c.length-1)}var e=a.attr("id");var b=e.substring(2,e.length);c+="%3Atnidle%3A"+b;var d=f.attr("id");if(d.indexOf("ds")==0){c+="%3Asne%3Ayes"}else{if(d.indexOf("dt")==0){c+="%3Asne%3Aend"}}jQuery(".ui-droppable").each(function(j,m){jQuery(m).droppable("disable")});o_XHREvent(c+"/",false,false)}function treeAcceptDrop(a){return true}function treeAcceptDrop_notWithChildren(a){var c=false;var b=jQuery(a);var e=b.attr("id");if(e!=undefined&&(e.indexOf("dd")==0||e.indexOf("ds")==0||e.indexOf("dt")==0||e.indexOf("da")==0||e.indexOf("row")==0)){var g=jQuery(this);var j=g.attr("id");var d=e.substring(2,e.length);var f=j.substring(2,j.length);if(d!=f){var h=jQuery("#dd"+d).parents("li");if(h.length>0&&jQuery(h.get(0)).find("#dd"+f).length==0){c=true}}}return c}function treeAcceptDrop_portfolio(b){var d=false;var c=jQuery(b);var f=c.attr("id");if(treeNode_isDragNode(f)){var h=jQuery(this);var n=h.attr("id");var e=f.substring(2,f.length);var g=n.substring(2,n.length);var m=f.indexOf("ds")==0||f.indexOf("dt")==0;if(e!=g){var j=treeNode_portfolioType(c);var a=treeNode_portfolioType(h);if(j=="artefact"){if(a=="page"||a=="struct"||a=="artefact"){d=true}}else{if(j=="struct"){if(a=="page"||a=="struct"){d=true}}else{if(j=="page"){if(a=="map"||a=="page"){d=true}}}}}}return d}function treeNode_portfolioType(e){var c=jQuery(e.get(0));var d=treeNode_portfolioTypes(c);if(d==null){var a=c.parent("a");if(a.length>0){d=treeNode_portfolioTypes(jQuery(a.get(0)))}else{if(c.attr("id").indexOf("ds")==0){var b=c.prev("div");if(b.length>0){d=treeNode_portfolioTypes(b)}}else{if(c.attr("id").indexOf("dt")==0){var b=c.next("div");if(b.length>0){d=treeNode_portfolioTypes(b)}}}}}return d}function treeNode_portfolioTypes(a){if(a.find===undefined){return null}else{if(a.find(".o_ep_icon_struct").length>0||a.hasClass("o_ep_icon_struct")){return"struct"}else{if(a.find(".o_ep_icon_page").length>0||a.hasClass("o_ep_icon_page")){return"page"}else{if(a.find(".o_ep_icon_map").length>0||a.hasClass("o_ep_icon_map")){return"map"}else{if(a.find(".o_ep_artefact").length>0||a.hasClass("o_ep_artefact")){return"artefact"}}}}}return null}function treeNode_isDragNode(a){if(a!=undefined&&(a.indexOf("dd")==0||a.indexOf("ds")==0||a.indexOf("dt")==0||a.indexOf("da")==0||a.indexOf("row")==0)){return true}return false}function o_choice_toggleCheck(c,b){var d=document.forms[c].elements;len=d.length;if(typeof(len)=="undefined"){d.checked=b}else{var a;for(a=0;a<len;a++){if(d[a].type=="checkbox"&&d[a].getAttribute("class")=="o_checkbox"){d[a].checked=b}}}}function b_briefcase_isChecked(c,e){var b;var a=document.getElementById(c);var d=0;for(b=0;a.elements[b];b++){if(a.elements[b].type=="checkbox"&&a.elements[b].name=="paths"&&a.elements[b].checked){d++}}if(d<1){alert(e);return false}return true}function b_briefcase_toggleCheck(d,c){var a=document.getElementById(d);len=a.elements.length;var b;for(b=0;b<len;b++){if(a.elements[b].name=="paths"){a.elements[b].checked=c}}}function o_doPrint(){var d=jQuery("div.o_iframedisplay iframe");if(d.length>0){try{var a=d[0];frames[a.name].focus();frames[a.name].print();return}catch(c){for(i=0;frames.length>i;i++){a=frames[i];if(a.name=="oaa0"){continue}var b=document.getElementsByName(a.name)[0];if(b&&b.getAttribute("class")=="ext-shim"){continue}if(a.name!=""){try{frames[a.name].focus();frames[a.name].print()}catch(c){window.print()}return}}window.print()}}else{window.print()}}function b_attach_i18n_inline_editing(){jQuery("span.o_translation_i18nitem").hover(function(){jQuery(this.firstChild).show();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Entered i18nitem::"+this.firstChild,"functions.js:b_attach_i18n_inline_editing()")}},function(){jQuery("a.o_translation_i18nitem_launcher").hide();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Leaving i18nitem::"+this,"functions.js:b_attach_i18n_inline_editing()")}});jQuery("a.o_translation_i18nitem_launcher").hover(function(){var a=jQuery(this).parent("span.o_translation_i18nitem");a.effect("highlight")});b_AddOnDomReplacementFinishedCallback(b_attach_i18n_inline_editing)}function b_hideExtMessageBox(){}var BDebugger={_lastDOMCount:0,_lastObjCount:0,_knownGlobalOLATObjects:["o_afterserver","o_onc","o_getMainWin","o_ainvoke","o_info","o_beforeserver","o_ffEvent","o_openPopUp","o_debu_show","o_logwarn","o_dbg_unmark","o_ffRegisterSubmit","o_clearConsole","o_init","o_log","o_allowNextClick","o_dbg_mark","o_debu_hide","o_logerr","o_debu_oldcn","o_debu_oldtt","o_debug_trid","o_log_all"],_countDOMElements:function(){return document.getElementsByTagName("*").length},_countGlobalObjects:function(){var a=0;for(prop in window){a++}return a},logDOMCount:function(){var b=BDebugger;var a=b._countDOMElements();var c=a-b._lastDOMCount;console.log((c>0?"+":"")+c+" \t"+a+" \tDOM element count after DOM replacement");b._lastDOMCount=a;a=null},logGlobalObjCount:function(){var b=BDebugger;var a=b._countGlobalObjects();var c=a-b._lastObjCount;console.log((c>0?"+":"")+c+" \t"+a+" \tGlobal object count after DOM replacement");b._lastObjCount=a;a=null},logGlobalOLATObjects:function(){var b=BDebugger;var a=new Array();for(prop in window){if(prop.indexOf("o_")==0&&b._knownGlobalOLATObjects.indexOf(prop)==-1){a.push(prop)}}if(a.length>0){console.log(a.length+" global OLAT objects found:");a.each(function(c){console.log("\t"+typeof window[c]+" \t"+c)})}}};/*! +jQuery.periodic=function(l,h){if(jQuery.isFunction(l)){h=l;l={}}var c=jQuery.extend({},jQuery.periodic.defaults,{ajax_complete:j,increment:g,reset:f,cancel:i},l);c.cur_period=c.period;c.tid=false;var e="";b();return c;function b(){i();c.tid=setTimeout(function(){h.call(c);g();if(c.tid){b()}},c.cur_period)}function j(n,m){if(m==="success"&&e!==n.responseText){e=n.responseText;f()}}function g(){c.cur_period*=c.decay;if(c.cur_period<c.period){f()}else{if(c.cur_period>c.max_period){c.cur_period=c.max_period;if(c.on_max!==undefined){c.on_max.call(c)}}}}function f(){c.cur_period=c.period;b()}function i(){clearTimeout(c.tid);c.tid=null}function k(){}function a(){}function d(){}};jQuery.periodic.defaults={period:4000,max_period:1800000,decay:1.5,on_max:undefined};var Hashtable=(function(){var p="function";var n=(typeof Array.prototype.splice==p)?function(s,r){s.splice(r,1)}:function(u,t){var s,v,r;if(t===u.length-1){u.length=t}else{s=u.slice(t+1);u.length=t;for(v=0,r=s.length;v<r;++v){u[t+v]=s[v]}}};function a(t){var r;if(typeof t=="string"){return t}else{if(typeof t.hashCode==p){r=t.hashCode();return(typeof r=="string")?r:a(r)}else{if(typeof t.toString==p){return t.toString()}else{try{return String(t)}catch(s){return Object.prototype.toString.call(t)}}}}}function g(r,s){return r.equals(s)}function e(r,s){return(typeof s.equals==p)?s.equals(r):(r===s)}function c(r){return function(s){if(s===null){throw new Error("null is not a valid "+r)}else{if(typeof s=="undefined"){throw new Error(r+" must not be undefined")}}}}var q=c("key"),l=c("value");function d(u,s,t,r){this[0]=u;this.entries=[];this.addEntry(s,t);if(r!==null){this.getEqualityFunction=function(){return r}}}var h=0,j=1,f=2;function o(r){return function(t){var s=this.entries.length,v,u=this.getEqualityFunction(t);while(s--){v=this.entries[s];if(u(t,v[0])){switch(r){case h:return true;case j:return v;case f:return[s,v[1]]}}}return false}}function k(r){return function(u){var v=u.length;for(var t=0,s=this.entries.length;t<s;++t){u[v+t]=this.entries[t][r]}}}d.prototype={getEqualityFunction:function(r){return(typeof r.equals==p)?g:e},getEntryForKey:o(j),getEntryAndIndexForKey:o(f),removeEntryForKey:function(s){var r=this.getEntryAndIndexForKey(s);if(r){n(this.entries,r[0]);return r[1]}return null},addEntry:function(r,s){this.entries[this.entries.length]=[r,s]},keys:k(0),values:k(1),getEntries:function(s){var u=s.length;for(var t=0,r=this.entries.length;t<r;++t){s[u+t]=this.entries[t].slice(0)}},containsKey:o(h),containsValue:function(s){var r=this.entries.length;while(r--){if(s===this.entries[r][1]){return true}}return false}};function m(s,t){var r=s.length,u;while(r--){u=s[r];if(t===u[0]){return r}}return null}function i(r,s){var t=r[s];return(t&&(t instanceof d))?t:null}function b(t,r){var w=this;var v=[];var u={};var x=(typeof t==p)?t:a;var s=(typeof r==p)?r:null;this.put=function(B,C){q(B);l(C);var D=x(B),E,A,z=null;E=i(u,D);if(E){A=E.getEntryForKey(B);if(A){z=A[1];A[1]=C}else{E.addEntry(B,C)}}else{E=new d(D,B,C,s);v[v.length]=E;u[D]=E}return z};this.get=function(A){q(A);var B=x(A);var C=i(u,B);if(C){var z=C.getEntryForKey(A);if(z){return z[1]}}return null};this.containsKey=function(A){q(A);var z=x(A);var B=i(u,z);return B?B.containsKey(A):false};this.containsValue=function(A){l(A);var z=v.length;while(z--){if(v[z].containsValue(A)){return true}}return false};this.clear=function(){v.length=0;u={}};this.isEmpty=function(){return !v.length};var y=function(z){return function(){var A=[],B=v.length;while(B--){v[B][z](A)}return A}};this.keys=y("keys");this.values=y("values");this.entries=y("getEntries");this.remove=function(B){q(B);var C=x(B),z,A=null;var D=i(u,C);if(D){A=D.removeEntryForKey(B);if(A!==null){if(!D.entries.length){z=m(v,C);n(v,z);delete u[C]}}}return A};this.size=function(){var A=0,z=v.length;while(z--){A+=v[z].entries.length}return A};this.each=function(C){var z=w.entries(),A=z.length,B;while(A--){B=z[A];C(B[0],B[1])}};this.putAll=function(H,C){var B=H.entries();var E,F,D,z,A=B.length;var G=(typeof C==p);while(A--){E=B[A];F=E[0];D=E[1];if(G&&(z=w.get(F))){D=C(F,z,D)}w.put(F,D)}};this.clone=function(){var z=new b(t,r);z.putAll(w);return z}}return b})();(function(b){b.fn.ooLog=function(f,d,e){var c=null;b(this).each(function(){c=b(this).data("_ooLog");if(c==undefined){c=new a();b(this).data("_ooLog",c)}});if(f==undefined){return c}else{if(typeof f==="string"){if(c){c.log(f,d,e)}}}};function a(){return this}a.prototype={isDebugEnabled:function(){return o_info.JSTracingLogDebugEnabled},log:function(e,c,d){if(!this.isDebugEnabled()){return}jQuery.post(o_info.JSTracingUri,{level:e,logMsg:c,jsFile:d})}}})(jQuery);(function(b){b.fn.ooTranslator=function(){var d=null;b(document).each(function(){d=b(document).data("_ooTranslator");if(d==undefined){d=new a();b(document).data("_ooTranslator",d)}});return d};function a(){return this}a.prototype={mapperUrl:null,translators:null,initialize:function(d){this.mapperUrl=d;this.translators=new Object()},getTranslator:function(d,f){if(this.translators[d]==null){this.translators[d]=new Object()}if(this.translators[d][f]==null){var e=this.mapperUrl+"/"+d+"/"+f+"/translations.js";jQuery.ajax(e,{async:false,dataType:"json",success:function(g,i,h){jQuery(document).ooTranslator()._createTranslator(g,d,f)}})}return this.translators[d][f]},_createTranslator:function(e,d,f){this.translators[d][f]=new c().initialize(e,d,f)}};function c(){return this}c.prototype={localizationData:null,bundle:null,locale:null,initialize:function(f,d,e){this.bundle=e;this.locale=d;this.localizationData=f;return this},translate:function(d){if(this.localizationData[d]){return this.localizationData[d]}else{return this.bundle+":"+d}}}})(jQuery);+function(b){var a=function(){this.addExtraElements();this.state={busy:false,brandW:0,sitesW:0,sitesDirty:false,sites:{collapsed:this.isSitesCollapsed(),extended:this.isSitesExtended},tabsW:0,tabsDirty:false,tabs:{collapsed:this.isTabsCollapsed(),extended:this.isTabsExtended()},toolsW:0,toolsDirty:false,tools:{collapsed:this.isToolsCollapsed(),extended:this.isToolsExtended()},offCanvasWidth:0,moreW:0};var c=b("#o_offcanvas_right").css("width");if(c){this.state.offCanvasWidth=parseInt(c.replace(/[^\d.]/g,""));this.initListners();this.calculateWidth();this.optimize()}};a.prototype.initListners=function(){b(window).resize(b.proxy(this.onResizeCallback,this));b(document).on("oo.nav.sites.modified",b.proxy(function(){this.state.sitesDirty=true},this));b(document).on("oo.nav.tabs.modified",b.proxy(function(){this.state.tabsDirty=true},this));b(document).on("oo.nav.tools.modified",b.proxy(function(){this.state.toolsDirty=true},this));b(document).on("oo.dom.replacement.after",b.proxy(this.onDOMreplacementCallback,this));b(window).on("orientationchange",b.proxy(this.hideRight,this));b("#o_navbar_right-toggle").on("click",b.proxy(this.toggleRight,this));b("#o_offcanvas_right .o_offcanvas_close").on("click",b.proxy(this.hideRight,this));b("#o_navbar_more").on("shown.bs.dropdown",this.onDropdownShown);b("#o_navbar_more").on("hidden.bs.dropdown",this.onDropdownHidden)};a.prototype.onResizeCallback=function(){if(!this.state.busy){this.state.busy=true;this.calculateWidth();this.optimize();this.state.busy=false}};a.prototype.onDOMreplacementCallback=function(){if(!this.state.busy&&(this.state.sitesDirty||this.state.tabsDirty||this.state.toolsDirty)){this.state.busy=true;this.cleanupMoreDropdown();this.calculateWidth();this.optimize();this.state.sitesDirty=false;this.state.tabsDirty=false;this.state.toolsDirty=false;this.state.busy=false}};a.prototype.onDropdownShown=function(c){var f=b("#o_navbar_more .dropdown-menu");if(f.length){var d=f.offset().left;if(d<0){f.removeClass("dropdown-menu-right")}}};a.prototype.onDropdownHidden=function(c){var d=b("#o_navbar_more .dropdown-menu");d.addClass("dropdown-menu-right")};a.prototype.calculateWidth=function(){var c=b("#o_navbar_container .o_navbar-collapse");this.state.navbarW=c.innerWidth();this.state.brandW=b(".o_navbar-brand").outerWidth(true);this.state.sitesW=this.getSites().outerWidth(true);this.state.tabsW=this.getTabs().outerWidth(true);this.state.toolsW=this.getTools().outerWidth(false);this.state.moreW=b("#o_navbar_more:visible").outerWidth(true)};a.prototype.getOverflow=function(c){var d=this.state.navbarW;d-=this.state.sitesW;d-=this.state.tabsW;d-=this.state.toolsW;d-=this.state.brandW;d-=this.state.moreW;d-=25;return -d};a.prototype.optimize=function(h){var c=this.getOverflow();var k=this.getSites();var l=this.getTabs();var g=this.getTools();var n=this.getMoreDropdown();var f=this.getOffcanvasRight();this.updateState();while(c>0&&(!this.state.tabs.collapsed||!this.state.sites.collapsed||!this.state.tools.collapsed)){if(!this.state.tabs.collapsed){this.collapse(l,n,"li","o_dropdown_tab")}else{if(!this.state.sites.collapsed){this.collapse(k,n,"li","o_dropdown_site")}else{if(!this.state.tools.collapsed){this.collapse(g,f,".o_navbar_tool:not(#o_navbar_imclient, #o_navbar_search_opener, #o_navbar_my_menu)","o_tool_right")}}}this.calculateWidth();c=this.getOverflow();this.updateState()}while(c<0&&(!this.state.tabs.extended||!this.state.sites.extended||!this.state.tools.extended)){if(!this.state.tools.extended){var m=this.extend(f,g.children("#o_navbar_imclient, #o_navbar_search_opener, #o_navbar_my_menu").first(),".o_tool_right","o_tool_right",true);if(!m){break}}if(!this.state.sites.extended){var j=this.extend(n,k,"li","o_dropdown_site");if(!j){break}}else{if(!this.state.tabs.extended){var d=this.extend(n,l,"li","o_dropdown_tab");if(!d){break}}}this.calculateWidth();c=this.getOverflow();this.updateState()}if(this.state.sites.extended&&this.state.tabs.extended){var i=b("#o_navbar_more");i.css("display","none")}this.checkToolsOrder()};a.prototype.updateState=function(){this.state.sites.collapsed=this.isSitesCollapsed();this.state.sites.extended=this.isSitesExtended();this.state.tabs.collapsed=this.isTabsCollapsed();this.state.tabs.extended=this.isTabsExtended();this.state.tools.collapsed=this.isToolsCollapsed();this.state.tools.extended=this.isToolsExtended()};a.prototype.collapse=function(g,d,c,f){var e=g.find(c);if(e.length){e=e.last()}if(e.length){f&&e.addClass(f);if(d){e.prependTo(d)}}this.updateDropdownToggle(g)};a.prototype.extend=function(g,d,c,i,f){var e=g.find(c);if(e.length){e=e.first()}var j=false;if(e.length){if(d&&d.length){if(f){d.before(e)}else{e.appendTo(d)}this.updateDropdownToggle(g);this.calculateWidth();var h=this.getOverflow();if(h>0){e.prependTo(g)}else{i&&e.removeClass(i);j=true}}}this.updateDropdownToggle(g);return j};a.prototype.updateDropdownToggle=function(c){var d=c.parents(".o_dropdown_toggle");if(!d.length){return}if(c.children().length){d.css("display","block")}else{d.css("display","none")}};a.prototype.addExtraElements=function(){var d=b("#o_navbar_container .o_navbar-collapse");var c=b("#o_navbar_more");if(c.length==0){c=b('<ul id="o_navbar_more" class="nav o_navbar-nav o_dropdown_toggle"><li><a class="dropdown-toggle" data-toggle="dropdown" href="#"">'+o_info.i18n_topnav_more+' <b class="caret"></b></a><ul class="dropdown-menu dropdown-menu-right"></ul></li></ul>');c.appendTo(d)}this.getSites().append('<li class="divider o_dropdown_site"></li>');b("#o_navbar_help .o_icon, #o_navbar_print .o_icon").addClass("o_icon-fw")};a.prototype.cleanupMoreDropdown=function(){if(!this.state.sitesDirty){var f=this.getSites();var d=this.getMoreDropdown().children(".o_dropdown_site");d.appendTo(f)}else{this.getSites().append('<li class="divider o_dropdown_site"></li>')}if(!this.state.tabsDirty){var e=this.getTabs();var c=this.getMoreDropdown().children(".o_dropdown_tab");c.prependTo(e)}this.getMoreDropdown().empty()};a.prototype.checkToolsOrder=function(){var f=this.getTools();var e=f.find("#o_navbar_help");var d=f.find("#o_navbar_print");var c=f.find("#o_navbar_imclient");if(c&&d){c.after(d)}if(c&&e){c.after(e)}};a.prototype.showRight=function(){if(!this.isOffcanvasVisible()&&!this.offcanvasTransitioning){this.offcanvasTransitioning=true;var d=this;var c=b("#o_offcanvas_right");c.show().transition({x:-d.state.offCanvasWidth},function(){b("body").addClass("o_offcanvas_right_visible");var e=b.proxy(d.hideRightOnClick,d);setTimeout(function(){b("html").on("click",e);d.offcanvasTransitioning=false},10)})}};a.prototype.hideRightOnClick=function(c){if("INPUT"!=c.target.nodeName){this.hideRight()}};a.prototype.hideRight=function(){if(this.isOffcanvasVisible()&&!this.offcanvasTransitioning){this.offcanvasTransitioning=true;b("html").off("click",b.proxy(this.hideRight,this));var d=this;var c=b("#o_offcanvas_right");c.transition({x:d.state.offCanvasWidth},function(){c.hide();b("body").removeClass("o_offcanvas_right_visible");d.offcanvasTransitioning=false})}};a.prototype.toggleRight=function(){if(this.isOffcanvasVisible()){this.hideRight()}else{this.showRight()}};a.prototype.isOffcanvasVisible=function(){return b("#o_offcanvas_right:visible").length};a.prototype.getSites=function(){return b("#o_navbar_container .o_navbar_sites")};a.prototype.getTabs=function(){return b("#o_navbar_container .o_navbar_tabs")};a.prototype.getTools=function(){return b("#o_navbar_container #o_navbar_tools_permanent")};a.prototype.getMoreDropdown=function(){return b("#o_navbar_more .dropdown-menu")};a.prototype.getOffcanvasRight=function(){return b("#o_offcanvas_right_container .o_navbar-right")};a.prototype.isSitesCollapsed=function(){return !this.getSites().children("li").not(".divider").length};a.prototype.isSitesExtended=function(){return !this.getMoreDropdown().children(".o_dropdown_site").not(".divider").length};a.prototype.isTabsCollapsed=function(){return !this.getTabs().children("li").length};a.prototype.isTabsExtended=function(){return !this.getMoreDropdown().children(".o_dropdown_tab").length};a.prototype.isToolsCollapsed=function(){return !this.getTools().children(".o_navbar_tool").not("#o_navbar_imclient, #o_navbar_search_opener, #o_navbar_my_menu").length};a.prototype.isToolsExtended=function(){return !this.getOffcanvasRight().children(".o_tool_right").length};b(document).ready(function(){var d=b("#o_navbar_wrapper");if(d){var c=new a();window.OPOL.navbar=c}})}(jQuery);+function(b){b.fn.ooBgCarrousel=function(){return new a()};var a=function(){};a.prototype.initCarrousel=function(g){this.settings=b.extend({query:null,images:[],shuffle:false,shuffleFirst:false,durationshow:5000,durationout:500,durationin:500,easeout:"ease",easein:"ease"},g);this.pos=null;if(this.settings.query==null||this.settings.images.length==0){return}this.initialImage=this.settings.images[0];if(this.settings.shuffle){var f=this.settings.images;for(var d,c,e=f.length;e;d=parseInt(Math.random()*e),c=f[--e],f[e]=f[d],f[d]=c){}}if(this.settings.shuffleFirst){this._replaceImage()}this.rotate()};a.prototype.rotate=function(){setTimeout(b.proxy(this._hideCurrent,this),this.settings.durationshow)};a.prototype._hideCurrent=function(){var c=b(this.settings.query);if(c&&c.size()>0){c.transition({opacity:0,duration:this.settings.durationout,easing:this.settings.easeout},b.proxy(this._showNext,this))}};a.prototype._replaceImage=function(d){if(!d){d=b(this.settings.query)}if(d&&d.size()>0){this.newImg="";this.oldImg="";if(this.pos==null){this.pos=1;this.oldImg=this.initialImage}else{this.oldImg=this.settings.images[this.pos];this.pos++;if(this.settings.images.length==this.pos){this.pos=0}}this.newImg=this.settings.images[this.pos];var c=d.css("background-image");if(c.indexOf(this.oldImg)==-1){d.transition({opacity:1,duration:0});return}var e=c.replace(this.oldImg,this.newImg);d.css("background-image",e)}};a.prototype._showNext=function(){var c=b(this.settings.query);this._replaceImage(c);c.transition({opacity:1,duration:this.settings.durationin,easing:this.settings.easein},b.proxy(this.rotate,this))}}(jQuery);!function(e){function t(){function t(e){"remove"===e&&this.each(function(e,t){var n=i(t);n&&n.remove()}),this.find("span.mceEditor,div.mceEditor").each(function(e,t){var n=tinymce.get(t.id.replace(/_parent$/,""));n&&n.remove()})}function r(e){var n,r=this;if(null!=e)t.call(r),r.each(function(t,n){var r;(r=tinymce.get(n.id))&&r.setContent(e)});else if(r.length>0&&(n=tinymce.get(r[0].id)))return n.getContent()}function i(e){var t=null;return e&&e.id&&a.tinymce&&(t=tinymce.get(e.id)),t}function o(e){return!!(e&&e.length&&a.tinymce&&e.is(":tinymce"))}var s={};e.each(["text","html","val"],function(t,a){var l=s[a]=e.fn[a],c="text"===a;e.fn[a]=function(t){var a=this;if(!o(a))return l.apply(a,arguments);if(t!==n)return r.call(a.filter(":tinymce"),t),l.apply(a.not(":tinymce"),arguments),a;var s="",u=arguments;return(c?a:a.eq(0)).each(function(t,n){var r=i(n);s+=r?c?r.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):r.getContent({save:!0}):l.apply(e(n),u)}),s}}),e.each(["append","prepend"],function(t,r){var a=s[r]=e.fn[r],l="prepend"===r;e.fn[r]=function(e){var t=this;return o(t)?e!==n?("string"==typeof e&&t.filter(":tinymce").each(function(t,n){var r=i(n);r&&r.setContent(l?e+r.getContent():r.getContent()+e)}),a.apply(t.not(":tinymce"),arguments),t):void 0:a.apply(t,arguments)}}),e.each(["remove","replaceWith","replaceAll","empty"],function(n,r){var i=s[r]=e.fn[r];e.fn[r]=function(){return t.call(this,r),i.apply(this,arguments)}}),s.attr=e.fn.attr,e.fn.attr=function(t,a){var l=this,c=arguments;if(!t||"value"!==t||!o(l))return a!==n?s.attr.apply(l,c):s.attr.apply(l,c);if(a!==n)return r.call(l.filter(":tinymce"),a),s.attr.apply(l.not(":tinymce"),c),l;var u=l[0],d=i(u);return d?d.getContent({save:!0}):s.attr.apply(e(u),c)}}var n,r,i,o=[],a=window;e.fn.tinymce=function(n){function s(){var r=[],o=0;i||(t(),i=!0),d.each(function(e,t){var i,a=t.id,s=n.oninit;a||(t.id=a=tinymce.DOM.uniqueId()),tinymce.get(a)||(i=new tinymce.Editor(a,n,tinymce.EditorManager),r.push(i),i.on("init",function(){var e,t=s;d.css("visibility",""),s&&++o==r.length&&("string"==typeof t&&(e=t.indexOf(".")===-1?null:tinymce.resolve(t.replace(/\.\w+$/,"")),t=tinymce.resolve(t)),t.apply(e||tinymce,r))}))}),e.each(r,function(e,t){t.render()})}var l,c,u,d=this,f="";if(!d.length)return d;if(!n)return window.tinymce?tinymce.get(d[0].id):null;if(d.css("visibility","hidden"),a.tinymce||r||!(l=n.script_url))1===r?o.push(s):s();else{r=1,c=l.substring(0,l.lastIndexOf("/")),l.indexOf(".min")!=-1&&(f=".min"),a.tinymce=a.tinyMCEPreInit||{base:c,suffix:f},l.indexOf("gzip")!=-1&&(u=n.language||"en",l=l+(/\?/.test(l)?"&":"?")+"js=true&core=true&suffix="+escape(f)+"&themes="+escape(n.theme||"modern")+"&plugins="+escape(n.plugins||"")+"&languages="+(u||""),a.tinyMCE_GZ||(a.tinyMCE_GZ={start:function(){function t(e){tinymce.ScriptLoader.markDone(tinymce.baseURI.toAbsolute(e))}t("langs/"+u+".js"),t("themes/"+n.theme+"/theme"+f+".js"),t("themes/"+n.theme+"/langs/"+u+".js"),e.each(n.plugins.split(","),function(e,n){n&&(t("plugins/"+n+"/plugin"+f+".js"),t("plugins/"+n+"/langs/"+u+".js"))})},end:function(){}}));var p=document.createElement("script");p.type="text/javascript",p.onload=p.onreadystatechange=function(t){t=t||window.event,2===r||"load"!=t.type&&!/complete|loaded/.test(p.readyState)||(tinymce.dom.Event.domLoaded=1,r=2,n.script_loaded&&n.script_loaded(),s(),e.each(o,function(e,t){t()}))},p.src=l,document.body.appendChild(p)}return d},e.extend(e.expr[":"],{tinymce:function(e){var t;return!!(e.id&&"tinymce"in window&&(t=tinymce.get(e.id),t&&t.editorManager===tinymce))}})}(jQuery);OPOL={};var o2c=0;var o3c=new Array();o_info.guibusy=false;o_info.linkbusy=false;o_info.scrolling=false;o_info.debug=true;var BLoader={_ajaxLoadedJS:new Array(),_isAlreadyLoadedJS:function(b){var a=true;jQuery("head script[src]").each(function(d,c){if(jQuery(c).attr("src").indexOf(b)!=-1){a=false}});if(jQuery.inArray(b,this._ajaxLoadedJS)!=-1){a=false}return !a},loadJS:function(b,c,a){if(!this._isAlreadyLoadedJS(b)){if(o_info.debug){o_log("BLoader::loadJS: loading ajax::"+a+" url::"+b)}if(a){jQuery.ajax(b,{async:false,dataType:"script",cache:true,success:function(d,f,e){}});this._ajaxLoadedJS.push(b)}else{jQuery.getScript(b)}if(o_info.debug){o_log("BLoader::loadJS: loading DONE url::"+b)}}else{if(o_info.debug){o_log("BLoader::loadJS: already loaded url::"+b)}}},executeGlobalJS:function(jsString,contextDesc){try{if(window.execScript){window.execScript(jsString)}else{window.eval(jsString)}}catch(e){if(window.console){console.log(contextDesc,"cannot execute js",jsString)}if(o_info.debug){o_logerr("BLoader::executeGlobalJS: Error when executing JS code in contextDesc::"+contextDesc+' error::"'+showerror(e)+" for: "+escape(jsString))}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::executeGlobalJS: Error when executing JS code in contextDesc::"+contextDesc+' error::"'+showerror(e)+" for: "+escape(jsString),"functions.js::BLoader::executeGlobalJS::"+contextDesc)}if(window.location.href.indexOf("o_winrndo")!=-1){window.location.reload()}else{window.location.href=window.location.href+(window.location.href.indexOf("?")!=-1?"&":"?")+"o_winrndo=1"}}},loadCSS:function(b,p,r){var s=window.document;try{if(s.createStyleSheet){var m=s.styleSheets;var d=0;var q=0;for(i=0;i<m.length;i++){var n=m[i];var g=n.href;if(g==b){d++;if(n.disabled){n.disabled=false;return}else{if(o_info.debug){o_logwarn("BLoader::loadCSS: style: "+b+" already in document and not disabled! (duplicate add)")}return}}if(n.id=="o_theme_css"){q=i}}if(d>1&&o_info.debug){o_logwarn("BLoader::loadCSS: apply styles: num of stylesheets found was not 0 or 1:"+d)}if(r){q=m.length}var f=s.createStyleSheet(b,q)}else{var c=jQuery("#"+p);if(c&&c.size()>0){if(o_info.debug){o_logwarn("BLoader::loadCSS: stylesheet already found in doc when trying to add:"+b+", with id "+p)}return}else{var a=jQuery('<link id="'+p+'" rel="stylesheet" type="text/css" href="'+b+'">');if(r){a.insertBefore(jQuery("#o_fontSize_css"))}else{a.insertBefore(jQuery("#o_theme_css"))}}}}catch(o){if(window.console){console.log(o)}if(o_info.debug){o_logerr("BLoader::loadCSS: Error when loading CSS from URL::"+b)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::loadCSS: Error when loading CSS from URL::"+b,"functions.js::BLoader::loadCSS")}}},unLoadCSS:function(a,n){var o=window.document;try{if(o.createStyleSheet){var f=o.styleSheets;var d=0;var p=a;var b=window.location.href.substring(0,window.location.href.indexOf("/",8));if(a.indexOf(b)==0){p=a.substring(b.length)}for(i=0;i<f.length;i++){var g=f[i].href;if(g==a||g==p){d++;if(!f[i].disabled){f[i].disabled=true}else{if(o_info.debug){o_logwarn("stylesheet: when removing: matching url, but already disabled! url:"+g)}}}}if(d!=1&&o_info.debug){o_logwarn("stylesheet: when removeing: num of stylesheets found was not 1:"+d)}}else{var c=jQuery("#"+n);if(c){c.href="";c.remove();c=null;return}else{if(o_info.debug){o_logwarn("no link with id found to remove, id:"+n+", url "+a)}}}}catch(m){if(o_info.debug){o_logerr("BLoader::unLoadCSS: Error when unloading CSS from URL::"+a)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::unLoadCSS: Error when unloading CSS from URL::"+a,"functions.js::BLoader::loadCSS")}}}};var BFormatter={formatLatexFormulas:function(b){try{if(typeof MathJax==="undefined"){o_mathjax()}else{if(MathJax&&MathJax.isReady){jQuery(function(){MathJax.Hub.Queue(function(){if(jQuery("#"+b+" .MathJax").length==0){MathJax.Hub.Typeset(b)}})})}else{setTimeout(function(){BFormatter.formatLatexFormulas(b)},100)}}}catch(a){if(window.console){console.log("error in BFormatter.formatLatexFormulas: ",a)}}},alignTableColumns:function(a){try{var b=new Array();jQuery(a).each(function(){for(j=0;j<jQuery(this)[0].rows[0].cells.length;j++){var d=jQuery(this)[0].rows[0].cells[j];if(!b[j]||b[j]<d.clientWidth){b[j]=d.clientWidth}}});jQuery(a).each(function(){for(j=0;j<jQuery(this)[0].rows[0].cells.length;j++){jQuery(this)[0].rows[0].cells[j].style.width=b[j]+"px"}})}catch(c){if(window.console){console.log("error in BFormatter.alignTableColumns: ",c)}}}};function o_init(){try{o_getMainWin().o_afterserver();if(window.location.href&&window.location.href!=null&&window.location.href.indexOf("%3A")<0){var a=window.location.href;if(a!=null&&!(a.lastIndexOf("http",0)===0)&&!(a.lastIndexOf("https",0)===0)){a=o_info.serverUri+a}o_info.businessPath=a;if(!(typeof o_shareActiveSocialUrl==="undefined")){o_shareActiveSocialUrl()}}}catch(b){if(o_info.debug){o_log("error in o_init: "+showerror(b))}}}function o_initEmPxFactor(){o_info.emPxFactor=jQuery("#o_width_1em").width();if(o_info.emPxFactor==0||o_info.emPxFactor=="undefined"){o_info.emPxFactor=12;if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Could not read with of element b_width_1em, set o_info.emPxFactor to 12","functions.js")}}}function o_getMainWin(){try{if(window.OPOL){return window}else{if(window.opener&&window.opener.OPOL){return window.opener}}}catch(a){if(o_info.debug){o_logerr('Exception while getting main window. rror::"'+showerror(a))}if(window.console){console.log('Exception while getting main window. rror::"'+showerror(a),"functions.js");console.log(a)}}throw"Can not find main OpenOLAT window"}function o_beforeserver(){o_info.linkbusy=true;showAjaxBusy();if(window.suppressOlatOnUnloadOnce){window.suppressOlatOnUnloadOnce=false}else{if(window.olatonunload){olatonunload()}}}function o_afterserver(){o2c=0;o_info.linkbusy=false;removeAjaxBusy()}function o2cl(){try{if(o_info.linkbusy){return false}else{var b=(o2c==0||confirm(o_info.dirty_form));if(b){o_beforeserver()}return b}}catch(a){if(window.console){console.log(a)}return false}}function o2cl_dirtyCheckOnly(){try{if(o_info.linkbusy){return false}else{return(o2c==0||confirm(o_info.dirty_form))}}catch(a){if(window.console){console.log(a)}return false}}function o2cl_noDirtyCheck(){if(o_info.linkbusy){return false}else{o_beforeserver();return true}}function o3cl(d){if(o_info.linkbusy){return false}else{var b=o3c1.indexOf(d)>-1;var a=(b&&o3c1.length>1)||o3c1.length>0;var c=(!a||confirm(o_info.dirty_form));if(c){o_beforeserver()}return c}}function o_onc(a){var b=a.responseText;BLoader.executeGlobalJS("o_info.last_o_onc="+b+";","o_onc");o_ainvoke(o_info.last_o_onc,false)}function o_allowNextClick(){o_info.linkbusy=false;removeAjaxBusy()}function removeBusyAfterDownload(c,b,a){o2c=0;o_afterserver()}Array.prototype.search=function(c,d){var a=this.length;for(var b=0;b<a;b++){if(this[b].constructor==Array){if(this[b].search(c,d)){return true;break}}else{if(d){if(this[b].indexOf(c)!=-1){return true;break}}else{if(this[b]==c){return true;break}}}}return false};if(!Function.prototype.curry){Function.prototype.curry=function(){if(arguments.length<1){return this}var a=this;var b=Array.prototype.slice.call(arguments);return function(){return a.apply(this,b.concat(Array.prototype.slice.call(arguments)))}}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(c){if(this==null){throw new TypeError()}var d=Object(this);var a=d.length>>>0;if(a===0){return -1}var e=0;if(arguments.length>1){e=Number(arguments[1]);if(e!=e){e=0}else{if(e!=0&&e!=Infinity&&e!=-Infinity){e=(e>0||-1)*Math.floor(Math.abs(e))}}}if(e>=a){return -1}var b=e>=0?e:Math.max(a-Math.abs(e),0);for(;b<a;b++){if(b in d&&d[b]===c){return b}}return -1}}var b_onDomReplacementFinished_callbacks=new Array();function b_AddOnDomReplacementFinishedCallback(a){var b=jQuery(document).ooLog().isDebugEnabled();if(b){jQuery(document).ooLog("debug","callback stack size: "+b_onDomReplacementFinished_callbacks.length,"functions.js ADD")}if(b&&b_onDomReplacementFinished_callbacks.toSource){jQuery(document).ooLog("debug","stack content"+b_onDomReplacementFinished_callbacks.toSource(),"functions.js ADD")}b_onDomReplacementFinished_callbacks.push(a);if(b){jQuery(document).ooLog("debug","push to callback stack, func: "+a,"functions.js ADD")}}var b_changedDomEl=new Array();function b_AddOnDomReplacementFinishedUniqueCallback(a){if(a.constructor==Array){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","add: its an ARRAY! ","functions.js ADD")}if(b_onDomReplacementFinished_callbacks.search(a[0])){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","push to callback stack, already there!!: "+a[0],"functions.js ADD")}return}}b_AddOnDomReplacementFinishedCallback(a)}var o_debug_trid=0;function o_ainvoke(N){if(N==undefined){return}o_info.inainvoke=true;var I=N.cmdcnt;if(I>0){jQuery(document).trigger("oo.dom.replacement.before");b_changedDomEl=new Array();if(o_info.debug){o_debug_trid++}var y=N.cmds;for(var T=0;T<I;T++){var J=y[T];var A=J.cmd;var R=J.cda;var U=J.w;var c=this.window;var K;if(c){switch(A){case 1:var M=R.e;BLoader.executeGlobalJS(M,"o_ainvoker::jsexec");if(o_info.debug){o_log("c1: execute jscode: "+M)}case 2:var u=R.cc;var F=R.cps;for(var Q=0;Q<u;Q++){var m=F[Q];var h=m.cid;var P=m.cidvis;var H=m.cw;var x=m.hfrag;var O=m.jsol;var g=m.hdr;if(o_info.debug){o_log("c2: redraw: "+m.cname+" ("+h+") "+m.hfragsize+" bytes, listener(s): "+m.clisteners)}var W=g+"\n\n"+x;var C="";var S=false;var E="o_c"+h;var B=jQuery("#"+E);if(B==null||B.length==0){E="o_fi"+h;B=jQuery("#"+E);S=true}if(B!=null){var w=jQuery("div.o_richtext_mce textarea",B);for(var L=0;L<w.length;L++){try{var a=jQuery(w.get(L)).attr("id");if(typeof top.tinymce!=undefined){top.tinymce.remove("#"+a)}}catch(Z){if(window.console){console.log(Z)}}}if(P){B.css("display","")}else{B.css("display","none")}if(S||!H){B.replaceWith(W)}else{try{B.empty().html(W);if(W.length>0&&B.get(0).innerHTML==""){B.get(0).innerHTML=W}}catch(Z){if(window.console){console.log(Z)}if(window.console){console.log("Fragment",W)}}b_changedDomEl.push(E)}B=null;if(C!=""){C.each(function(e){BLoader.executeGlobalJS(e,"o_ainvoker::inscripts")})}if(O!=""){BLoader.executeGlobalJS(O,"o_ainvoker::jsol")}}}break;case 3:c.o2c=0;var X=R.rurl;c.o_afterserver();c.document.location.replace(X);break;case 5:c.o2c=0;var X=R.rurl;c.o_afterserver();c.document.location.replace(X);break;case 6:c.o2c=0;c.o_afterserver();break;case 7:var o=c.document.location;var z=o.protocol+"//"+o.hostname;if(o.port!=""){z+=":"+o.port}var v=R.cssrm;for(Q=0;Q<v.length;Q++){var D=v[Q];var G=D.id;var f=z+D.url;BLoader.unLoadCSS(f,G);if(o_info.debug){o_log("c7: rm css: id:"+G+" ,url:'"+f+"'")}}var V=R.cssadd;for(k=0;k<V.length;k++){var D=V[k];var G=D.id;var f=z+D.url;var n=D.pt;BLoader.loadCSS(f,G,n);if(o_info.debug){o_log("c7: add css: id:"+G+" ,url:'"+f+"'")}}var p=R.jsadd;for(l=0;l<p.length;l++){var D=p[l];var Y=D.before;if(jQuery.type(Y)==="string"){BLoader.executeGlobalJS(Y,"o_ainvoker::preJsAdd")}var f=D.url;var q=D.enc;if(jQuery.type(f)==="string"){BLoader.loadJS(f,q,true)}if(o_info.debug){o_log("c7: add js: "+f)}}break;default:if(o_info.debug){o_log("?: unknown command "+A)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in o_ainvoke(), ?: unknown command "+A,"functions.js")}break}}else{if(o_info.debug){o_log("could not find window??")}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in o_ainvoke(), could not find window??","functions.js")}}}var b=b_onDomReplacementFinished_callbacks.length;if(b_onDomReplacementFinished_callbacks.toSource&&jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","stack content"+b_onDomReplacementFinished_callbacks.toSource(),"functions.js")}for(mycounter=0;b>mycounter;mycounter++){if(mycounter>50){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stopped executing DOM replacement callback functions - to many functions::"+b_onDomReplacementFinished_callbacks.length,"functions.js")}break}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stacksize before shift: "+b_onDomReplacementFinished_callbacks.length,"functions.js")}var s=b_onDomReplacementFinished_callbacks.shift();if(typeof s.length==="number"){if(s[0]=="glosshighlighter"){var d=s[1];if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","arr fct: "+d,"functions.js")}s=d}}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Executing DOM replacement callback function #"+mycounter+" with timeout funct::"+s,"functions.js")}s();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stacksize after timeout: "+b_onDomReplacementFinished_callbacks.length,"functions.js")}}jQuery(document).trigger("oo.dom.replacement.after")}o_info.inainvoke=false}function clearAfterAjaxIframeCall(){if(o_info.linkbusy){o_afterserver()}}function showAjaxBusy(){setTimeout(function(){if(o_info.linkbusy){try{if(jQuery("#o_ajax_busy_backdrop").length==0){jQuery("#o_body").addClass("o_ajax_busy");jQuery("#o_ajax_busy").modal({show:true,backdrop:"static",keyboard:"false"});jQuery("#o_ajax_busy").after('<div id="o_ajax_busy_backdrop" class="modal-backdrop in"></div>');jQuery("#o_ajax_busy>.modal-backdrop").remove();jQuery("#o_ajax_busy_backdrop").css({"z-index":1200})}}catch(a){if(window.console){console.log(a)}}}},700)}function removeAjaxBusy(){try{jQuery("#o_body").removeClass("o_ajax_busy");jQuery("#o_ajax_busy_backdrop").remove();jQuery("#o_ajax_busy").modal("hide")}catch(a){if(window.console){console.log(a)}}}function setFormDirty(c){o2c=1;var a=document.getElementById(c);if(a!=null){var b=a.olat_fosm_0;if(b==null){b=a.olat_fosm}if(b){b.className="btn o_button_dirty"}}else{if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in setFormDirty, myForm was null for formId="+c,"functions.js")}}}function contextHelpWindow(a){helpWindow=window.open(a,"HelpWindow","height=760, width=940, left=0, top=0, location=no, menubar=no, resizable=yes, scrollbars=yes, toolbar=no");helpWindow.focus()}function o_openPopUp(b,d,c,a,f){attributes="height="+a+", width="+c+", resizable=yes, scrollbars=yes, left=100, top=100, ";if(f){attributes+="location=yes, menubar=yes, status=yes, toolbar=yes"}else{attributes+="location=no, menubar=no, status=no, toolbar=no"}var h;try{h=window.open(b,d,attributes)}catch(g){h=window.open(b,"OpenOLAT",attributes)}h.focus();if(o_info.linkbusy){o_afterserver()}}function b_handleFileUploadFormChange(e,b,d){var f=e.value;slashPos=f.lastIndexOf("/");if(slashPos!=-1){f=f.substring(slashPos+1)}slashPos=f.lastIndexOf("\\");if(slashPos!=-1){f=f.substring(slashPos+1)}b.value=f;if(d){d.className="o_button_dirty"}var c=e.form.elements;for(i=0;i<c.length;i++){var a=c[i];if(a.name==b.name&&i+1<c.length){c[i+1].focus()}}}function gotonode(a){try{if(typeof o_activateCourseNode!="undefined"){o_activateCourseNode(a)}else{if(opener&&typeof opener.o_activateCourseNode!="undefined"){opener.o_activateCourseNode(a)}else{if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in gotonode(), could not find main window","functions.js")}}}}catch(b){alert("Goto node error:"+b);if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in gotonode()::"+b.message,"functions.js")}}}function o_viewportHeight(){var a=jQuery(document).height();if(a>0){return a}else{return 600}}OPOL.getMainColumnsMaxHeight=function(){var m=0,f=0,a=0,c=0,h=0,b,g=jQuery("#o_main_left_content"),e=jQuery("#o_main_right_content"),d=jQuery("#o_main_center_content");if(g!="undefined"&&g!=null){m=g.outerHeight(true)}if(e!="undefined"&&e!=null){f=e.outerHeight(true)}if(d!="undefined"&&d!=null){a=d.outerHeight(true)}c=(m>f?m:f);c=(c>a?c:a);if(c>0){return c}b=jQuery("#o_main");if(b!="undefined"&&b!=null){h=b.height()}if(b>0){return b}return o_viewportHeight()};OPOL.adjustHeight=function(){try{var a=0;col1=jQuery("#o_main_left_content").outerHeight(true);col2=jQuery("#o_main_right_content").outerHeight(true);col3=jQuery("#o_main_center_content").outerHeight(true);a=Math.max(col1,col2,col3);if(col1!=null){jQuery("#o_main_left").css({"min-height":a+"px"})}if(col2!=null){jQuery("#o_main_right").css({"min-height":a+"px"})}if(col3!=null){jQuery("#o_main_center").css({"min-height":a+"px"})}}catch(b){if(window.console){console.log(b)}}};jQuery(window).resize(function(){clearTimeout(o_info.resizeId);o_info.resizeId=setTimeout(function(){jQuery(document).trigger("oo.window.resize.after")},500)});jQuery(document).on("oo.window.resize.after",OPOL.adjustHeight);jQuery(document).on("oo.dom.replacement.after",OPOL.adjustHeight);jQuery().ready(OPOL.adjustHeight);function o_scrollToElement(a){try{o_info.scrolling=true;jQuery("html, body").animate({scrollTop:jQuery(a).offset().top},333,function(d,c){o_info.scrolling=false})}catch(b){}}function o_popover(c,b,a){if(typeof(a)==="undefined"){a="bottom"}jQuery("#"+c).popover({placement:a,html:true,trigger:"click",container:"body",content:function(){return jQuery("#"+b).clone().html()}}).on("shown.bs.popover",function(){var d=function(f){jQuery("#"+c).popover("hide");jQuery("body").unbind("click",d)};setTimeout(function(){jQuery("body").on("click",d)},5)})}function o_popoverWithTitle(d,c,b,a){if(typeof(a)==="undefined"){a="bottom"}return jQuery("#"+d).popover({placement:a,html:true,title:b,trigger:"click",container:"body",content:function(){return jQuery("#"+c).clone().html()}}).on("shown.bs.popover",function(){var e=function(f){jQuery("#"+d).popover("destroy");jQuery("body").unbind("click",e)};setTimeout(function(){jQuery("body").on("click",e)},5)})}function o_shareLinkPopup(d,c,b){if(typeof(b)==="undefined"){b="top"}var a=jQuery("#"+d);a.popover({placement:b,html:true,trigger:"click",container:"body",content:c}).on("shown.bs.popover",function(){var e=function(f){if(jQuery(f.target).data("toggle")!=="popover"&&jQuery(f.target).parents(".popover.in").length===0){jQuery("#"+d).popover("hide");jQuery("body").unbind("click",e)}};setTimeout(function(){jQuery("body").on("click",e)},5)});a.attr("title",a.attr("data-original-title"))}function o_QRCodePopup(d,c,b){if(typeof(b)==="undefined"){b="top"}var a=jQuery("#"+d);a.popover({placement:b,html:true,trigger:"click",container:"body",content:'<div id="'+d+'_pop" class="o_qrcode"></div>'}).on("shown.bs.popover",function(){o_info.qr=o_QRCode(d+"_pop",(jQuery.isFunction(c)?c():c));var e=function(f){if(jQuery(f.target).data("toggle")!=="popover"&&jQuery(f.target).parents(".popover.in").length===0){jQuery("#"+d).popover("hide");jQuery("body").unbind("click",e)}};setTimeout(function(){jQuery("body").on("click",e)},5)}).on("hidden.bs.popover",function(){try{o_info.qr.clear();delete o_info.qr}catch(f){}});a.attr("title",a.attr("data-original-title"))}function o_QRCode(c,b){try{BLoader.loadJS(o_info.o_baseURI+"/js/jquery/qrcodejs/qrcode.min.js","utf8",true);return new QRCode(document.getElementById(c),b)}catch(a){return null}}function b_resizeIframeToMainMaxHeight(f){var d=jQuery("#"+f);if(d!="undefined"&&d!=null){var c=OPOL.getMainColumnsMaxHeight()-110;var b=o_viewportHeight()-100;b=b-d.offset().top;var e=jQuery("#b_footer");if(e!="undefined"&&e!=null){b=b-e.outerHeight(true)}var a=(b>c?b:c);d.height(a)}}var o_debu_oldcn,o_debu_oldtt;function o_debu_show(b,a){if(o_debu_oldcn){o_debu_hide(o_debu_oldcn,o_debu_oldtt)}jQuery(b).addClass("o_dev_m");jQuery(a).show();o_debu_oldtt=a;o_debu_oldcn=b}function o_debu_hide(b,a){jQuery(a).hide();jQuery(b).removeClass("o_dev_m")}function o_dbg_mark(a){var b=jQuery("#"+a);if(b){b.css("background-color","#FCFCB8");b.css("border","3px solid #00F")}}function o_dbg_unmark(a){var b=jQuery("#"+a);if(b){b.css("border","");b.css("background-color","")}}function o_clearConsole(){o_log_all="";o_log(null)}var o_log_all="";function o_log(b){if(b){o_log_all="\n"+o_debug_trid+"> "+b+o_log_all;o_log_all=o_log_all.substr(0,4000)}var a=jQuery("#o_debug_cons");if(a){if(o_log_all.length==4000){o_log_all=o_log_all+"\n... (stripped: to long)... "}a.value=o_log_all}if(!jQuery.type(window.console)==="undefined"){window.console.log(b)}}function o_logerr(a){o_log("ERROR:"+a)}function o_logwarn(a){o_log("WARN:"+a)}function showerror(c){var a="";for(var b in c){a+=b+": "+c[b]+"\n"}return"error detail:\n"+a}function o_ffEvent(f,e,d,n,o){var g,h,b,a;g=document.getElementById(e);h=g.value;g.value=d;b=document.getElementById(n);a=b.value;b.value=o;var c=jQuery("#"+f);var m=c.attr("enctype");if(m&&m.indexOf("multipart")==0){o_XHRSubmitMultipart(f)}else{if(document.forms[f].onsubmit()){document.forms[f].submit()}}g.value=h;b.value=a}function o_IQEvent(a){if(document.forms[a].onsubmit()){document.forms[a].submit()}}function o_TableMultiActionEvent(a,c){var b=jQuery("#o_mai_"+a);b.val(c);if(document.forms[a].onsubmit()){document.forms[a].submit()}b.val("")}function o_XHRSubmit(h){if(o_info.linkbusy){return false}o_beforeserver();var o=true;var a=jQuery("#"+h);var n=a.attr("enctype");if(n&&n.indexOf("multipart")==0){var g="openolat-submit-"+(""+Math.random()).substr(2);var d=o_createIFrame(g);document.body.appendChild(d);a.attr("target",d.name);return true}else{var f=a.serializeArray();if(arguments.length>1){var m=arguments.length;for(var e=1;e<m;e=e+2){if(m>e+1){var c=new Object();c.name=arguments[e];c.value=arguments[e+1];f[f.length]=c}}}var b=a.attr("action");jQuery.ajax(b,{type:"POST",data:f,cache:false,dataType:"json",success:function(s,v,r){try{o_ainvoke(s);if(o){var p=s.businessPath;var q=s.documentTitle;var u=s.historyPointId;if(p){o_pushState(u,q,p)}}}catch(t){if(window.console){console.log(t)}}finally{o_afterserver()}},error:o_onXHRError});return false}}function o_XHRSubmitMultipart(a){var c=jQuery("#"+a);var d="openolat-submit-"+(""+Math.random()).substr(2);var b=o_createIFrame(d);document.body.appendChild(b);c.attr("target",b.name);c.submit();c.attr("target","")}function o_createIFrame(b){var a=jQuery('<iframe name="'+b+'" id="'+b+'" src="about:blank" style="position: absolute; top: -9999px; left: -9999px;"></iframe>');return a[0]}function o_removeIframe(a){jQuery("#"+a).remove()}function o_showFormDirtyDialog(a){o_scrollToElement("#o_top");jQuery("#o_form_dirty_message").modal("show");jQuery("#o_form_dirty_message .o_form_dirty_ignore").on("click",function(){jQuery("#o_form_dirty_message").modal("hide");jQuery("#o_form_dirty_message .o_form_dirty_ignore").off();a()});return false}function o_ffXHREvent(h,e,s,g,p,t,f,m){if(t&&o2c==1){var d=Array.prototype.slice.call(arguments);d[5]=false;var u=function(){o_ffXHREvent.apply(window,d)};return o_showFormDirtyDialog(u)}else{if(!o2cl_noDirtyCheck()){return false}}o_beforeserver();var v=new Object();if(m){var b=jQuery("#"+h);var q=b.serializeArray();var o=q.length;for(var r=0;r<o;r++){var n=q[r];if(n.name!="dispatchuri"&&n.name!="dispatchevent"){v[n.name]=n.value}}}v.dispatchuri=s;v.dispatchevent=p;if(arguments.length>8){var a=arguments.length;for(var r=8;r<a;r=r+2){if(a>r+1){v[arguments[r]]=arguments[r+1]}}}var c=jQuery("#"+h).attr("action");jQuery.ajax(c,{type:"POST",data:v,cache:false,dataType:"json",success:function(z,C,y){try{o_ainvoke(z);if(f){var w=z.businessPath;var x=z.documentTitle;var B=z.historyPointId;if(w){o_pushState(B,x,w)}}}catch(A){if(window.console){console.log(A)}}finally{o_afterserver()}},error:o_onXHRError})}function o_ffXHRNFEvent(f,e,a,h,m){var c=new Object();c.dispatchuri=a;c.dispatchevent=m;if(arguments.length>5){var g=arguments.length;for(var d=5;d<g;d=d+2){if(g>d+1){c[arguments[d]]=arguments[d+1]}}}var b=jQuery("#"+f).attr("action");jQuery.ajax(b,{type:"POST",data:c,cache:false,dataType:"json",success:function(o,p,n){}})}function o_XHREvent(h,f,c){if(f&&o2c==1){var b=Array.prototype.slice.call(arguments);b[1]=false;var a=function(){o_XHREvent.apply(window,b)};return o_showFormDirtyDialog(a)}else{if(!o2cl_noDirtyCheck()){return false}}o_beforeserver();var e=new Object();if(arguments.length>3){var g=arguments.length;for(var d=3;d<g;d=d+2){if(g>d+1){e[arguments[d]]=arguments[d+1]}}}jQuery.ajax(h,{type:"POST",data:e,cache:false,dataType:"json",success:function(p,s,o){try{o_ainvoke(p);if(c){var m=p.businessPath;var n=p.documentTitle;var r=p.historyPointId;if(m){o_pushState(r,n,m)}}}catch(q){if(window.console){console.log(q)}}finally{o_afterserver()}},error:o_onXHRError});return false}function o_XHRNFEvent(d){var b=new Object();if(arguments.length>1){var c=arguments.length;for(var a=1;a<c;a=a+2){if(c>a+1){b[arguments[a]]=arguments[a+1]}}}jQuery.ajax(d,{type:"POST",data:b,cache:false,dataType:"json",success:function(f,g,e){},error:o_onXHRError})}function o_onXHRError(a,d,b){o_afterserver();if(401==a.status){var c=o_info.oo_noresponse.replace("reload.html",window.document.location.href);showMessageBox("error",o_info.oo_noresponse_title,c,undefined)}else{if(window.console){console.log("Error status 2",d,b,a.responseText);console.log(a)}}}function o_pushState(d,f,a){try{var b=new Object();b.businessPath=a;b.historyPointId=d;if(a!=null&&!(a.lastIndexOf("http",0)===0)&&!(a.lastIndexOf("https",0)===0)){a=o_info.serverUri+a}o_info.businessPath=a;if(!(typeof o_shareActiveSocialUrl==="undefined")){o_shareActiveSocialUrl()}if(window.history&&!(typeof window.history==="undefined")&&window.history.pushState){window.history.pushState(b,f,a)}else{window.location.hash=d}}catch(c){if(window.console){console.log(c,a)}}}function o_toggleMark(a){var b=jQuery("i",a).attr("class");if(b.indexOf("o_icon_bookmark_add")>=0){jQuery("i",a).removeClass("o_icon_bookmark_add").addClass("o_icon_bookmark")}else{jQuery("i",a).removeClass("o_icon_bookmark").addClass("o_icon_bookmark_add")}}function o_normalizeFilename(b){b=b.replace(/\s/g,"_");var f=["/",",",":","(",")"];for(var c=f.length;c-->0;){b=b.split(f[c]).join("_")}var a=["\u00C4","\u00D6","\u00DC","\u00E4","\u00F6","\u00E6","\u00FC","\u00DF","\u00F8","\u2205"],d=["Ae","Oe","Ue","ae","oe","ae","ue","ss","o","o"];for(var c=a.length;c-->0;){b=b.split(a[c]).join(d[c])}try{b=b.normalize("NFKD");b=b.replace("/p{InCombiningDiacriticalMarks}+/g","");b=b.replace("/W+/g","")}catch(g){if(window.console){console.log(g)}}return b}function setFlexiFormDirtyByListener(a){setFlexiFormDirty(a.data.formId,a.data.hideMessage)}function setFlexiFormDirty(b,c){var a=o3c.indexOf(b)>-1;if(!a){o3c.push(b)}jQuery("#"+b).each(function(){var d=jQuery(this).data("FlexiSubmit");if(d!=null){jQuery("#"+d).addClass("btn o_button_dirty");o2c=(c?0:1)}})}function o_ffRegisterSubmit(b,a){jQuery("#"+b).data("FlexiSubmit",a)}function dismissInfoBox(a){javascript:jQuery("#"+a).remove();return true}function showInfoBox(g,d){var c=Math.floor(Math.random()*65536).toString(16);var f='<div id="'+c+'" class="o_alert_info"><div class="alert alert-info clearfix o_sel_info_message"><a class="o_alert_close o_sel_info_close" href="javascript:;" onclick="dismissInfoBox(\''+c+'\')"><i class="o_icon o_icon_close"> </i></a><h3><i class="o_icon o_icon_info"> </i> '+g+"</h3><p>"+d+"</p></div></div>";var a=jQuery("#o_messages").prepend(f);var e=(d.length>150)?8000:((d.length>70)?6000:4000);var b=function(){jQuery("#"+c).transition({top:"-100%"},333,function(){jQuery("#"+c).remove()})};o_info.scrolling=true;jQuery("#"+c).show().transition({top:0},333);jQuery("#"+c).click(function(h){b()});o_scrollToElement("#o_top");g=null;d=null;a=null;setTimeout(function(){try{b()}catch(h){}},e)}function showMessageBox(b,f,d,a){if(b=="info"){showInfoBox(f,d);return null}else{var c='<div id="myFunctionalModal" class="modal fade" role="dialog"><div class="modal-dialog"><div class="modal-content">';c+='<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>';c+='<h4 class="modal-title">'+f+"</h4></div>";c+='<div class="modal-body alert ';if("warn"==b){c+="alert-warning"}else{if("error"==b){c+="alert-danger"}else{c+="alert-info"}}c+='"><p>'+d+"</p></div></div></div></div>";jQuery("#myFunctionalModal").remove();jQuery("body").append(c);var e=jQuery("#myFunctionalModal").modal("show").on("hidden.bs.modal",function(g){jQuery("#myFunctionalModal").remove()});o_scrollToElement("#o_top");return e}}function o_table_toggleCheck(d,c){var a=document.forms[d].elements.tb_ms;len=a.length;if(typeof(len)=="undefined"){a.checked=c}else{var b;for(b=0;b<len;b++){a[b].checked=c}}}function onTreeStartDrag(a,b){jQuery(a.target).addClass("o_dnd_proxy")}function onTreeStopDrag(a,b){jQuery(a.target).removeClass("o_dnd_proxy")}function onTreeDrop(g,h){var a=jQuery(h.draggable[0]);var f=jQuery(this);f.css({position:"",width:""});var c=f.droppable("option","endUrl");if(c.lastIndexOf("/")==(c.length-1)){c=c.substring(0,c.length-1)}var e=a.attr("id");var b=e.substring(2,e.length);c+="%3Atnidle%3A"+b;var d=f.attr("id");if(d.indexOf("ds")==0){c+="%3Asne%3Ayes"}else{if(d.indexOf("dt")==0){c+="%3Asne%3Aend"}}jQuery(".ui-droppable").each(function(m,n){jQuery(n).droppable("disable")});o_XHREvent(c+"/",false,false)}function treeAcceptDrop(a){return true}function treeAcceptDrop_notWithChildren(a){var c=false;var b=jQuery(a);var e=b.attr("id");if(e!=undefined&&(e.indexOf("dd")==0||e.indexOf("ds")==0||e.indexOf("dt")==0||e.indexOf("da")==0||e.indexOf("row")==0)){var g=jQuery(this);var m=g.attr("id");var d=e.substring(2,e.length);var f=m.substring(2,m.length);if(d!=f){var h=jQuery("#dd"+d).parents("li");if(h.length>0&&jQuery(h.get(0)).find("#dd"+f).length==0){c=true}}}return c}function treeAcceptDrop_portfolio(b){var d=false;var c=jQuery(b);var f=c.attr("id");if(treeNode_isDragNode(f)){var h=jQuery(this);var o=h.attr("id");var e=f.substring(2,f.length);var g=o.substring(2,o.length);var n=f.indexOf("ds")==0||f.indexOf("dt")==0;if(e!=g){var m=treeNode_portfolioType(c);var a=treeNode_portfolioType(h);if(m=="artefact"){if(a=="page"||a=="struct"||a=="artefact"){d=true}}else{if(m=="struct"){if(a=="page"||a=="struct"){d=true}}else{if(m=="page"){if(a=="map"||a=="page"){d=true}}}}}}return d}function treeNode_portfolioType(e){var c=jQuery(e.get(0));var d=treeNode_portfolioTypes(c);if(d==null){var a=c.parent("a");if(a.length>0){d=treeNode_portfolioTypes(jQuery(a.get(0)))}else{if(c.attr("id").indexOf("ds")==0){var b=c.prev("div");if(b.length>0){d=treeNode_portfolioTypes(b)}}else{if(c.attr("id").indexOf("dt")==0){var b=c.next("div");if(b.length>0){d=treeNode_portfolioTypes(b)}}}}}return d}function treeNode_portfolioTypes(a){if(a.find===undefined){return null}else{if(a.find(".o_ep_icon_struct").length>0||a.hasClass("o_ep_icon_struct")){return"struct"}else{if(a.find(".o_ep_icon_page").length>0||a.hasClass("o_ep_icon_page")){return"page"}else{if(a.find(".o_ep_icon_map").length>0||a.hasClass("o_ep_icon_map")){return"map"}else{if(a.find(".o_ep_artefact").length>0||a.hasClass("o_ep_artefact")){return"artefact"}}}}}return null}function treeNode_isDragNode(a){if(a!=undefined&&(a.indexOf("dd")==0||a.indexOf("ds")==0||a.indexOf("dt")==0||a.indexOf("da")==0||a.indexOf("row")==0)){return true}return false}function o_choice_toggleCheck(c,b){var d=document.forms[c].elements;len=d.length;if(typeof(len)=="undefined"){d.checked=b}else{var a;for(a=0;a<len;a++){if(d[a].type=="checkbox"&&d[a].getAttribute("class")=="o_checkbox"){d[a].checked=b}}}}function b_briefcase_isChecked(c,e){var b;var a=document.getElementById(c);var d=0;for(b=0;a.elements[b];b++){if(a.elements[b].type=="checkbox"&&a.elements[b].name=="paths"&&a.elements[b].checked){d++}}if(d<1){alert(e);return false}return true}function b_briefcase_toggleCheck(d,c){var a=document.getElementById(d);len=a.elements.length;var b;for(b=0;b<len;b++){if(a.elements[b].name=="paths"){a.elements[b].checked=c}}}function o_doPrint(){var d=jQuery("div.o_iframedisplay iframe");if(d.length>0){try{var a=d[0];frames[a.name].focus();frames[a.name].print();return}catch(c){for(i=0;frames.length>i;i++){a=frames[i];if(a.name=="oaa0"){continue}var b=document.getElementsByName(a.name)[0];if(b&&b.getAttribute("class")=="ext-shim"){continue}if(a.name!=""){try{frames[a.name].focus();frames[a.name].print()}catch(c){window.print()}return}}window.print()}}else{window.print()}}function b_attach_i18n_inline_editing(){jQuery("span.o_translation_i18nitem").hover(function(){jQuery(this.firstChild).show();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Entered i18nitem::"+this.firstChild,"functions.js:b_attach_i18n_inline_editing()")}},function(){jQuery("a.o_translation_i18nitem_launcher").hide();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Leaving i18nitem::"+this,"functions.js:b_attach_i18n_inline_editing()")}});jQuery("a.o_translation_i18nitem_launcher").hover(function(){var a=jQuery(this).parent("span.o_translation_i18nitem");a.effect("highlight")});b_AddOnDomReplacementFinishedCallback(b_attach_i18n_inline_editing)}function b_hideExtMessageBox(){}var BDebugger={_lastDOMCount:0,_lastObjCount:0,_knownGlobalOLATObjects:["o_afterserver","o_onc","o_getMainWin","o_ainvoke","o_info","o_beforeserver","o_ffEvent","o_openPopUp","o_debu_show","o_logwarn","o_dbg_unmark","o_ffRegisterSubmit","o_clearConsole","o_init","o_log","o_allowNextClick","o_dbg_mark","o_debu_hide","o_logerr","o_debu_oldcn","o_debu_oldtt","o_debug_trid","o_log_all"],_countDOMElements:function(){return document.getElementsByTagName("*").length},_countGlobalObjects:function(){var a=0;for(prop in window){a++}return a},logDOMCount:function(){var b=BDebugger;var a=b._countDOMElements();var c=a-b._lastDOMCount;console.log((c>0?"+":"")+c+" \t"+a+" \tDOM element count after DOM replacement");b._lastDOMCount=a;a=null},logGlobalObjCount:function(){var b=BDebugger;var a=b._countGlobalObjects();var c=a-b._lastObjCount;console.log((c>0?"+":"")+c+" \t"+a+" \tGlobal object count after DOM replacement");b._lastObjCount=a;a=null},logGlobalOLATObjects:function(){var b=BDebugger;var a=new Array();for(prop in window){if(prop.indexOf("o_")==0&&b._knownGlobalOLATObjects.indexOf(prop)==-1){a.push(prop)}}if(a.length>0){console.log(a.length+" global OLAT objects found:");a.each(function(c){console.log("\t"+typeof window[c]+" \t"+c)})}}};/*! * jQuery Transit - CSS3 transitions and transformations * (c) 2011-2014 Rico Sta. Cruz * MIT Licensed. diff --git a/src/main/webapp/static/js/openolat/iframe.js b/src/main/webapp/static/js/openolat/iframe.js index fe2833f4ed4dcad03e586c39a06e0c9a12546abd..78e7442fcdc87f2b86baf2eacdbe59ab14698c87 100644 --- a/src/main/webapp/static/js/openolat/iframe.js +++ b/src/main/webapp/static/js/openolat/iframe.js @@ -178,7 +178,7 @@ function b_sendNewUriEventToParent() { } function b_addOnloadEvent(fnc){ -//console.log("b_addOnloadEvent window.name=" + window.name + " b_iframeid=" + b_iframeid + " fnc=" + fnc); + //console.log("b_addOnloadEvent window.name=" + window.name + " b_iframeid=" + b_iframeid + " fnc=" + fnc); try { // Only continue if we can locate the main window var mainwindow = b_getMainWindow(window.parent); @@ -211,29 +211,31 @@ function b_anchorFirefoxWorkaround() { var anchors = document.getElementsByTagName('a'); for (var i=0; i < anchors.length; i++) { var anchor = anchors[i]; - var href = anchor.getAttribute('href'); - if(href && href[0] == "#") { - var name = href.substring(1); - anchor.addEventListener('click', function() { - try { - var nameElement = document.getElementsByName(name); - var element = null; - if(nameElement != null && nameElement.length > 0) { + var href = anchor.getAttribute('href'); + if(href && href[0] == "#") { + anchor.addEventListener('click', function(el) { + try { + var href = el.target.getAttribute('href'); + var name = href.substring(1); + var nameElement = document.getElementsByName(name); + + var element = null; + if(nameElement != null && nameElement.length > 0) { element = nameElement[0]; - } else { - var idElement = document.getElementById(name); - if(idElement != null) { - element = idElement; - } - } - if(element && window && window.parent) { + } else { + var idElement = document.getElementById(name); + if(idElement != null) { + element = idElement; + } + } + if(element && window && window.parent) { var offset = b_anchorFirefoxWorkaroundCumulativeOffset(element); window.parent.scrollTo(offset[0], offset[1]); - } - } catch(e) { - //console.log(e); - } - return true; + } + } catch(e) { + //console.log(e); + } + return true; }); } } diff --git a/src/main/webapp/static/js/tinymce4/tinymce/plugins/olatcharcount/plugin.js b/src/main/webapp/static/js/tinymce4/tinymce/plugins/olatcharcount/plugin.js new file mode 100644 index 0000000000000000000000000000000000000000..e2c42689c5e02af37779577886ee09f788f254e3 --- /dev/null +++ b/src/main/webapp/static/js/tinymce4/tinymce/plugins/olatcharcount/plugin.js @@ -0,0 +1,105 @@ +(function() { + tinymce.create('org.olat.core.gui.components.form.flexible.impl.elements.richText.plugins.charcount', { + + /** + * Returns information about the plugin as a name/value array. + * The current keys are longname, author, authorurl, infourl and version. + * + * @returns Name/value array containing information about the plugin. + * @type Array + */ + getInfo : function() { + return { + longname : 'OpenOLAT character counter', + author : 'frentix GmbH', + authorurl : 'http://www.frentix.com', + infourl : 'http://www.frentix.com', + version : '1.0.1' + }; + }, + + /** + * Not used, adButton used instead + */ + createControl : function(n, cm) { + return null; + }, + + /** + * Initializes the plugin, this will be executed after the plugin has been created. + * This call is done before the editor instance has finished it's initialization so use the onInit event + * of the editor instance to intercept that event. + * + * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in. + * @param {string} url Absolute URL to where the plugin is located. + */ + init : function(ed, url) { + + var cachedTrans; + + // Load the OLAT translator. + function translator() { + if(cachedTrans) return cachedTrans; + var mainWin = o_getMainWin(); + if (mainWin) { + cachedTrans = jQuery(document).ooTranslator().getTranslator(mainWin.o_info.locale, 'org.olat.core.gui.components.form.flexible.impl.elements.richText.plugins.olatcharcount'); + } else { + cachedTrans = { translate : function(key) { return key; } } + } + return cachedTrans; + } + + function getCharacterLength() { + var text = ed.getContent({format: 'html'}); + text = text.trim().replace(/(\n)+/g, " "); + return text.length; + } + + function update() { + var count = getCharacterLength(); + var label = translator().translate('olatcharcount.size') + "\u00A0"; + ed.theme.panel.find('#wordcount').text([label, count]); + var maxSize = ed.getParam("maxSize"); + if(count > maxSize) { + ed.theme.panel.find('#statusbar').addClass('danger'); + } else { + ed.theme.panel.find('#statusbar').removeClass('danger'); + } + } + + // Load Content CSS upon initialization + ed.on('init', function() { + var statusbar = ed.theme.panel && ed.theme.panel.find('#statusbar')[0]; + if (statusbar) { + window.setTimeout(function() { + var label = translator().translate('olatcharcount.size') + "\u00A0"; + var tooltip = translator().translate('olatcharcount.tooltip'); + statusbar.insert({ + type: 'label', + name: 'wordcount', + text: [label, getCharacterLength()], + classes: 'wordcount', + tooltip: tooltip, + disabled: ed.settings.readonly + }, 0); + + ed.on('setcontent beforeaddundo undo redo', function() { + update(); + }); + + var sizer = jQuery.periodic({period: 5000, decay:1.000, max_period: Number.MAX_VALUE}, function() { + try { + update(); + } catch (e) { + sizer.cancel(); //error if the editor is removed + } + }); + }, 0); + } + }); + } + }); + + // Register plugin + tinymce.PluginManager.add('olatcharcount', org.olat.core.gui.components.form.flexible.impl.elements.richText.plugins.charcount); +})(); \ No newline at end of file diff --git a/src/main/webapp/static/js/tinymce4/tinymce/plugins/olatcharcount/plugin.min.js b/src/main/webapp/static/js/tinymce4/tinymce/plugins/olatcharcount/plugin.min.js new file mode 100644 index 0000000000000000000000000000000000000000..9a281d1850a85656f43e257ad1d5a74820381d1b --- /dev/null +++ b/src/main/webapp/static/js/tinymce4/tinymce/plugins/olatcharcount/plugin.min.js @@ -0,0 +1 @@ +(function(){tinymce.create("org.olat.core.gui.components.form.flexible.impl.elements.richText.plugins.charcount",{getInfo:function(){return{longname:"OpenOLAT character counter",author:"frentix GmbH",authorurl:"http://www.frentix.com",infourl:"http://www.frentix.com",version:"1.0.1"}},createControl:function(b,a){return null},init:function(a,c){var d;function b(){if(d){return d}var g=o_getMainWin();if(g){d=jQuery(document).ooTranslator().getTranslator(g.o_info.locale,"org.olat.core.gui.components.form.flexible.impl.elements.richText.plugins.olatcharcount")}else{d={translate:function(h){return h}}}return d}function e(){var g=a.getContent({format:"html"});g=g.trim().replace(/(\n)+/g," ");return g.length}function f(){var h=e();var g=b().translate("olatcharcount.size")+"\u00A0";a.theme.panel.find("#wordcount").text([g,h]);var i=a.getParam("maxSize");if(h>i){a.theme.panel.find("#statusbar").addClass("danger")}else{a.theme.panel.find("#statusbar").removeClass("danger")}}a.on("init",function(){var g=a.theme.panel&&a.theme.panel.find("#statusbar")[0];if(g){window.setTimeout(function(){var h=b().translate("olatcharcount.size")+"\u00A0";var j=b().translate("olatcharcount.tooltip");g.insert({type:"label",name:"wordcount",text:[h,e()],classes:"wordcount",tooltip:j,disabled:a.settings.readonly},0);a.on("setcontent beforeaddundo undo redo",function(){f()});var i=jQuery.periodic({period:5000,decay:1,max_period:Number.MAX_VALUE},function(){try{f()}catch(k){i.cancel()}})},0)}})}});tinymce.PluginManager.add("olatcharcount",org.olat.core.gui.components.form.flexible.impl.elements.richText.plugins.charcount)})(); \ No newline at end of file diff --git a/src/main/webapp/static/movie/README b/src/main/webapp/static/movie/README index caccc126877cf6a20e3e026a6a419380525118f3..bb52fb05a33ff5a522cd6a7700261a7a92a8d7fa 100644 --- a/src/main/webapp/static/movie/README +++ b/src/main/webapp/static/movie/README @@ -2,4 +2,39 @@ The main library is MediaElement.js, there is a fallback the JWPlayer for some rtmp streams. mediaelement-and-player.min.js is slightly modified to support AAC even in flash fallback. -This AAC type support is added automatically by the BPlayer code after loading. \ No newline at end of file +This AAC type support is added automatically by the BPlayer code after loading. + +This is a slightly modified 4.1.2 version. The patch need to be applied against +mediaelement 4.1.2 and mediaelement need to be compiled with grunt. After that, +you can copy the mediaelement-and-player.js and mediaelement-and-player.min.js +in OpenOLAT. + + +diff --git a/src/js/renderers/flv.js b/src/js/renderers/flv.js +index 1cda6a6..7681114 100644 +--- a/src/js/renderers/flv.js ++++ b/src/js/renderers/flv.js +@@ -64,6 +64,7 @@ + // To modify more elements from FLV player, + // see https://github.com/Bilibili/flv.js/blob/master/docs/api.md#config + cors: true, ++ withCredentials: true, + debug: false + } + }, +@@ -117,6 +118,7 @@ + flvOptions.cors = options.flv.cors; + flvOptions.debug = options.flv.debug; + flvOptions.path = options.flv.path; ++ flvOptions.withCredentials = options.flv.withCredentials; + + flvPlayer.destroy(); + flvPlayer = NativeFlv._createPlayer({ +@@ -184,6 +186,7 @@ + flvOptions.cors = options.flv.cors; + flvOptions.debug = options.flv.debug; + flvOptions.path = options.flv.path; ++ flvOptions.withCredentials = options.flv.withCredentials; + + NativeFlv.load({ + options: flvOptions, diff --git a/src/main/webapp/static/movie/mediaelementjs/mediaelement-and-player.js b/src/main/webapp/static/movie/mediaelementjs/mediaelement-and-player.js index ecdca0876f3257f48d03c444f34b5668156c733c..924ba912b3dfc8c011a45e1fed338b3a297ae087 100755 --- a/src/main/webapp/static/movie/mediaelementjs/mediaelement-and-player.js +++ b/src/main/webapp/static/movie/mediaelementjs/mediaelement-and-player.js @@ -16,31 +16,37 @@ var topLevel = typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : {} var minDoc = _dereq_(1); +var doccy; + if (typeof document !== 'undefined') { - module.exports = document; + doccy = document; } else { - var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; + doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; if (!doccy) { doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; } - - module.exports = doccy; } +module.exports = doccy; + }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"1":1}],3:[function(_dereq_,module,exports){ (function (global){ +var win; + if (typeof window !== "undefined") { - module.exports = window; + win = window; } else if (typeof global !== "undefined") { - module.exports = global; + win = global; } else if (typeof self !== "undefined"){ - module.exports = self; + win = self; } else { - module.exports = {}; + win = {}; } +module.exports = win; + }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],4:[function(_dereq_,module,exports){ 'use strict'; @@ -2718,17 +2724,6 @@ Object.assign(_player2.default.prototype, { e.preventDefault(); e.stopPropagation(); - }, - toggleMute = function toggleMute() { - if (media.muted) { - positionVolumeHandle(0); - (0, _dom.removeClass)(mute, t.options.classPrefix + 'mute'); - (0, _dom.addClass)(mute, t.options.classPrefix + 'unmute'); - } else { - positionVolumeHandle(media.volume); - (0, _dom.removeClass)(mute, t.options.classPrefix + 'unmute'); - (0, _dom.addClass)(mute, t.options.classPrefix + 'mute'); - } }; mute.addEventListener('mouseenter', function (e) { @@ -2828,7 +2823,15 @@ Object.assign(_player2.default.prototype, { media.addEventListener('volumechange', function (e) { if (!mouseIsDown) { - toggleMute(); + if (media.muted) { + positionVolumeHandle(0); + (0, _dom.removeClass)(mute, t.options.classPrefix + 'mute'); + (0, _dom.addClass)(mute, t.options.classPrefix + 'unmute'); + } else { + positionVolumeHandle(media.volume); + (0, _dom.removeClass)(mute, t.options.classPrefix + 'unmute'); + (0, _dom.addClass)(mute, t.options.classPrefix + 'mute'); + } } updateVolumeSlider(e); }); @@ -2838,9 +2841,8 @@ Object.assign(_player2.default.prototype, { if (!modified) { setTimeout(function () { rendered = true; - if (player.options.startVolume === 0 || media.originalNode.muted) { + if (player.options.startVolume === 0) { media.setMuted(true); - player.options.startVolume = 0; } media.setVolume(player.options.startVolume); t.setControlsSize(); @@ -2851,9 +2853,8 @@ Object.assign(_player2.default.prototype, { media.addEventListener('loadedmetadata', function () { setTimeout(function () { if (!modified && !rendered) { - if (player.options.startVolume === 0 || media.originalNode.muted) { + if (player.options.startVolume === 0) { media.setMuted(true); - player.options.startVolume = 0; } media.setVolume(player.options.startVolume); t.setControlsSize(); @@ -2862,16 +2863,22 @@ Object.assign(_player2.default.prototype, { }, 250); }); - if (player.options.startVolume === 0 || media.originalNode.muted) { + if (player.options.startVolume === 0) { media.setMuted(true); - player.options.startVolume = 0; - toggleMute(); } media.setVolume(player.options.startVolume); t.container.addEventListener('controlsresize', function () { - toggleMute(); + if (media.muted) { + positionVolumeHandle(0); + (0, _dom.removeClass)(mute, t.options.classPrefix + 'mute'); + (0, _dom.addClass)(mute, t.options.classPrefix + 'unmute'); + } else { + positionVolumeHandle(media.volume); + (0, _dom.removeClass)(mute, t.options.classPrefix + 'unmute'); + (0, _dom.addClass)(mute, t.options.classPrefix + 'mute'); + } }); } }); @@ -3268,13 +3275,6 @@ var MediaElementPlayer = function () { t.options = Object.assign({}, config, o); - if (t.options.loop && !t.media.getAttribute('loop')) { - t.media.loop = true; - t.node.loop = true; - } else if (t.media.loop) { - t.options.loop = true; - } - if (!t.options.timeFormat) { t.options.timeFormat = 'mm:ss'; if (t.options.alwaysShowHours) { @@ -4948,7 +4948,7 @@ var DashNativeRenderer = { dashEvents = dashjs.MediaPlayer.events, assignEvents = function assignEvents(eventName) { if (eventName === 'loadedmetadata') { - dashPlayer.initialize(node, null, autoplay); + dashPlayer.initialize(node, null, preload && preload === 'auto' || autoplay); dashPlayer.setFastSwitchEnabled(true); if (!_mejs2.default.Utils.isObjectEmpty(options.dash.drm)) { @@ -5130,8 +5130,6 @@ var FlashMediaElementRenderer = { create: function create(mediaElement, options, mediaFiles) { var flash = {}; - - console.log('FlashMediaElementRenderer.create'); flash.options = options; flash.id = mediaElement.id + '_' + flash.options.prefix; @@ -5221,9 +5219,6 @@ var FlashMediaElementRenderer = { for (var _i = 0, _total = methods.length; _i < _total; _i++) { assignMethods(methods[_i]); } - - - console.log('FlashMediaElementRenderer.create 2'); var initEvents = ['rendererready']; @@ -5336,12 +5331,10 @@ var FlashMediaElementRenderer = { flash.flashNode.remove(); }; - console.log('File ' + mediaFiles); if (mediaFiles && mediaFiles.length > 0) { for (var _i4 = 0, _total4 = mediaFiles.length; _i4 < _total4; _i4++) { if (_renderer.renderer.renderers[options.prefix].canPlayType(mediaFiles[_i4].type)) { flash.setSrc(mediaFiles[_i4].src); - console.log('File ' + mediaFiles[_i4].src); break; } } @@ -5435,7 +5428,6 @@ if (hasFlash) { }, canPlayType: function canPlayType(type) { - console.log('Can play mp3 flash'); return ~['audio/mp3'].indexOf(type.toLowerCase()); }, @@ -5516,6 +5508,7 @@ var FlvNativeRenderer = { path: 'https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.2.0/flv.min.js', cors: true, + withCredentials: true, debug: false } }, @@ -5555,6 +5548,7 @@ var FlvNativeRenderer = { _flvOptions.cors = options.flv.cors; _flvOptions.debug = options.flv.debug; _flvOptions.path = options.flv.path; + _flvOptions.withCredentials = options.flv.withCredentials; flvPlayer.destroy(); flvPlayer = NativeFlv._createPlayer({ @@ -5617,6 +5611,7 @@ var FlvNativeRenderer = { flvOptions.cors = options.flv.cors; flvOptions.debug = options.flv.debug; flvOptions.path = options.flv.path; + flvOptions.withCredentials = options.flv.withCredentials; NativeFlv.load({ options: flvOptions, @@ -6394,12 +6389,9 @@ var YouTubeIframeRenderer = { youTubeIframe = youTubeApi.getIframe(); - if (mediaElement.originalNode.getAttribute('muted')) { - youTubeApi.mute(); - } - var events = ['mouseover', 'mouseout'], assignEvents = function assignEvents(e) { + var newEvent = (0, _general.createEvent)(e.type, youtube); mediaElement.dispatchEvent(newEvent); }; @@ -6427,10 +6419,8 @@ var YouTubeIframeRenderer = { case 0: events = ['ended']; paused = false; - ended = !youtube.options.youtube.loop; - if (!youtube.options.youtube.loop) { - youtube.stopInterval(); - } + ended = true; + youtube.stopInterval(); break; case 1: events = ['play', 'playing']; @@ -6472,14 +6462,6 @@ var YouTubeIframeRenderer = { youtubeSettings.playerVars.playsinline = 1; } - if (mediaElement.originalNode.autoplay) { - youtubeSettings.playerVars.autoplay = 1; - } - - if (mediaElement.originalNode.loop) { - youtubeSettings.playerVars.loop = 1; - } - YouTubeApi.enqueueIframe(youtubeSettings); youtube.onEvent = function (eventName, player, _youTubeState) { @@ -6512,6 +6494,7 @@ var YouTubeIframeRenderer = { youtube.startInterval = function () { youtube.interval = setInterval(function () { + var event = (0, _general.createEvent)('timeupdate', youtube); mediaElement.dispatchEvent(event); }, 250); diff --git a/src/main/webapp/static/movie/mediaelementjs/mediaelement-and-player.min.js b/src/main/webapp/static/movie/mediaelementjs/mediaelement-and-player.min.js index e9325a069bc022e8b6001360e4aafac49d52d5e3..f52cad0c50e7235987c6b694214ee4c5c6e23190 100755 --- a/src/main/webapp/static/movie/mediaelementjs/mediaelement-and-player.min.js +++ b/src/main/webapp/static/movie/mediaelementjs/mediaelement-and-player.min.js @@ -9,4 +9,4 @@ * License: MIT * */ -!function e(t,n,i){function o(r,s){if(!n[r]){if(!t[r]){var l="function"==typeof require&&require;if(!s&&l)return l(r,!0);if(a)return a(r,!0);var d=new Error("Cannot find module '"+r+"'");throw d.code="MODULE_NOT_FOUND",d}var u=n[r]={exports:{}};t[r][0].call(u.exports,function(e){var n=t[r][1][e];return o(n||e)},u,u.exports,e,t,n,i)}return n[r].exports}for(var a="function"==typeof require&&require,r=0;r<i.length;r++)o(i[r]);return o}({1:[function(e,t,n){},{}],2:[function(e,t,n){(function(n){var i=void 0!==n?n:"undefined"!=typeof window?window:{},o=e(1);if("undefined"!=typeof document)t.exports=document;else{var a=i["__GLOBAL_DOCUMENT_CACHE@4"];a||(a=i["__GLOBAL_DOCUMENT_CACHE@4"]=o),t.exports=a}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1}],3:[function(e,t,n){(function(e){"undefined"!=typeof window?t.exports=window:void 0!==e?t.exports=e:"undefined"!=typeof self?t.exports=self:t.exports={}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],4:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o=function(e){return e&&e.__esModule?e:{default:e}}(e(6)),a=e(14),r=e(25),s={lang:"en",en:a.EN};s.language=function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];if(null!==t&&void 0!==t&&t.length){if("string"!=typeof t[0])throw new TypeError("Language code must be a string value");if(!/^[a-z]{2}(\-[a-z]{2})?$/i.test(t[0]))throw new TypeError("Language code must have format `xx` or `xx-xx`");s.lang=t[0],void 0===s[t[0]]?(t[1]=null!==t[1]&&void 0!==t[1]&&"object"===i(t[1])?t[1]:{},s[t[0]]=(0,r.isObjectEmpty)(t[1])?a.EN:t[1]):null!==t[1]&&void 0!==t[1]&&"object"===i(t[1])&&(s[t[0]]=t[1])}return s.lang},s.t=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if("string"==typeof e&&e.length){var n=void 0,o=void 0,a=s.language(),l=function(e,t,n){return"object"!==(void 0===e?"undefined":i(e))||"number"!=typeof t||"number"!=typeof n?e:function(){return[function(){return arguments.length<=1?void 0:arguments[1]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:arguments.length<=2?void 0:arguments[2]},function(){return 0===(arguments.length<=0?void 0:arguments[0])||1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:arguments.length<=2?void 0:arguments[2]},function(){return(arguments.length<=0?void 0:arguments[0])%10==1&&(arguments.length<=0?void 0:arguments[0])%100!=11?arguments.length<=1?void 0:arguments[1]:0!==(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 1===(arguments.length<=0?void 0:arguments[0])||11===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:2===(arguments.length<=0?void 0:arguments[0])||12===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:(arguments.length<=0?void 0:arguments[0])>2&&(arguments.length<=0?void 0:arguments[0])<20?arguments.length<=3?void 0:arguments[3]:arguments.length<=4?void 0:arguments[4]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:0===(arguments.length<=0?void 0:arguments[0])||(arguments.length<=0?void 0:arguments[0])%100>0&&(arguments.length<=0?void 0:arguments[0])%100<20?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return(arguments.length<=0?void 0:arguments[0])%10==1&&(arguments.length<=0?void 0:arguments[0])%100!=11?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10>=2&&((arguments.length<=0?void 0:arguments[0])%100<10||(arguments.length<=0?void 0:arguments[0])%100>=20)?arguments.length<=2?void 0:arguments[2]:[3]},function(){return(arguments.length<=0?void 0:arguments[0])%10==1&&(arguments.length<=0?void 0:arguments[0])%100!=11?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10>=2&&(arguments.length<=0?void 0:arguments[0])%10<=4&&((arguments.length<=0?void 0:arguments[0])%100<10||(arguments.length<=0?void 0:arguments[0])%100>=20)?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])>=2&&(arguments.length<=0?void 0:arguments[0])<=4?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10>=2&&(arguments.length<=0?void 0:arguments[0])%10<=4&&((arguments.length<=0?void 0:arguments[0])%100<10||(arguments.length<=0?void 0:arguments[0])%100>=20)?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return(arguments.length<=0?void 0:arguments[0])%100==1?arguments.length<=2?void 0:arguments[2]:(arguments.length<=0?void 0:arguments[0])%100==2?arguments.length<=3?void 0:arguments[3]:(arguments.length<=0?void 0:arguments[0])%100==3||(arguments.length<=0?void 0:arguments[0])%100==4?arguments.length<=4?void 0:arguments[4]:arguments.length<=1?void 0:arguments[1]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:2===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:(arguments.length<=0?void 0:arguments[0])>2&&(arguments.length<=0?void 0:arguments[0])<7?arguments.length<=3?void 0:arguments[3]:(arguments.length<=0?void 0:arguments[0])>6&&(arguments.length<=0?void 0:arguments[0])<11?arguments.length<=4?void 0:arguments[4]:arguments.length<=5?void 0:arguments[5]},function(){return 0===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:2===(arguments.length<=0?void 0:arguments[0])?arguments.length<=3?void 0:arguments[3]:(arguments.length<=0?void 0:arguments[0])%100>=3&&(arguments.length<=0?void 0:arguments[0])%100<=10?arguments.length<=4?void 0:arguments[4]:(arguments.length<=0?void 0:arguments[0])%100>=11?arguments.length<=5?void 0:arguments[5]:arguments.length<=6?void 0:arguments[6]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:0===(arguments.length<=0?void 0:arguments[0])||(arguments.length<=0?void 0:arguments[0])%100>1&&(arguments.length<=0?void 0:arguments[0])%100<11?arguments.length<=2?void 0:arguments[2]:(arguments.length<=0?void 0:arguments[0])%100>10&&(arguments.length<=0?void 0:arguments[0])%100<20?arguments.length<=3?void 0:arguments[3]:arguments.length<=4?void 0:arguments[4]},function(){return(arguments.length<=0?void 0:arguments[0])%10==1?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10==2?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 11!==(arguments.length<=0?void 0:arguments[0])&&(arguments.length<=0?void 0:arguments[0])%10==1?arguments.length<=1?void 0:arguments[1]:arguments.length<=2?void 0:arguments[2]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10>=2&&(arguments.length<=0?void 0:arguments[0])%10<=4&&((arguments.length<=0?void 0:arguments[0])%100<10||(arguments.length<=0?void 0:arguments[0])%100>=20)?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:2===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:8!==(arguments.length<=0?void 0:arguments[0])&&11!==(arguments.length<=0?void 0:arguments[0])?arguments.length<=3?void 0:arguments[3]:arguments.length<=4?void 0:arguments[4]},function(){return 0===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:arguments.length<=2?void 0:arguments[2]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:2===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:3===(arguments.length<=0?void 0:arguments[0])?arguments.length<=3?void 0:arguments[3]:arguments.length<=4?void 0:arguments[4]},function(){return 0===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]}]}()[n].apply(null,[t].concat(e))};return void 0!==s[a]&&(n=s[a][e],null!==t&&"number"==typeof t&&(o=s[a]["mejs.plural-form"],n=l.apply(null,[n,t,o]))),!n&&s.en&&(n=s.en[e],null!==t&&"number"==typeof t&&(o=s.en["mejs.plural-form"],n=l.apply(null,[n,t,o]))),n=n||e,null!==t&&"number"==typeof t&&(n=n.replace("%1",t)),(0,r.escapeHTML)(n)}return e},o.default.i18n=s,"undefined"!=typeof mejsL10n&&o.default.i18n.language(mejsL10n.language,mejsL10n.strings),n.default=s},{14:14,25:25,6:6}],5:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r=i(e(3)),s=i(e(2)),l=i(e(6)),d=e(25),u=e(26),c=e(7),f=e(23),p=function e(t,n,i){var p=this;o(this,e);var m=this;i=Array.isArray(i)?i:null,m.defaults={renderers:[],fakeNodeName:"mediaelementwrapper",pluginPath:"build/",shimScriptAccess:"sameDomain",customError:""},n=Object.assign(m.defaults,n),m.mediaElement=s.default.createElement(n.fakeNodeName),m.mediaElement.options=n;var h=t,v=!1;if("string"==typeof t?m.mediaElement.originalNode=s.default.getElementById(t):(m.mediaElement.originalNode=t,h=t.id),h=h||"mejs_"+Math.random().toString().slice(2),void 0!==m.mediaElement.originalNode&&null!==m.mediaElement.originalNode&&m.mediaElement.appendChild){m.mediaElement.originalNode.setAttribute("id",h+"_from_mejs");var y=m.mediaElement.originalNode.tagName.toLowerCase();["video","audio"].indexOf(y)>-1&&!m.mediaElement.originalNode.getAttribute("preload")&&m.mediaElement.originalNode.setAttribute("preload","none"),m.mediaElement.originalNode.parentNode.insertBefore(m.mediaElement,m.mediaElement.originalNode),m.mediaElement.appendChild(m.mediaElement.originalNode)}m.mediaElement.id=h,m.mediaElement.renderers={},m.mediaElement.renderer=null,m.mediaElement.rendererName=null,m.mediaElement.changeRenderer=function(e,t){var n=p,i=Object.keys(t[0]).length>2?t[0]:t[0].src;if(void 0!==n.mediaElement.renderer&&null!==n.mediaElement.renderer&&n.mediaElement.renderer.name===e)return n.mediaElement.renderer.pause(),n.mediaElement.renderer.stop&&n.mediaElement.renderer.stop(),n.mediaElement.renderer.show(),n.mediaElement.renderer.setSrc(i),!0;void 0!==n.mediaElement.renderer&&null!==n.mediaElement.renderer&&(n.mediaElement.renderer.pause(),n.mediaElement.renderer.stop&&n.mediaElement.renderer.stop(),n.mediaElement.renderer.hide());var o=n.mediaElement.renderers[e],a=null;if(void 0!==o&&null!==o)return o.show(),o.setSrc(i),n.mediaElement.renderer=o,n.mediaElement.rendererName=e,!0;for(var r=n.mediaElement.options.renderers.length?n.mediaElement.options.renderers:c.renderer.order,s=0,l=r.length;s<l;s++){var d=r[s];if(d===e){a=c.renderer.renderers[d];var u=Object.assign(a.options,n.mediaElement.options);return o=a.create(n.mediaElement,u,t),o.name=e,n.mediaElement.renderers[a.name]=o,n.mediaElement.renderer=o,n.mediaElement.rendererName=e,o.show(),!0}}return!1},m.mediaElement.setSize=function(e,t){void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer&&m.mediaElement.renderer.setSize(e,t)},m.mediaElement.createErrorMessage=function(e){e=Array.isArray(e)?e:[];var t=s.default.createElement("div");t.className="me_cannotplay",t.style.width="100%",t.style.height="100%";var n=m.mediaElement.options.customError;if(!n){var i=m.mediaElement.originalNode.getAttribute("poster");i&&(n+='<img src="'+i+'" width="100%" height="100%" alt="'+l.default.i18n.t("mejs.download-file")+'">');for(var o=0,a=e.length;o<a;o++){var r=e[o];n+='<a href="'+r.src+'" data-type="'+r.type+'"><span>'+l.default.i18n.t("mejs.download-file")+": "+r.src+"</span></a>"}}t.innerHTML=n,m.mediaElement.originalNode.parentNode.insertBefore(t,m.mediaElement.originalNode),m.mediaElement.originalNode.style.display="none",v=!0};var g=l.default.html5media.properties,b=l.default.html5media.methods,E=function(e,t,n,i){var o=e[t],a=function(){return n.apply(e,[o])},r=function(t){return o=i.apply(e,[t])};Object.defineProperty(e,t,{get:a,set:r})},S=function(){return void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer?m.mediaElement.renderer.getSrc():null},x=function(e){var t=[];if("string"==typeof e)t.push({src:e,type:e?(0,u.getTypeFromFile)(e):""});else if("object"===(void 0===e?"undefined":a(e))&&void 0!==e.src){var n=(0,u.absolutizeUrl)(e.src),i=e.type,o=Object.assign(e,{src:n,type:""!==i&&null!==i&&void 0!==i||!n?i:(0,u.getTypeFromFile)(n)});t.push(o)}else if(Array.isArray(e))for(var r=0,s=e.length;r<s;r++){var l=(0,u.absolutizeUrl)(e[r].src),f=e[r].type,p=Object.assign(e[r],{src:l,type:""!==f&&null!==f&&void 0!==f||!l?f:(0,u.getTypeFromFile)(l)});t.push(p)}var h=c.renderer.select(t,m.mediaElement.options.renderers.length?m.mediaElement.options.renderers:[]),v=void 0;if(m.mediaElement.paused||(m.mediaElement.pause(),v=(0,d.createEvent)("pause",m.mediaElement),m.mediaElement.dispatchEvent(v)),m.mediaElement.originalNode.setAttribute("src",t[0].src||""),m.mediaElement.querySelector(".me_cannotplay")&&m.mediaElement.querySelector(".me_cannotplay").remove(),null===h)return m.mediaElement.createErrorMessage(t),v=(0,d.createEvent)("error",m.mediaElement),v.message="No renderer found",void m.mediaElement.dispatchEvent(v);m.mediaElement.changeRenderer(h.rendererName,t),void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer||((v=(0,d.createEvent)("error",m.mediaElement)).message="Error creating renderer",m.mediaElement.dispatchEvent(v),m.mediaElement.createErrorMessage(t))};E(m.mediaElement,"src",S,x),m.mediaElement.getSrc=S,m.mediaElement.setSrc=x;for(var w=0,P=g.length;w<P;w++)!function(e){if("src"!==e){var t=""+e.substring(0,1).toUpperCase()+e.substring(1),n=function(){return void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer&&"function"==typeof m.mediaElement.renderer["get"+t]?m.mediaElement.renderer["get"+t]():null},i=function(e){void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer&&"function"==typeof m.mediaElement.renderer["set"+t]&&m.mediaElement.renderer["set"+t](e)};E(m.mediaElement,e,n,i),m.mediaElement["get"+t]=n,m.mediaElement["set"+t]=i}}(g[w]);for(var T=0,C=b.length;T<C;T++)!function(e){m.mediaElement[e]=function(){for(var t=arguments.length,n=Array(t),i=0;i<t;i++)n[i]=arguments[i];if(void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer&&"function"==typeof m.mediaElement.renderer[e])try{m.mediaElement.renderer[e](n)}catch(e){m.mediaElement.createErrorMessage()}return null}}(b[T]);m.mediaElement.events={},m.mediaElement.addEventListener=function(e,t){m.mediaElement.events[e]=m.mediaElement.events[e]||[],m.mediaElement.events[e].push(t)},m.mediaElement.removeEventListener=function(e,t){if(!e)return m.mediaElement.events={},!0;var n=m.mediaElement.events[e];if(!n)return!0;if(!t)return m.mediaElement.events[e]=[],!0;for(var i=0;i<n.length;i++)if(n[i]===t)return m.mediaElement.events[e].splice(i,1),!0;return!1},m.mediaElement.dispatchEvent=function(e){var t=m.mediaElement.events[e.type];if(t)for(var n=0;n<t.length;n++)t[n].apply(null,[e])};var k=function(e,t){if(l.default.html5media.mediaTypes.indexOf(t)>-1&&"https:"===r.default.location.protocol&&f.IS_IOS&&!r.default.MSStream){var n=new XMLHttpRequest;n.onreadystatechange=function(){if(4===this.readyState&&200===this.status){var t=(r.default.URL||r.default.webkitURL).createObjectURL(this.response);return m.mediaElement.originalNode.setAttribute("src",t),t}return e},n.open("GET",e),n.responseType="blob",n.send()}return e},_=void 0;if(null!==i)_=i;else if(null!==m.mediaElement.originalNode)switch(_=[],m.mediaElement.originalNode.nodeName.toLowerCase()){case"iframe":_.push({type:"",src:m.mediaElement.originalNode.getAttribute("src")});break;case"audio":case"video":var N=m.mediaElement.originalNode.childNodes.length,A=m.mediaElement.originalNode.getAttribute("src");if(A){var L=m.mediaElement.originalNode,F=(0,u.formatType)(A,L.getAttribute("type"));_.push({type:F,src:k(A,F)})}for(var j=0;j<N;j++){var I=m.mediaElement.originalNode.childNodes[j];if(I.nodeType===Node.ELEMENT_NODE&&"source"===I.tagName.toLowerCase()){var M=I.getAttribute("src"),O=(0,u.formatType)(M,I.getAttribute("type"));_.push({type:O,src:k(M,O)})}}}return _.length&&(m.mediaElement.src=_),m.mediaElement.options.success&&m.mediaElement.options.success(m.mediaElement,m.mediaElement.originalNode),v&&m.mediaElement.options.error&&m.mediaElement.options.error(m.mediaElement,m.mediaElement.originalNode),m.mediaElement};r.default.MediaElement=p,n.default=p},{2:2,23:23,25:25,26:26,3:3,6:6,7:7}],6:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var i=function(e){return e&&e.__esModule?e:{default:e}}(e(3)),o={};o.version="4.1.2",o.html5media={properties:["volume","src","currentTime","muted","duration","paused","ended","buffered","error","networkState","readyState","seeking","seekable","currentSrc","preload","bufferedBytes","bufferedTime","initialTime","startOffsetTime","defaultPlaybackRate","playbackRate","played","autoplay","loop","controls"],readOnlyProperties:["duration","paused","ended","buffered","error","networkState","readyState","seeking","seekable"],methods:["load","play","pause","canPlayType"],events:["loadstart","progress","suspend","abort","error","emptied","stalled","play","pause","loadedmetadata","loadeddata","waiting","playing","canplay","canplaythrough","seeking","seeked","timeupdate","ended","ratechange","durationchange","volumechange"],mediaTypes:["audio/mp3","audio/ogg","audio/oga","audio/wav","audio/x-wav","audio/wave","audio/x-pn-wav","audio/mpeg","audio/mp4","video/mp4","video/webm","video/ogg","video/ogv"]},i.default.mejs=o,n.default=o},{3:3}],7:[function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0}),n.renderer=void 0;var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),r=function(e){return e&&e.__esModule?e:{default:e}}(e(6)),s=function(){function e(){i(this,e),this.renderers={},this.order=[]}return a(e,[{key:"add",value:function(e){if(void 0===e.name)throw new TypeError("renderer must contain at least `name` property");this.renderers[e.name]=e,this.order.push(e.name)}},{key:"select",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=t.length;if(t=t.length?t:this.order,!n){var i=[/^(html5|native)/i,/^flash/i,/iframe$/i],o=function(e){for(var t=0,n=i.length;t<n;t++)if(i[t].test(e))return t;return i.length};t.sort(function(e,t){return o(e)-o(t)})}for(var a=0,r=t.length;a<r;a++){var s=t[a],l=this.renderers[s];if(null!==l&&void 0!==l)for(var d=0,u=e.length;d<u;d++)if("function"==typeof l.canPlayType&&"string"==typeof e[d].type&&l.canPlayType(e[d].type))return{rendererName:l.name,src:e[d].src}}return null}},{key:"order",set:function(e){if(!Array.isArray(e))throw new TypeError("order must be an array of strings.");this._order=e},get:function(){return this._order}},{key:"renderers",set:function(e){if(null!==e&&"object"!==(void 0===e?"undefined":o(e)))throw new TypeError("renderers must be an array of objects.");this._renderers=e},get:function(){return this._renderers}}]),e}(),l=n.renderer=new s;r.default.Renderers=l},{6:6}],8:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(2)),r=i(e(4)),s=e(16),l=i(s),d=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}(e(23)),u=e(25),c=e(24);Object.assign(s.config,{usePluginFullScreen:!0,fullscreenText:null}),Object.assign(l.default.prototype,{isFullScreen:!1,isNativeFullScreen:!1,isInIframe:!1,isPluginClickThroughCreated:!1,fullscreenMode:"",containerSizeTimeout:null,buildfullscreen:function(e){if(e.isVideo){e.isInIframe=o.default.location!==o.default.parent.location,e.detectFullscreenMode();var t=this,n=(0,u.isString)(t.options.fullscreenText)?t.options.fullscreenText:r.default.t("mejs.fullscreen"),i=a.default.createElement("div");if(i.className=t.options.classPrefix+"button "+t.options.classPrefix+"fullscreen-button",i.innerHTML='<button type="button" aria-controls="'+t.id+'" title="'+n+'" aria-label="'+n+'" tabindex="0"></button>',t.addControlElement(i,"fullscreen"),i.addEventListener("click",function(){d.HAS_TRUE_NATIVE_FULLSCREEN&&d.IS_FULLSCREEN||e.isFullScreen?e.exitFullScreen():e.enterFullScreen()}),e.fullscreenBtn=i,t.globalBind("keydown",function(n){27===(n.which||n.keyCode||0)&&(d.HAS_TRUE_NATIVE_FULLSCREEN&&d.IS_FULLSCREEN||t.isFullScreen)&&e.exitFullScreen()}),t.normalHeight=0,t.normalWidth=0,d.HAS_TRUE_NATIVE_FULLSCREEN){var s=function(){e.isFullScreen&&(d.isFullScreen()?(e.isNativeFullScreen=!0,e.setControlsSize()):(e.isNativeFullScreen=!1,e.exitFullScreen()))};e.globalBind(d.FULLSCREEN_EVENT_NAME,s)}}},detectFullscreenMode:function(){var e=this,t=null!==e.media.rendererName&&/(native|html5)/i.test(e.media.rendererName),n="";return n=d.HAS_TRUE_NATIVE_FULLSCREEN&&t?"native-native":d.HAS_TRUE_NATIVE_FULLSCREEN&&!t?"plugin-native":e.usePluginFullScreen&&d.SUPPORT_POINTER_EVENTS?"plugin-click":"fullwindow",e.fullscreenMode=n,n},cleanfullscreen:function(e){e.exitFullScreen()},enterFullScreen:function(){var e=this,t=null!==e.media.rendererName&&/(html5|native)/i.test(e.media.rendererName),n=getComputedStyle(e.container);if(d.IS_IOS&&d.HAS_IOS_FULLSCREEN)"function"==typeof e.media.webkitEnterFullscreen?e.media.webkitEnterFullscreen():e.media.originalNode.webkitEnterFullscreen();else{if((0,c.addClass)(a.default.documentElement,e.options.classPrefix+"fullscreen"),(0,c.addClass)(e.container,e.options.classPrefix+"container-fullscreen"),e.normalHeight=parseFloat(n.height),e.normalWidth=parseFloat(n.width),"native-native"!==e.fullscreenMode&&"plugin-native"!==e.fullscreenMode||(d.requestFullScreen(e.container),e.isInIframe&&setTimeout(function t(){if(e.isNativeFullScreen){var n=o.default.innerWidth||a.default.documentElement.clientWidth||a.default.body.clientWidth,i=screen.width;Math.abs(i-n)>.002*i?e.exitFullScreen():setTimeout(t,500)}},1e3)),e.container.style.width="100%",e.container.style.height="100%",e.containerSizeTimeout=setTimeout(function(){e.container.style.width="100%",e.container.style.height="100%",e.setControlsSize()},500),t)e.node.style.width="100%",e.node.style.height="100%";else for(var i=e.container.querySelectorAll("iframe, embed, object, video"),r=i.length,s=0;s<r;s++)i[s].style.width="100%",i[s].style.height="100%";e.options.setDimensions&&"function"==typeof e.media.setSize&&e.media.setSize(screen.width,screen.height);for(var l=e.layers.childNodes,f=l.length,p=0;p<f;p++)l[p].style.width="100%",l[p].style.height="100%";e.fullscreenBtn&&((0,c.removeClass)(e.fullscreenBtn,e.options.classPrefix+"fullscreen"),(0,c.addClass)(e.fullscreenBtn,e.options.classPrefix+"unfullscreen")),e.setControlsSize(),e.isFullScreen=!0;var m=Math.min(screen.width/e.width,screen.height/e.height),h=e.container.querySelector("."+e.options.classPrefix+"captions-text");h&&(h.style.fontSize=100*m+"%",h.style.lineHeight="normal",e.container.querySelector("."+e.options.classPrefix+"captions-position").style.bottom="45px");var v=(0,u.createEvent)("enteredfullscreen",e.container);e.container.dispatchEvent(v)}},exitFullScreen:function(){var e=this,t=null!==e.media.rendererName&&/(native|html5)/i.test(e.media.rendererName);if(clearTimeout(e.containerSizeTimeout),d.HAS_TRUE_NATIVE_FULLSCREEN&&(d.IS_FULLSCREEN||e.isFullScreen)&&d.cancelFullScreen(),(0,c.removeClass)(a.default.documentElement,e.options.classPrefix+"fullscreen"),(0,c.removeClass)(e.container,e.options.classPrefix+"container-fullscreen"),e.options.setDimensions){if(e.container.style.width=e.normalWidth+"px",e.container.style.height=e.normalHeight+"px",t)e.node.style.width=e.normalWidth+"px",e.node.style.height=e.normalHeight+"px";else for(var n=e.container.querySelectorAll("iframe, embed, object, video"),i=n.length,o=0;o<i;o++)n[o].style.width=e.normalWidth+"px",n[o].style.height=e.normalHeight+"px";"function"==typeof e.media.setSize&&e.media.setSize(e.normalWidth,e.normalHeight);for(var r=e.layers.childNodes,s=r.length,l=0;l<s;l++)r[l].style.width=e.normalWidth+"px",r[l].style.height=e.normalHeight+"px"}e.fullscreenBtn&&((0,c.removeClass)(e.fullscreenBtn,e.options.classPrefix+"unfullscreen"),(0,c.addClass)(e.fullscreenBtn,e.options.classPrefix+"fullscreen")),e.setControlsSize(),e.isFullScreen=!1;var f=e.container.querySelector("."+e.options.classPrefix+"captions-text");f&&(f.style.fontSize="",f.style.lineHeight="",e.container.querySelector("."+e.options.classPrefix+"captions-position").style.bottom="");var p=(0,u.createEvent)("exitedfullscreen",e.container);e.container.dispatchEvent(p)}})},{16:16,2:2,23:23,24:24,25:25,3:3,4:4}],9:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=e(16),r=i(a),s=i(e(4)),l=e(25),d=e(24);Object.assign(a.config,{playText:null,pauseText:null}),Object.assign(r.default.prototype,{buildplaypause:function(e,t,n,i){function a(e){"play"===e?((0,d.removeClass)(p,r.options.classPrefix+"play"),(0,d.removeClass)(p,r.options.classPrefix+"replay"),(0,d.addClass)(p,r.options.classPrefix+"pause"),m.setAttribute("title",f),m.setAttribute("aria-label",f)):((0,d.removeClass)(p,r.options.classPrefix+"pause"),(0,d.removeClass)(p,r.options.classPrefix+"replay"),(0,d.addClass)(p,r.options.classPrefix+"play"),m.setAttribute("title",c),m.setAttribute("aria-label",c))}var r=this,u=r.options,c=(0,l.isString)(u.playText)?u.playText:s.default.t("mejs.play"),f=(0,l.isString)(u.pauseText)?u.pauseText:s.default.t("mejs.pause"),p=o.default.createElement("div");p.className=r.options.classPrefix+"button "+r.options.classPrefix+"playpause-button "+r.options.classPrefix+"play",p.innerHTML='<button type="button" aria-controls="'+r.id+'" title="'+c+'" aria-label="'+f+'" tabindex="0"></button>',p.addEventListener("click",function(){i.paused?i.play():i.pause()});var m=p.querySelector("button");r.addControlElement(p,"playpause"),a("pse"),i.addEventListener("loadedmetadata",function(){-1===i.rendererName.indexOf("flash")&&a("pse")}),i.addEventListener("play",function(){a("play")}),i.addEventListener("playing",function(){a("play")}),i.addEventListener("pause",function(){a("pse")}),i.addEventListener("ended",function(){e.options.loop||((0,d.removeClass)(p,r.options.classPrefix+"pause"),(0,d.removeClass)(p,r.options.classPrefix+"play"),(0,d.addClass)(p,r.options.classPrefix+"replay"),m.setAttribute("title",c),m.setAttribute("aria-label",c))})}})},{16:16,2:2,24:24,25:25,4:4}],10:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=e(16),r=i(a),s=i(e(4)),l=e(23),d=e(28),u=e(24);Object.assign(a.config,{enableProgressTooltip:!0,useSmoothHover:!0}),Object.assign(r.default.prototype,{buildprogress:function(e,t,n,i){var a=0,r=!1,c=!1,f=this,p=e.options.autoRewind,m=e.options.enableProgressTooltip?'<span class="'+f.options.classPrefix+'time-float"><span class="'+f.options.classPrefix+'time-float-current">00:00</span><span class="'+f.options.classPrefix+'time-float-corner"></span></span>':"",h=o.default.createElement("div");h.className=f.options.classPrefix+"time-rail",h.innerHTML='<span class="'+f.options.classPrefix+"time-total "+f.options.classPrefix+'time-slider"><span class="'+f.options.classPrefix+'time-buffering"></span><span class="'+f.options.classPrefix+'time-loaded"></span><span class="'+f.options.classPrefix+'time-current"></span><span class="'+f.options.classPrefix+'time-hovered no-hover"></span><span class="'+f.options.classPrefix+'time-handle"><span class="'+f.options.classPrefix+'time-handle-content"></span></span>'+m+"</span>",f.addControlElement(h,"progress"),t.querySelector("."+f.options.classPrefix+"time-buffering").style.display="none",f.rail=t.querySelector("."+f.options.classPrefix+"time-rail"),f.total=t.querySelector("."+f.options.classPrefix+"time-total"),f.loaded=t.querySelector("."+f.options.classPrefix+"time-loaded"),f.current=t.querySelector("."+f.options.classPrefix+"time-current"),f.handle=t.querySelector("."+f.options.classPrefix+"time-handle"),f.timefloat=t.querySelector("."+f.options.classPrefix+"time-float"),f.timefloatcurrent=t.querySelector("."+f.options.classPrefix+"time-float-current"),f.slider=t.querySelector("."+f.options.classPrefix+"time-slider"),f.hovered=t.querySelector("."+f.options.classPrefix+"time-hovered"),f.newTime=0,f.forcedHandlePause=!1,f.setTransformStyle=function(e,t){e.style.transform=t,e.style.webkitTransform=t,e.style.MozTransform=t,e.style.msTransform=t,e.style.OTransform=t};var v=function(t){var n=getComputedStyle(f.total),i=(0,u.offset)(f.total),o=parseFloat(n.width),a=function(){return void 0!==n.webkitTransform?"webkitTransform":void 0!==n.mozTransform?"mozTransform ":void 0!==n.oTransform?"oTransform":void 0!==n.msTransform?"msTransform":"transform"}(),s=function(){return"WebKitCSSMatrix"in window?"WebKitCSSMatrix":"MSCSSMatrix"in window?"MSCSSMatrix":"CSSMatrix"in window?"CSSMatrix":void 0}(),c=0,p=0,m=void 0;if(m=t.originalEvent&&t.originalEvent.changedTouches?t.originalEvent.changedTouches[0].pageX:t.changedTouches?t.changedTouches[0].pageX:t.pageX,f.getDuration()&&(m<i.left?m=i.left:m>o+i.left&&(m=o+i.left),p=m-i.left,c=p/o,f.newTime=c<=.02?0:c*f.getDuration(),r&&null!==f.getCurrentTime()&&f.newTime.toFixed(4)!==f.getCurrentTime().toFixed(4)&&(f.setCurrentRailHandle(f.newTime),f.updateCurrent(f.newTime)),!l.IS_IOS&&!l.IS_ANDROID&&f.timefloat)){if(p<0&&(p=0),f.options.useSmoothHover&&null!==s&&void 0!==window[s]){var h=new window[s](getComputedStyle(f.handle)[a]).m41,v=p/parseFloat(getComputedStyle(f.total).width)-h/parseFloat(getComputedStyle(f.total).width);f.hovered.style.left=h+"px",f.setTransformStyle(f.hovered,"scaleX("+v+")"),f.hovered.setAttribute("pos",p),v>=0?(0,u.removeClass)(f.hovered,"negative"):(0,u.addClass)(f.hovered,"negative")}f.timefloat.style.left=p+"px",f.timefloatcurrent.innerHTML=(0,d.secondsToTimeCode)(f.newTime,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength),f.timefloat.style.display="block"}},y=function(){var t=f.getCurrentTime(),n=s.default.t("mejs.time-slider"),o=(0,d.secondsToTimeCode)(t,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength),a=f.getDuration();f.slider.setAttribute("role","slider"),f.slider.tabIndex=0,i.paused?(f.slider.setAttribute("aria-label",n),f.slider.setAttribute("aria-valuemin",0),f.slider.setAttribute("aria-valuemax",a),f.slider.setAttribute("aria-valuenow",t),f.slider.setAttribute("aria-valuetext",o)):(f.slider.removeAttribute("aria-label"),f.slider.removeAttribute("aria-valuemin"),f.slider.removeAttribute("aria-valuemax"),f.slider.removeAttribute("aria-valuenow"),f.slider.removeAttribute("aria-valuetext"))},g=function(){new Date-a>=1e3&&i.play()},b=function(){r&&null!==f.getCurrentTime()&&f.newTime.toFixed(4)!==f.getCurrentTime().toFixed(4)&&(f.setCurrentTime(f.newTime),e.setCurrentRail(),f.updateCurrent(f.newTime)),f.forcedHandlePause&&f.media.play(),f.forcedHandlePause=!1};f.slider.addEventListener("focus",function(){e.options.autoRewind=!1}),f.slider.addEventListener("blur",function(){e.options.autoRewind=p}),f.slider.addEventListener("keydown",function(t){if(new Date-a>=1e3&&(c=i.paused),f.options.keyActions.length){var n=t.which||t.keyCode||0,o=f.getDuration(),r=e.options.defaultSeekForwardInterval(i),s=e.options.defaultSeekBackwardInterval(i),d=f.getCurrentTime();switch(n){case 37:case 40:f.getDuration()!==1/0&&(d-=s);break;case 39:case 38:f.getDuration()!==1/0&&(d+=r);break;case 36:d=0;break;case 35:d=o;break;case 32:return void(l.IS_FIREFOX||(i.paused?i.play():i.pause()));case 13:return void(i.paused?i.play():i.pause());default:return}d=d<0?0:d>=o?o:Math.floor(d),a=new Date,c||i.pause(),d<f.getDuration()&&!c&&setTimeout(g,1100),f.setCurrentTime(d),t.preventDefault(),t.stopPropagation()}});var E=["mousedown","touchstart"];f.slider.addEventListener("dragstart",function(){return!1});for(var S=0,x=E.length;S<x;S++)f.slider.addEventListener(E[S],function(e){if(f.forcedHandlePause=!1,f.getDuration()!==1/0&&(1===e.which||0===e.which)){i.paused||(f.media.pause(),f.forcedHandlePause=!0),r=!0,v(e);for(var t=["mouseup","touchend"],n=0,o=t.length;n<o;n++)f.container.addEventListener(t[n],function(e){var t=e.target;(t===f.slider||t.closest("."+f.options.classPrefix+"time-slider"))&&v(e)});f.globalBind("mouseup.dur touchend.dur",function(){b(),r=!1,f.timefloat&&(f.timefloat.style.display="none"),f.globalUnbind("mousemove.dur touchmove.dur mouseup.dur touchend.dur")})}});f.slider.addEventListener("mouseenter",function(e){e.target===f.slider&&f.getDuration()!==1/0&&(f.container.addEventListener("mousemove",function(e){var t=e.target;(t===f.slider||t.closest("."+f.options.classPrefix+"time-slider"))&&v(e)}),!f.timefloat||l.IS_IOS||l.IS_ANDROID||(f.timefloat.style.display="block"),f.hovered&&!l.IS_IOS&&!l.IS_ANDROID&&f.options.useSmoothHover&&(0,u.removeClass)(f.hovered,"no-hover"))}),f.slider.addEventListener("mouseleave",function(){f.getDuration()!==1/0&&(r||(f.globalUnbind("mousemove.dur"),f.timefloat&&(f.timefloat.style.display="none"),f.hovered&&f.options.useSmoothHover&&(0,u.addClass)(f.hovered,"no-hover")))}),i.addEventListener("progress",function(n){var i=t.querySelector("."+f.options.classPrefix+"broadcast");if(f.getDuration()!==1/0)i&&(f.slider.style.display="",i.remove()),e.setProgressRail(n),f.forcedHandlePause||e.setCurrentRail(n);else if(!i){var a=o.default.createElement("span");a.className=f.options.classPrefix+"broadcast",a.innerText=s.default.t("mejs.live-broadcast"),f.slider.style.display="none"}}),i.addEventListener("timeupdate",function(n){var i=t.querySelector("."+f.options.classPrefix+"broadcast");if(f.getDuration()!==1/0)i&&(f.slider.style.display="",i.remove()),e.setProgressRail(n),f.forcedHandlePause||e.setCurrentRail(n),y();else if(!i){var a=o.default.createElement("span");a.className=f.options.classPrefix+"broadcast",a.innerText=s.default.t("mejs.live-broadcast"),t.querySelector("."+f.options.classPrefix+"time-rail").appendChild(a),f.slider.style.display="none"}}),f.container.addEventListener("controlsresize",function(t){f.getDuration()!==1/0&&(e.setProgressRail(t),f.forcedHandlePause||e.setCurrentRail(t))})},setProgressRail:function(e){var t=this,n=void 0!==e?e.detail.target||e.target:t.media,i=null;n&&n.buffered&&n.buffered.length>0&&n.buffered.end&&t.getDuration()?i=n.buffered.end(n.buffered.length-1)/t.getDuration():n&&void 0!==n.bytesTotal&&n.bytesTotal>0&&void 0!==n.bufferedBytes?i=n.bufferedBytes/n.bytesTotal:e&&e.lengthComputable&&0!==e.total&&(i=e.loaded/e.total),null!==i&&(i=Math.min(1,Math.max(0,i)),t.loaded&&t.setTransformStyle(t.loaded,"scaleX("+i+")"))},setCurrentRailHandle:function(e){var t=this;t.setCurrentRailMain(t,e)},setCurrentRail:function(){var e=this;e.setCurrentRailMain(e)},setCurrentRailMain:function(e,t){if(void 0!==e.getCurrentTime()&&e.getDuration()){var n=void 0===t?e.getCurrentTime():t;if(e.total&&e.handle){var i=parseFloat(getComputedStyle(e.total).width),o=Math.round(i*n/e.getDuration()),a=o-Math.round(e.handle.offsetWidth/2);if(a=a<0?0:a,e.setTransformStyle(e.current,"scaleX("+o/i+")"),e.setTransformStyle(e.handle,"translateX("+a+"px)"),e.options.useSmoothHover&&!(0,u.hasClass)(e.hovered,"no-hover")){var r=parseInt(e.hovered.getAttribute("pos")),s=(r=isNaN(r)?0:r)/i-a/i;e.hovered.style.left=a+"px",e.setTransformStyle(e.hovered,"scaleX("+s+")"),s>=0?(0,u.removeClass)(e.hovered,"negative"):(0,u.addClass)(e.hovered,"negative")}}}}})},{16:16,2:2,23:23,24:24,28:28,4:4}],11:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=e(16),r=i(a),s=e(28),l=e(24);Object.assign(a.config,{duration:0,timeAndDurationSeparator:"<span> | </span>"}),Object.assign(r.default.prototype,{buildcurrent:function(e,t,n,i){var a=this,r=o.default.createElement("div");r.className=a.options.classPrefix+"time",r.setAttribute("role","timer"),r.setAttribute("aria-live","off"),r.innerHTML='<span class="'+a.options.classPrefix+'currenttime">'+(0,s.secondsToTimeCode)(0,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength)+"</span>",a.addControlElement(r,"current"),i.addEventListener("timeupdate",function(){a.controlsAreVisible&&e.updateCurrent()})},buildduration:function(e,t,n,i){var a=this;if(t.lastChild.querySelector("."+a.options.classPrefix+"currenttime"))t.querySelector("."+a.options.classPrefix+"time").innerHTML+=a.options.timeAndDurationSeparator+'<span class="'+a.options.classPrefix+'duration">'+(0,s.secondsToTimeCode)(a.options.duration,a.options.alwaysShowHours,a.options.showTimecodeFrameCount,a.options.framesPerSecond,a.options.secondsDecimalLength)+"</span>";else{t.querySelector("."+a.options.classPrefix+"currenttime")&&(0,l.addClass)(t.querySelector("."+a.options.classPrefix+"currenttime").parentNode,a.options.classPrefix+"currenttime-container");var r=o.default.createElement("div");r.className=a.options.classPrefix+"time "+a.options.classPrefix+"duration-container",r.innerHTML='<span class="'+a.options.classPrefix+'duration">'+(0,s.secondsToTimeCode)(a.options.duration,a.options.alwaysShowHours,a.options.showTimecodeFrameCount,a.options.framesPerSecond,a.options.secondsDecimalLength)+"</span>",a.addControlElement(r,"duration")}i.addEventListener("timeupdate",function(){a.controlsAreVisible&&e.updateDuration()})},updateCurrent:function(){var e=this,t=e.getCurrentTime();isNaN(t)&&(t=0),e.controls.querySelector("."+e.options.classPrefix+"currenttime")&&(e.controls.querySelector("."+e.options.classPrefix+"currenttime").innerText=(0,s.secondsToTimeCode)(t,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength))},updateDuration:function(){var e=this,t=e.getDuration();(isNaN(t)||t===1/0||t<0)&&(e.media.duration=e.options.duration=t=0),e.options.duration>0&&(t=e.options.duration);var n=(0,s.secondsToTimeCode)(t,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength);n.length>5&&(0,l.toggleClass)(e.container,e.options.classPrefix+"long-video"),e.controls.querySelector("."+e.options.classPrefix+"duration")&&t>0&&(e.controls.querySelector("."+e.options.classPrefix+"duration").innerHTML=n)}})},{16:16,2:2,24:24,28:28}],12:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=i(e(6)),r=i(e(4)),s=e(16),l=i(s),d=e(28),u=e(25),c=e(24);Object.assign(s.config,{startLanguage:"",tracksText:null,chaptersText:null,tracksAriaLive:!1,hideCaptionsButtonWhenEmpty:!0,toggleCaptionsButtonWhenOnlyOne:!1,slidesSelector:""}),Object.assign(l.default.prototype,{hasChapters:!1,buildtracks:function(e,t,n,i){if(e.tracks.length||e.trackFiles&&0!==!e.trackFiles.length){var a=this,s=a.options.tracksAriaLive?' role="log" aria-live="assertive" aria-atomic="false"':"",l=(0,u.isString)(a.options.tracksText)?a.options.tracksText:r.default.t("mejs.captions-subtitles"),d=(0,u.isString)(a.options.chaptersText)?a.options.chaptersText:r.default.t("mejs.captions-chapters"),f=null===e.trackFiles?e.tracks.length:e.trackFiles.length;if(a.domNode.textTracks)for(var p=a.domNode.textTracks.length-1;p>=0;p--)a.domNode.textTracks[p].mode="hidden";a.cleartracks(e),e.captions=o.default.createElement("div"),e.captions.className=a.options.classPrefix+"captions-layer "+a.options.classPrefix+"layer",e.captions.innerHTML='<div class="'+a.options.classPrefix+"captions-position "+a.options.classPrefix+'captions-position-hover"'+s+'><span class="'+a.options.classPrefix+'captions-text"></span></div>',e.captions.style.display="none",n.insertBefore(e.captions,n.firstChild),e.captionsText=e.captions.querySelector("."+a.options.classPrefix+"captions-text"),e.captionsButton=o.default.createElement("div"),e.captionsButton.className=a.options.classPrefix+"button "+a.options.classPrefix+"captions-button",e.captionsButton.innerHTML='<button type="button" aria-controls="'+a.id+'" title="'+l+'" aria-label="'+l+'" tabindex="0"></button><div class="'+a.options.classPrefix+"captions-selector "+a.options.classPrefix+'offscreen"><ul class="'+a.options.classPrefix+'captions-selector-list"><li class="'+a.options.classPrefix+'captions-selector-list-item"><input type="radio" class="'+a.options.classPrefix+'captions-selector-input" name="'+e.id+'_captions" id="'+e.id+'_captions_none" value="none" checked disabled><label class="'+a.options.classPrefix+"captions-selector-label "+a.options.classPrefix+'captions-selected" for="'+e.id+'_captions_none">'+r.default.t("mejs.none")+"</label></li></ul></div>",a.addControlElement(e.captionsButton,"tracks"),e.captionsButton.querySelector("."+a.options.classPrefix+"captions-selector-input").disabled=!1,e.chaptersButton=o.default.createElement("div"),e.chaptersButton.className=a.options.classPrefix+"button "+a.options.classPrefix+"chapters-button",e.chaptersButton.innerHTML='<button type="button" aria-controls="'+a.id+'" title="'+d+'" aria-label="'+d+'" tabindex="0"></button><div class="'+a.options.classPrefix+"chapters-selector "+a.options.classPrefix+'offscreen"><ul class="'+a.options.classPrefix+'chapters-selector-list"></ul></div>';for(var m=0,h=0;h<f;h++){var v=e.tracks[h].kind;"subtitles"===v||"captions"===v?m++:"chapters"!==v||t.querySelector("."+a.options.classPrefix+"chapter-selector")||e.captionsButton.parentNode.insertBefore(e.chaptersButton,e.captionsButton)}e.trackToLoad=-1,e.selectedTrack=null,e.isLoadingTrack=!1;for(var y=0;y<f;y++){var g=e.tracks[y].kind;"subtitles"!==g&&"captions"!==g||e.addTrackButton(e.tracks[y].trackId,e.tracks[y].srclang,e.tracks[y].label)}e.loadNextTrack();var b=["mouseenter","focusin"],E=["mouseleave","focusout"];if(a.options.toggleCaptionsButtonWhenOnlyOne&&1===m)e.captionsButton.addEventListener("click",function(){var t="none";null===e.selectedTrack&&(t=e.tracks[0].trackId),e.setTrack(t)});else{for(var S=e.captionsButton.querySelectorAll("."+a.options.classPrefix+"captions-selector-label"),x=e.captionsButton.querySelectorAll("input[type=radio]"),w=0,P=b.length;w<P;w++)e.captionsButton.addEventListener(b[w],function(){(0,c.removeClass)(this.querySelector("."+a.options.classPrefix+"captions-selector"),a.options.classPrefix+"offscreen")});for(var T=0,C=E.length;T<C;T++)e.captionsButton.addEventListener(E[T],function(){(0,c.addClass)(this.querySelector("."+a.options.classPrefix+"captions-selector"),a.options.classPrefix+"offscreen")});for(var k=0,_=x.length;k<_;k++)x[k].addEventListener("click",function(){e.setTrack(this.value)});for(var N=0,A=S.length;N<A;N++)S[N].addEventListener("click",function(){var e=(0,c.siblings)(this,function(e){return"INPUT"===e.tagName})[0],t=(0,u.createEvent)("click",e);e.dispatchEvent(t)});e.captionsButton.addEventListener("keydown",function(e){e.stopPropagation()})}for(var L=0,F=b.length;L<F;L++)e.chaptersButton.addEventListener(b[L],function(){this.querySelector("."+a.options.classPrefix+"chapters-selector-list").childNodes.length&&(0,c.removeClass)(this.querySelector("."+a.options.classPrefix+"chapters-selector"),a.options.classPrefix+"offscreen")});for(var j=0,I=E.length;j<I;j++)e.chaptersButton.addEventListener(E[j],function(){(0,c.addClass)(this.querySelector("."+a.options.classPrefix+"chapters-selector"),a.options.classPrefix+"offscreen")});e.chaptersButton.addEventListener("keydown",function(e){e.stopPropagation()}),e.options.alwaysShowControls?(0,c.addClass)(e.container.querySelector("."+a.options.classPrefix+"captions-position"),a.options.classPrefix+"captions-position-hover"):(e.container.addEventListener("controlsshown",function(){(0,c.addClass)(e.container.querySelector("."+a.options.classPrefix+"captions-position"),a.options.classPrefix+"captions-position-hover")}),e.container.addEventListener("controlshidden",function(){i.paused||(0,c.removeClass)(e.container.querySelector("."+a.options.classPrefix+"captions-position"),a.options.classPrefix+"captions-position-hover")})),i.addEventListener("timeupdate",function(){e.displayCaptions()}),""!==e.options.slidesSelector&&(e.slidesContainer=o.default.querySelectorAll(e.options.slidesSelector),i.addEventListener("timeupdate",function(){e.displaySlides()}))}},cleartracks:function(e){e&&(e.captions&&e.captions.remove(),e.chapters&&e.chapters.remove(),e.captionsText&&e.captionsText.remove(),e.captionsButton&&e.captionsButton.remove(),e.chaptersButton&&e.chaptersButton.remove())},rebuildtracks:function(){var e=this;e.findTracks(),e.buildtracks(e,e.controls,e.layers,e.media)},findTracks:function(){var e=this,t=null===e.trackFiles?e.node.querySelectorAll("track"):e.trackFiles,n=t.length;e.tracks=[];for(var i=0;i<n;i++){var o=t[i],a=o.getAttribute("srclang").toLowerCase()||"",r=e.id+"_track_"+i+"_"+o.getAttribute("kind")+"_"+a;e.tracks.push({trackId:r,srclang:a,src:o.getAttribute("src"),kind:o.getAttribute("kind"),label:o.getAttribute("label")||"",entries:[],isLoaded:!1})}},setTrack:function(e){for(var t=this,n=t.captionsButton.querySelectorAll('input[type="radio"]'),i=t.captionsButton.querySelectorAll("."+t.options.classPrefix+"captions-selected"),o=t.captionsButton.querySelector('input[value="'+e+'"]'),a=0,r=n.length;a<r;a++)n[a].checked=!1;for(var s=0,l=i.length;s<l;s++)(0,c.removeClass)(i[s],t.options.classPrefix+"captions-selected");o.checked=!0;for(var d=(0,c.siblings)(o,function(e){return(0,c.hasClass)(e,t.options.classPrefix+"captions-selector-label")}),f=0,p=d.length;f<p;f++)(0,c.addClass)(d[f],t.options.classPrefix+"captions-selected");if("none"===e)t.selectedTrack=null,(0,c.removeClass)(t.captionsButton,t.options.classPrefix+"captions-enabled");else for(var m=0,h=t.tracks.length;m<h;m++){var v=t.tracks[m];if(v.trackId===e){null===t.selectedTrack&&(0,c.addClass)(t.captionsButton,t.options.classPrefix+"captions-enabled"),t.selectedTrack=v,t.captions.setAttribute("lang",t.selectedTrack.srclang),t.displayCaptions();break}}var y=(0,u.createEvent)("captionschange",t.media);y.detail.caption=t.selectedTrack,t.media.dispatchEvent(y)},loadNextTrack:function(){var e=this;++e.trackToLoad<e.tracks.length?(e.isLoadingTrack=!0,e.loadTrack(e.trackToLoad)):(e.isLoadingTrack=!1,e.checkForTracks())},loadTrack:function(e){var t=this,n=t.tracks[e];void 0===n||void 0===n.src&&""===n.src||(0,c.ajax)(n.src,"text",function(e){n.entries="string"==typeof e&&/<tt\s+xml/gi.exec(e)?a.default.TrackFormatParser.dfxp.parse(e):a.default.TrackFormatParser.webvtt.parse(e),n.isLoaded=!0,t.enableTrackButton(n),t.loadNextTrack(),"slides"===n.kind?t.setupSlides(n):"chapters"!==n.kind||t.hasChapters||(t.drawChapters(n),t.hasChapters=!0)},function(){t.removeTrackButton(n.trackId),t.loadNextTrack()})},enableTrackButton:function(e){var t=this,n=e.srclang,i=o.default.getElementById(""+e.trackId);if(i){var s=e.label;""===s&&(s=r.default.t(a.default.language.codes[n])||n),i.disabled=!1;for(var l=(0,c.siblings)(i,function(e){return(0,c.hasClass)(e,t.options.classPrefix+"captions-selector-label")}),d=0,f=l.length;d<f;d++)l[d].innerHTML=s;if(t.options.startLanguage===n){i.checked=!0;var p=(0,u.createEvent)("click",i);i.dispatchEvent(p)}}},removeTrackButton:function(e){var t=o.default.getElementById(""+e);if(t){var n=t.closest("li");n&&n.remove()}},addTrackButton:function(e,t,n){var i=this;""===n&&(n=r.default.t(a.default.language.codes[t])||t),i.captionsButton.querySelector("ul").innerHTML+='<li class="'+i.options.classPrefix+'captions-selector-list-item"><input type="radio" class="'+i.options.classPrefix+'captions-selector-input" name="'+i.id+'_captions" id="'+e+'" value="'+e+'" disabled><label class="'+i.options.classPrefix+'captions-selector-label"for="'+e+'">'+n+" (loading)</label></li>"},checkForTracks:function(){var e=this,t=!1;if(e.options.hideCaptionsButtonWhenEmpty){for(var n=0,i=e.tracks.length;n<i;n++){var o=e.tracks[n].kind;if(("subtitles"===o||"captions"===o)&&e.tracks[n].isLoaded){t=!0;break}}e.captionsButton.style.display=t?"":"none",e.setControlsSize()}},displayCaptions:function(){if(void 0!==this.tracks){var e=this,t=e.selectedTrack;if(null!==t&&t.isLoaded){var n=e.searchTrackPosition(t.entries,e.media.currentTime);if(n>-1)return e.captionsText.innerHTML=function(e){var t=o.default.createElement("div");t.innerHTML=e;for(var n=t.getElementsByTagName("script"),i=n.length;i--;)n[i].remove();for(var a=t.getElementsByTagName("*"),r=0,s=a.length;r<s;r++)for(var l=a[r].attributes,d=Array.prototype.slice.call(l),u=0,c=d.length;u<c;u++)d[u].name.startsWith("on")||d[u].value.startsWith("javascript")?a[r].remove():"style"===d[u].name&&a[r].removeAttribute(d[u].name);return t.innerHTML}(t.entries[n].text),e.captionsText.className=e.options.classPrefix+"captions-text "+(t.entries[n].identifier||""),e.captions.style.display="",void(e.captions.style.height="0px");e.captions.style.display="none"}else e.captions.style.display="none"}},setupSlides:function(e){var t=this;t.slides=e,t.slides.entries.imgs=[t.slides.entries.length],t.showSlide(0)},showSlide:function(e){var t=this,n=this;if(void 0!==n.tracks&&void 0!==n.slidesContainer){var i=n.slides.entries[e].text,a=n.slides.entries[e].imgs;if(void 0===a||void 0===a.fadeIn){var r=o.default.createElement("img");r.src=i,r.addEventListener("load",function(){var e=t,i=(0,c.siblings)(e,function(e){return i(e)});e.style.display="none",n.slidesContainer.innerHTML+=e.innerHTML,(0,c.fadeIn)(n.slidesContainer.querySelector(r));for(var o=0,a=i.length;o<a;o++)(0,c.fadeOut)(i[o],400)}),n.slides.entries[e].imgs=a=r}else if(!(0,c.visible)(a)){var s=(0,c.siblings)(self,function(e){return s(e)});(0,c.fadeIn)(n.slidesContainer.querySelector(a));for(var l=0,d=s.length;l<d;l++)(0,c.fadeOut)(s[l])}}},displaySlides:function(){var e=this;if(void 0!==this.slides){var t=e.slides,n=e.searchTrackPosition(t.entries,e.media.currentTime);n>-1&&e.showSlide(n)}},drawChapters:function(e){var t=this,n=e.entries.length;if(n){t.chaptersButton.querySelector("ul").innerHTML="";for(var i=0;i<n;i++)t.chaptersButton.querySelector("ul").innerHTML+='<li class="'+t.options.classPrefix+'chapters-selector-list-item" role="menuitemcheckbox" aria-live="polite" aria-disabled="false" aria-checked="false"><input type="radio" class="'+t.options.classPrefix+'captions-selector-input" name="'+t.id+'_chapters" id="'+t.id+"_chapters_"+i+'" value="'+e.entries[i].start+'" disabled><label class="'+t.options.classPrefix+'chapters-selector-label"for="'+t.id+"_chapters_"+i+'">'+e.entries[i].text+"</label></li>";for(var o=t.chaptersButton.querySelectorAll('input[type="radio"]'),a=t.chaptersButton.querySelectorAll("."+t.options.classPrefix+"chapters-selector-label"),r=0,s=o.length;r<s;r++)o[r].disabled=!1,o[r].checked=!1,o[r].addEventListener("click",function(){var e=this,n=t.chaptersButton.querySelectorAll("li"),i=(0,c.siblings)(e,function(e){return(0,c.hasClass)(e,t.options.classPrefix+"chapters-selector-label")})[0];e.checked=!0,e.parentNode.setAttribute("aria-checked",!0),(0,c.addClass)(i,t.options.classPrefix+"chapters-selected"),(0,c.removeClass)(t.chaptersButton.querySelector("."+t.options.classPrefix+"chapters-selected"),t.options.classPrefix+"chapters-selected");for(var o=0,a=n.length;o<a;o++)n[o].setAttribute("aria-checked",!1);t.media.setCurrentTime(parseFloat(e.value)),t.media.paused&&t.media.play()});for(var l=0,d=a.length;l<d;l++)a[l].addEventListener("click",function(){var e=(0,c.siblings)(this,function(e){return"INPUT"===e.tagName})[0],t=(0,u.createEvent)("click",e);e.dispatchEvent(t)})}},searchTrackPosition:function(e,t){for(var n=0,i=e.length-1,o=void 0,a=void 0,r=void 0;n<=i;){if(o=n+i>>1,a=e[o].start,r=e[o].stop,t>=a&&t<r)return o;a<t?n=o+1:a>t&&(i=o-1)}return-1}}),a.default.language={codes:{af:"mejs.afrikaans",sq:"mejs.albanian",ar:"mejs.arabic",be:"mejs.belarusian",bg:"mejs.bulgarian",ca:"mejs.catalan",zh:"mejs.chinese","zh-cn":"mejs.chinese-simplified","zh-tw":"mejs.chines-traditional",hr:"mejs.croatian",cs:"mejs.czech",da:"mejs.danish",nl:"mejs.dutch",en:"mejs.english",et:"mejs.estonian",fl:"mejs.filipino",fi:"mejs.finnish",fr:"mejs.french",gl:"mejs.galician",de:"mejs.german",el:"mejs.greek",ht:"mejs.haitian-creole",iw:"mejs.hebrew",hi:"mejs.hindi",hu:"mejs.hungarian",is:"mejs.icelandic",id:"mejs.indonesian",ga:"mejs.irish",it:"mejs.italian",ja:"mejs.japanese",ko:"mejs.korean",lv:"mejs.latvian",lt:"mejs.lithuanian",mk:"mejs.macedonian",ms:"mejs.malay",mt:"mejs.maltese",no:"mejs.norwegian",fa:"mejs.persian",pl:"mejs.polish",pt:"mejs.portuguese",ro:"mejs.romanian",ru:"mejs.russian",sr:"mejs.serbian",sk:"mejs.slovak",sl:"mejs.slovenian",es:"mejs.spanish",sw:"mejs.swahili",sv:"mejs.swedish",tl:"mejs.tagalog",th:"mejs.thai",tr:"mejs.turkish",uk:"mejs.ukrainian",vi:"mejs.vietnamese",cy:"mejs.welsh",yi:"mejs.yiddish"}},a.default.TrackFormatParser={webvtt:{pattern:/^((?:[0-9]{1,2}:)?[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ((?:[0-9]{1,2}:)?[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,parse:function(e){for(var t=e.split(/\r?\n/),n=[],i=void 0,o=void 0,a=void 0,r=0,s=t.length;r<s;r++){if((i=this.pattern.exec(t[r]))&&r<t.length){for(r-1>=0&&""!==t[r-1]&&(a=t[r-1]),o=t[++r],r++;""!==t[r]&&r<t.length;)o=o+"\n"+t[r],r++;o=o.trim().replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi,"<a href='$1' target='_blank'>$1</a>"),n.push({identifier:a,start:0===(0,d.convertSMPTEtoSeconds)(i[1])?.2:(0,d.convertSMPTEtoSeconds)(i[1]),stop:(0,d.convertSMPTEtoSeconds)(i[3]),text:o,settings:i[5]})}a=""}return n}},dfxp:{parse:function(e){var t=(e=$(e).filter("tt")).firstChild,n=t.querySelectorAll("p"),i=e.getElementById(""+t.attr("style")),o=[],a=void 0;if(i.length){i.removeAttribute("id");var r=i.attributes;if(r.length){a={};for(var s=0,l=r.length;s<l;s++)a[r[s].name.split(":")[1]]=r[s].value}}for(var u=0,c=n.length;u<c;u++){var f=void 0,p={start:null,stop:null,style:null,text:null};if(n.eq(u).attr("begin")&&(p.start=(0,d.convertSMPTEtoSeconds)(n.eq(u).attr("begin"))),!p.start&&n.eq(u-1).attr("end")&&(p.start=(0,d.convertSMPTEtoSeconds)(n.eq(u-1).attr("end"))),n.eq(u).attr("end")&&(p.stop=(0,d.convertSMPTEtoSeconds)(n.eq(u).attr("end"))),!p.stop&&n.eq(u+1).attr("begin")&&(p.stop=(0,d.convertSMPTEtoSeconds)(n.eq(u+1).attr("begin"))),a){f="";for(var m in a)f+=m+":"+a[m]+";"}f&&(p.style=f),0===p.start&&(p.start=.2),p.text=n.eq(u).innerHTML.trim().replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi,"<a href='$1' target='_blank'>$1</a>"),o.push(p)}return o}}}},{16:16,2:2,24:24,25:25,28:28,4:4,6:6}],13:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=e(16),r=i(a),s=i(e(4)),l=e(23),d=e(25),u=e(24);Object.assign(a.config,{muteText:null,unmuteText:null,allyVolumeControlText:null,hideVolumeOnTouchDevices:!0,audioVolume:"horizontal",videoVolume:"vertical",startVolume:.8}),Object.assign(r.default.prototype,{buildvolume:function(e,t,n,i){if(!l.IS_ANDROID&&!l.IS_IOS||!this.options.hideVolumeOnTouchDevices){var a=this,r=a.isVideo?a.options.videoVolume:a.options.audioVolume,c=(0,d.isString)(a.options.muteText)?a.options.muteText:s.default.t("mejs.mute"),f=(0,d.isString)(a.options.unmuteText)?a.options.unmuteText:s.default.t("mejs.unmute"),p=(0,d.isString)(a.options.allyVolumeControlText)?a.options.allyVolumeControlText:s.default.t("mejs.volume-help-text"),m=o.default.createElement("div");if(m.className=a.options.classPrefix+"button "+a.options.classPrefix+"volume-button "+a.options.classPrefix+"mute",m.innerHTML="horizontal"===r?'<button type="button" aria-controls="'+a.id+'" title="'+c+'" aria-label="'+c+'" tabindex="0"></button>':'<button type="button" aria-controls="'+a.id+'" title="'+c+'" aria-label="'+c+'" tabindex="0"></button><a href="javascript:void(0);" class="'+a.options.classPrefix+'volume-slider" aria-label="'+s.default.t("mejs.volume-slider")+'" aria-valuemin="0" aria-valuemax="100" role="slider" aria-orientation="vertical"><span class="'+a.options.classPrefix+'offscreen">'+p+'</span><div class="'+a.options.classPrefix+'volume-total"><div class="'+a.options.classPrefix+'volume-current"></div><div class="'+a.options.classPrefix+'volume-handle"></div></div></a>',a.addControlElement(m,"volume"),"horizontal"===r){var h=o.default.createElement("a");h.className=a.options.classPrefix+"horizontal-volume-slider",h.href="javascript:void(0);",h.setAttribute("aria-label",s.default.t("mejs.volume-slider")),h.setAttribute("aria-valuemin",0),h.setAttribute("aria-valuemax",100),h.setAttribute("role","slider"),h.innerHTML+='<span class="'+a.options.classPrefix+'offscreen">'+p+'</span><div class="'+a.options.classPrefix+'horizontal-volume-total"><div class="'+a.options.classPrefix+'horizontal-volume-current"></div><div class="'+a.options.classPrefix+'horizontal-volume-handle"></div></div>',m.parentNode.insertBefore(h,m.nextSibling)}var v=!1,y=!1,g=!1,b=function(){var e=Math.floor(100*i.volume);E.setAttribute("aria-valuenow",e),E.setAttribute("aria-valuetext",e+"%")},E="vertical"===r?a.container.querySelector("."+a.options.classPrefix+"volume-slider"):a.container.querySelector("."+a.options.classPrefix+"horizontal-volume-slider"),S="vertical"===r?a.container.querySelector("."+a.options.classPrefix+"volume-total"):a.container.querySelector("."+a.options.classPrefix+"horizontal-volume-total"),x="vertical"===r?a.container.querySelector("."+a.options.classPrefix+"volume-current"):a.container.querySelector("."+a.options.classPrefix+"horizontal-volume-current"),w="vertical"===r?a.container.querySelector("."+a.options.classPrefix+"volume-handle"):a.container.querySelector("."+a.options.classPrefix+"horizontal-volume-handle"),P=function(e){if(null!==e&&!isNaN(e)&&void 0!==e){if(e=Math.max(0,e),0===(e=Math.min(e,1))){(0,u.removeClass)(m,a.options.classPrefix+"mute"),(0,u.addClass)(m,a.options.classPrefix+"unmute");var t=m.firstElementChild;t.setAttribute("title",f),t.setAttribute("aria-label",f)}else{(0,u.removeClass)(m,a.options.classPrefix+"unmute"),(0,u.addClass)(m,a.options.classPrefix+"mute");var n=m.firstElementChild;n.setAttribute("title",c),n.setAttribute("aria-label",c)}var i=100*e+"%",o=getComputedStyle(w);"vertical"===r?(x.style.bottom=0,x.style.height=i,w.style.bottom=i,w.style.marginBottom=-parseFloat(o.height)/2+"px"):(x.style.left=0,x.style.width=i,w.style.left=i,w.style.marginLeft=-parseFloat(o.width)/2+"px")}},T=function(e){var t=(0,u.offset)(S),n=getComputedStyle(S);g=!0;var o=null;if("vertical"===r){var a=parseFloat(n.height);if(o=(a-(e.pageY-t.top))/a,0===t.top||0===t.left)return}else{var s=parseFloat(n.width);o=(e.pageX-t.left)/s}o=Math.max(0,o),o=Math.min(o,1),P(o),i.setMuted(0===o),i.setVolume(o),e.preventDefault(),e.stopPropagation()},C=function(){i.muted?(P(0),(0,u.removeClass)(m,a.options.classPrefix+"mute"),(0,u.addClass)(m,a.options.classPrefix+"unmute")):(P(i.volume),(0,u.removeClass)(m,a.options.classPrefix+"unmute"),(0,u.addClass)(m,a.options.classPrefix+"mute"))};m.addEventListener("mouseenter",function(e){e.target===m&&(E.style.display="block",y=!0,e.preventDefault(),e.stopPropagation())}),m.addEventListener("focusin",function(){E.style.display="block",y=!0}),m.addEventListener("focusout",function(e){e.relatedTarget&&(!e.relatedTarget||e.relatedTarget.matches("."+a.options.classPrefix+"volume-slider"))||"vertical"!==r||(E.style.display="none")}),m.addEventListener("mouseleave",function(){y=!1,v||"vertical"!==r||(E.style.display="none")}),m.addEventListener("focusout",function(){y=!1}),m.addEventListener("keydown",function(e){if(a.options.keyActions.length){var t=e.which||e.keyCode||0,n=i.volume;switch(t){case 38:n=Math.min(n+.1,1);break;case 40:n=Math.max(0,n-.1);break;default:return!0}v=!1,P(n),i.setVolume(n),e.preventDefault(),e.stopPropagation()}}),m.querySelector("button").addEventListener("click",function(){i.setMuted(!i.muted);var e=(0,d.createEvent)("volumechange",i);i.dispatchEvent(e)}),E.addEventListener("dragstart",function(){return!1}),E.addEventListener("mouseover",function(){y=!0}),E.addEventListener("focusin",function(){E.style.display="block",y=!0}),E.addEventListener("focusout",function(){y=!1,v||"vertical"!==r||(E.style.display="none")}),E.addEventListener("mousedown",function(e){T(e),a.globalBind("mousemove.vol",function(e){var t=e.target;v&&(t===E||t.closest("vertical"===r?"."+a.options.classPrefix+"volume-slider":"."+a.options.classPrefix+"horizontal-volume-slider"))&&T(e)}),a.globalBind("mouseup.vol",function(){v=!1,a.globalUnbind("mousemove.vol mouseup.vol"),y||"vertical"!==r||(E.style.display="none")}),v=!0,e.preventDefault(),e.stopPropagation()}),i.addEventListener("volumechange",function(e){v||C(),b()});var k=!1;i.addEventListener("rendererready",function(){g||setTimeout(function(){k=!0,(0===e.options.startVolume||i.originalNode.muted)&&(i.setMuted(!0),e.options.startVolume=0),i.setVolume(e.options.startVolume),a.setControlsSize()},250)}),i.addEventListener("loadedmetadata",function(){setTimeout(function(){g||k||((0===e.options.startVolume||i.originalNode.muted)&&(i.setMuted(!0),e.options.startVolume=0),i.setVolume(e.options.startVolume),a.setControlsSize()),k=!1},250)}),(0===e.options.startVolume||i.originalNode.muted)&&(i.setMuted(!0),e.options.startVolume=0,C()),i.setVolume(e.options.startVolume),a.container.addEventListener("controlsresize",function(){C()})}}})},{16:16,2:2,23:23,24:24,25:25,4:4}],14:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});n.EN={"mejs.plural-form":1,"mejs.download-file":"Download File","mejs.install-flash":"You are using a browser that does not have Flash player enabled or installed. Please turn on your Flash player plugin or download the latest version from https://get.adobe.com/flashplayer/","mejs.fullscreen":"Fullscreen","mejs.play":"Play","mejs.pause":"Pause","mejs.time-slider":"Time Slider","mejs.time-help-text":"Use Left/Right Arrow keys to advance one second, Up/Down arrows to advance ten seconds.","mejs.live-broadcast":"Live Broadcast","mejs.volume-help-text":"Use Up/Down Arrow keys to increase or decrease volume.","mejs.unmute":"Unmute","mejs.mute":"Mute","mejs.volume-slider":"Volume Slider","mejs.video-player":"Video Player","mejs.audio-player":"Audio Player","mejs.captions-subtitles":"Captions/Subtitles","mejs.captions-chapters":"Chapters","mejs.none":"None","mejs.afrikaans":"Afrikaans","mejs.albanian":"Albanian","mejs.arabic":"Arabic","mejs.belarusian":"Belarusian","mejs.bulgarian":"Bulgarian","mejs.catalan":"Catalan","mejs.chinese":"Chinese","mejs.chinese-simplified":"Chinese (Simplified)","mejs.chinese-traditional":"Chinese (Traditional)","mejs.croatian":"Croatian","mejs.czech":"Czech","mejs.danish":"Danish","mejs.dutch":"Dutch","mejs.english":"English","mejs.estonian":"Estonian","mejs.filipino":"Filipino","mejs.finnish":"Finnish","mejs.french":"French","mejs.galician":"Galician","mejs.german":"German","mejs.greek":"Greek","mejs.haitian-creole":"Haitian Creole","mejs.hebrew":"Hebrew","mejs.hindi":"Hindi","mejs.hungarian":"Hungarian","mejs.icelandic":"Icelandic","mejs.indonesian":"Indonesian","mejs.irish":"Irish","mejs.italian":"Italian","mejs.japanese":"Japanese","mejs.korean":"Korean","mejs.latvian":"Latvian","mejs.lithuanian":"Lithuanian","mejs.macedonian":"Macedonian","mejs.malay":"Malay","mejs.maltese":"Maltese","mejs.norwegian":"Norwegian","mejs.persian":"Persian","mejs.polish":"Polish","mejs.portuguese":"Portuguese","mejs.romanian":"Romanian","mejs.russian":"Russian","mejs.serbian":"Serbian","mejs.slovak":"Slovak","mejs.slovenian":"Slovenian","mejs.spanish":"Spanish","mejs.swahili":"Swahili","mejs.swedish":"Swedish","mejs.tagalog":"Tagalog","mejs.thai":"Thai","mejs.turkish":"Turkish","mejs.ukrainian":"Ukrainian","mejs.vietnamese":"Vietnamese","mejs.welsh":"Welsh","mejs.yiddish":"Yiddish"}},{}],15:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(6));"undefined"!=typeof jQuery?a.default.$=o.default.jQuery=o.default.$=jQuery:"undefined"!=typeof Zepto?a.default.$=o.default.Zepto=o.default.$=Zepto:"undefined"!=typeof ender&&(a.default.$=o.default.ender=o.default.$=ender)},{3:3,6:6}],16:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0}),n.config=void 0;var a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),s=i(e(3)),l=i(e(2)),d=i(e(6)),u=i(e(5)),c=i(e(4)),f=e(23),p=e(25),m=e(28),h=e(26),v=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}(e(24));d.default.mepIndex=0,d.default.players={};var y=n.config={poster:"",showPosterWhenEnded:!1,showPosterWhenPaused:!1,defaultVideoWidth:480,defaultVideoHeight:270,videoWidth:-1,videoHeight:-1,defaultAudioWidth:400,defaultAudioHeight:40,defaultSeekBackwardInterval:function(e){return.05*e.getDuration()},defaultSeekForwardInterval:function(e){return.05*e.getDuration()},setDimensions:!0,audioWidth:-1,audioHeight:-1,loop:!1,autoRewind:!0,enableAutosize:!0,timeFormat:"",alwaysShowHours:!1,showTimecodeFrameCount:!1,framesPerSecond:25,alwaysShowControls:!1,hideVideoControlsOnLoad:!1,hideVideoControlsOnPause:!1,clickToPlayPause:!0,controlsTimeoutDefault:1500,controlsTimeoutMouseEnter:2500,controlsTimeoutMouseLeave:1e3,iPadUseNativeControls:!1,iPhoneUseNativeControls:!1,AndroidUseNativeControls:!1,features:["playpause","current","progress","duration","tracks","volume","fullscreen"],isVideo:!0,stretching:"auto",classPrefix:"mejs__",enableKeyboard:!0,pauseOtherPlayers:!0,secondsDecimalLength:0,keyActions:[{keys:[32,179],action:function(e,t){f.IS_FIREFOX||(t.paused||t.ended?t.play():t.pause())}},{keys:[38],action:function(e,t){(e.container.querySelector("."+y.classPrefix+"volume-button>button").matches(":focus")||e.container.querySelector("."+y.classPrefix+"volume-slider").matches(":focus"))&&(e.container.querySelector("."+y.classPrefix+"volume-slider").style.display=""),e.isVideo&&(e.showControls(),e.startControlsTimer());var n=Math.min(t.volume+.1,1);t.setVolume(n),n>0&&t.setMuted(!1)}},{keys:[40],action:function(e,t){(e.container.querySelector("."+y.classPrefix+"volume-button>button").matches(":focus")||e.container.querySelector("."+y.classPrefix+"volume-slider").matches(":focus"))&&(e.container.querySelector("."+y.classPrefix+"volume-slider").style.display=""),e.isVideo&&(e.showControls(),e.startControlsTimer());var n=Math.max(t.volume-.1,0);t.setVolume(n),n<=.1&&t.setMuted(!0)}},{keys:[37,227],action:function(e,t){if(!isNaN(t.duration)&&t.duration>0){e.isVideo&&(e.showControls(),e.startControlsTimer());var n=Math.max(t.currentTime-e.options.defaultSeekBackwardInterval(t),0);t.setCurrentTime(n)}}},{keys:[39,228],action:function(e,t){if(!isNaN(t.duration)&&t.duration>0){e.isVideo&&(e.showControls(),e.startControlsTimer());var n=Math.min(t.currentTime+e.options.defaultSeekForwardInterval(t),t.duration);t.setCurrentTime(n)}}},{keys:[70],action:function(e,t,n,i){i.ctrlKey||void 0!==e.enterFullScreen&&(e.isFullScreen?e.exitFullScreen():e.enterFullScreen())}},{keys:[77],action:function(e){e.container.querySelector("."+y.classPrefix+"volume-slider").style.display="",e.isVideo&&(e.showControls(),e.startControlsTimer()),e.media.muted?e.setMuted(!1):e.setMuted(!0)}}]};d.default.MepDefaults=y;var g=function(){function e(t,n){o(this,e);var i=this,a="string"==typeof t?l.default.getElementById(t):t;if(i.hasFocus=!1,i.controlsAreVisible=!0,i.controlsEnabled=!0,i.controlsTimer=null,!(i instanceof e))return new e(a,n);if(i.node=i.media=a,i.node){if(void 0!==i.media.player)return i.media.player;if(void 0===n){var r=i.node.getAttribute("data-mejsoptions");n=r?JSON.parse(r):{}}i.options=Object.assign({},y,n),i.options.loop&&!i.media.getAttribute("loop")?(i.media.loop=!0,i.node.loop=!0):i.media.loop&&(i.options.loop=!0),i.options.timeFormat||(i.options.timeFormat="mm:ss",i.options.alwaysShowHours&&(i.options.timeFormat="hh:mm:ss"),i.options.showTimecodeFrameCount&&(i.options.timeFormat+=":ff")),(0,m.calculateTimeFormat)(0,i.options,i.options.framesPerSecond||25),i.id="mep_"+d.default.mepIndex++,d.default.players[i.id]=i;var s=Object.assign({},i.options,{success:function(e,t){i._meReady(e,t)},error:function(e){i._handleError(e)}}),g=i.node.tagName.toLowerCase();if(i.isDynamic="audio"!==g&&"video"!==g,i.isVideo=i.isDynamic?i.options.isVideo:"audio"!==g&&i.options.isVideo,i.mediaFiles=null,i.trackFiles=null,f.IS_IPAD&&i.options.iPadUseNativeControls||f.IS_IPHONE&&i.options.iPhoneUseNativeControls)i.node.setAttribute("controls",!0),f.IS_IPAD&&i.node.getAttribute("autoplay")&&i.play();else if(!(i.isVideo||!i.isVideo&&i.options.features.length)||f.IS_ANDROID&&i.options.AndroidUseNativeControls)i.isVideo||i.options.features.length||(i.node.style.display="none");else{i.node.removeAttribute("controls");var b=i.isVideo?c.default.t("mejs.video-player"):c.default.t("mejs.audio-player"),E=l.default.createElement("span");if(E.className=i.options.classPrefix+"offscreen",E.innerText=b,i.media.parentNode.insertBefore(E,i.media),i.container=l.default.createElement("div"),i.container.id=i.id,i.container.className=i.options.classPrefix+"container "+i.options.classPrefix+"container-keyboard-inactive "+i.media.className,i.container.tabIndex=0,i.container.setAttribute("role","application"),i.container.setAttribute("aria-label",b),i.container.innerHTML='<div class="'+i.options.classPrefix+'inner"><div class="'+i.options.classPrefix+'mediaelement"></div><div class="'+i.options.classPrefix+'layers"></div><div class="'+i.options.classPrefix+'controls"></div><div class="'+i.options.classPrefix+'clear"></div></div>',i.container.addEventListener("focus",function(e){if(!i.controlsAreVisible&&!i.hasFocus&&i.controlsEnabled){i.showControls(!0);var t=(0,p.isNodeAfter)(e.relatedTarget,i.container)?"."+i.options.classPrefix+"controls ."+i.options.classPrefix+"button:last-child > button":"."+i.options.classPrefix+"playpause-button > button";i.container.querySelector(t).focus()}}),i.node.parentNode.insertBefore(i.container,i.node),i.options.features.length||(i.container.style.background="transparent",i.container.querySelector("."+i.options.classPrefix+"controls").style.display="none"),i.isVideo&&"fill"===i.options.stretching&&!v.hasClass(i.container.parentNode,i.options.classPrefix+"fill-container")){i.outerContainer=i.media.parentNode;var S=l.default.createElement("div");S.className=i.options.classPrefix+"fill-container",i.container.parentNode.insertBefore(S,i.container),S.appendChild(i.container)}if(f.IS_ANDROID&&v.addClass(i.container,i.options.classPrefix+"android"),f.IS_IOS&&v.addClass(i.container,i.options.classPrefix+"ios"),f.IS_IPAD&&v.addClass(i.container,i.options.classPrefix+"ipad"),f.IS_IPHONE&&v.addClass(i.container,i.options.classPrefix+"iphone"),v.addClass(i.container,i.isVideo?i.options.classPrefix+"video":i.options.classPrefix+"audio"),f.IS_SAFARI&&!f.IS_IOS){v.addClass(i.container,i.options.classPrefix+"hide-cues");for(var x=i.node.cloneNode(),w=i.node.childNodes,P=[],T=[],C=0,k=w.length;C<k;C++){var _=w[C];_&&_.nodeType!==Node.TEXT_NODE&&function(){switch(_.tagName.toLowerCase()){case"source":var e={};Array.prototype.slice.call(_.attributes).forEach(function(t){e[t.name]=t.value}),e.type=(0,h.formatType)(e.src,e.type),P.push(e);break;case"track":_.mode="hidden",T.push(_);break;default:x.appendChild(_)}}()}i.node.remove(),i.node=i.media=x,P.length&&(i.mediaFiles=P),T.length&&(i.trackFiles=T)}i.container.querySelector("."+i.options.classPrefix+"mediaelement").appendChild(i.node),i.media.player=i,i.controls=i.container.querySelector("."+i.options.classPrefix+"controls"),i.layers=i.container.querySelector("."+i.options.classPrefix+"layers");var N=i.isVideo?"video":"audio",A=N.substring(0,1).toUpperCase()+N.substring(1);i.options[N+"Width"]>0||i.options[N+"Width"].toString().indexOf("%")>-1?i.width=i.options[N+"Width"]:""!==i.node.style.width&&null!==i.node.style.width?i.width=i.node.style.width:i.node.getAttribute("width")?i.width=i.node.getAttribute("width"):i.width=i.options["default"+A+"Width"],i.options[N+"Height"]>0||i.options[N+"Height"].toString().indexOf("%")>-1?i.height=i.options[N+"Height"]:""!==i.node.style.height&&null!==i.node.style.height?i.height=i.node.style.height:i.node.getAttribute("height")?i.height=i.node.getAttribute("height"):i.height=i.options["default"+A+"Height"],i.initialAspectRatio=i.height>=i.width?i.width/i.height:i.height/i.width,i.setPlayerSize(i.width,i.height),s.pluginWidth=i.width,s.pluginHeight=i.height}if(new u.default(i.media,s,i.mediaFiles),void 0!==i.container&&i.options.features.length&&i.controlsAreVisible&&!i.options.hideVideoControlsOnLoad){var L=(0,p.createEvent)("controlsshown",i.container);i.container.dispatchEvent(L)}return i}}return r(e,[{key:"showControls",value:function(e){var t=this;if(e=void 0===e||e,!t.controlsAreVisible&&t.isVideo){if(e)!function(){v.fadeIn(t.controls,200,function(){v.removeClass(t.controls,t.options.classPrefix+"offscreen");var e=(0,p.createEvent)("controlsshown",t.container);t.container.dispatchEvent(e)});for(var e=t.container.querySelectorAll("."+t.options.classPrefix+"control"),n=0,i=e.length;n<i;n++)!function(n,i){v.fadeIn(e[n],200,function(){v.removeClass(e[n],t.options.classPrefix+"offscreen")})}(n)}();else{v.removeClass(t.controls,t.options.classPrefix+"offscreen"),t.controls.style.display="",t.controls.style.opacity=1;for(var n=t.container.querySelectorAll("."+t.options.classPrefix+"control"),i=0,o=n.length;i<o;i++)v.removeClass(n[i],t.options.classPrefix+"offscreen"),n[i].style.display="";var a=(0,p.createEvent)("controlsshown",t.container);t.container.dispatchEvent(a)}t.controlsAreVisible=!0,t.setControlsSize()}}},{key:"hideControls",value:function(e,t){var n=this;if(e=void 0===e||e,!0===t||!(!n.controlsAreVisible||n.options.alwaysShowControls||n.keyboardAction||n.media.paused&&4===n.media.readyState&&(!n.options.hideVideoControlsOnLoad&&n.media.currentTime<=0||!n.options.hideVideoControlsOnPause&&n.media.currentTime>0)||n.isVideo&&!n.options.hideVideoControlsOnLoad&&!n.media.readyState||n.media.ended)){if(e)!function(){v.fadeOut(n.controls,200,function(){v.addClass(n.controls,n.options.classPrefix+"offscreen"),n.controls.style.display="";var e=(0,p.createEvent)("controlshidden",n.container);n.container.dispatchEvent(e)});for(var e=n.container.querySelectorAll("."+n.options.classPrefix+"control"),t=0,i=e.length;t<i;t++)!function(t,i){v.fadeOut(e[t],200,function(){v.addClass(e[t],n.options.classPrefix+"offscreen"),e[t].style.display=""})}(t)}();else{v.addClass(n.controls,n.options.classPrefix+"offscreen"),n.controls.style.display="",n.controls.style.opacity=0;for(var i=n.container.querySelectorAll("."+n.options.classPrefix+"control"),o=0,a=i.length;o<a;o++)v.addClass(i[o],n.options.classPrefix+"offscreen"),i[o].style.display="";var r=(0,p.createEvent)("controlshidden",n.container);n.container.dispatchEvent(r)}n.controlsAreVisible=!1}}},{key:"startControlsTimer",value:function(e){var t=this;e=void 0!==e?e:t.options.controlsTimeoutDefault,t.killControlsTimer("start"),t.controlsTimer=setTimeout(function(){t.hideControls(),t.killControlsTimer("hide")},e)}},{key:"killControlsTimer",value:function(){var e=this;null!==e.controlsTimer&&(clearTimeout(e.controlsTimer),delete e.controlsTimer,e.controlsTimer=null)}},{key:"disableControls",value:function(){var e=this;e.killControlsTimer(),e.controlsEnabled=!0,e.hideControls(!1,!0)}},{key:"enableControls",value:function(){var e=this;e.controlsEnabled=!0,e.showControls(!1)}},{key:"_meReady",value:function(e,t){var n=this,i=t.getAttribute("autoplay"),o=!(void 0===i||null===i||"false"===i),a=null!==e.rendererName&&/(native|html5)/i.test(n.media.rendererName);if(n.controls&&n.enableControls(),n.container&&n.container.querySelector("."+n.options.classPrefix+"overlay-play")&&(n.container.querySelector("."+n.options.classPrefix+"overlay-play").style.display=""),!n.created){if(n.created=!0,n.media=e,n.domNode=t,!(f.IS_ANDROID&&n.options.AndroidUseNativeControls||f.IS_IPAD&&n.options.iPadUseNativeControls||f.IS_IPHONE&&n.options.iPhoneUseNativeControls)){if(!n.isVideo&&!n.options.features.length)return o&&a&&n.play(),void(n.options.success&&("string"==typeof n.options.success?s.default[n.options.success](n.media,n.domNode,n):n.options.success(n.media,n.domNode,n)));n.buildposter(n,n.controls,n.layers,n.media),n.buildkeyboard(n,n.controls,n.layers,n.media),n.buildoverlays(n,n.controls,n.layers,n.media),n.findTracks(),n.featurePosition={};for(var r=0,u=n.options.features.length;r<u;r++){var c=n.options.features[r];if(n["build"+c])try{n["build"+c](n,n.controls,n.layers,n.media)}catch(e){console.error("error building "+c,e)}}var h=(0,p.createEvent)("controlsready",n.container);n.container.dispatchEvent(h),n.setPlayerSize(n.width,n.height),n.setControlsSize(),n.isVideo&&(n.clickToPlayPauseCallback=function(){if(n.options.clickToPlayPause){var e=n.container.querySelector("."+n.options.classPrefix+"overlay-button"),t=e.getAttribute("aria-pressed");n.media.paused&&t?n.pause():n.media.paused?n.play():n.pause(),e.setAttribute("aria-pressed",!t)}},n.createIframeLayer(),n.media.addEventListener("click",n.clickToPlayPauseCallback),!f.IS_ANDROID&&!f.IS_IOS||n.options.alwaysShowControls?(n.container.addEventListener("mouseenter",function(){n.controlsEnabled&&(n.options.alwaysShowControls||(n.killControlsTimer("enter"),n.showControls(),n.startControlsTimer(n.options.controlsTimeoutMouseEnter)))}),n.container.addEventListener("mousemove",function(){n.controlsEnabled&&(n.controlsAreVisible||n.showControls(),n.options.alwaysShowControls||n.startControlsTimer(n.options.controlsTimeoutMouseEnter))}),n.container.addEventListener("mouseleave",function(){n.controlsEnabled&&(n.media.paused||n.options.alwaysShowControls||n.startControlsTimer(n.options.controlsTimeoutMouseLeave))})):n.node.addEventListener("touchstart",function(){n.controlsAreVisible?n.hideControls(!1):n.controlsEnabled&&n.showControls(!1)}),n.options.hideVideoControlsOnLoad&&n.hideControls(!1),o&&!n.options.alwaysShowControls&&n.hideControls(),n.options.enableAutosize&&n.media.addEventListener("loadedmetadata",function(e){var t=void 0!==e?e.detail.target||e.target:n.media;n.options.videoHeight<=0&&!n.domNode.getAttribute("height")&&null!==t&&!isNaN(t.videoHeight)&&(n.setPlayerSize(t.videoWidth,t.videoHeight),n.setControlsSize(),n.media.setSize(t.videoWidth,t.videoHeight))})),n.media.addEventListener("play",function(){n.hasFocus=!0;for(var e in d.default.players)if(d.default.players.hasOwnProperty(e)){var t=d.default.players[e];t.id===n.id||!n.options.pauseOtherPlayers||t.paused||t.ended||(t.pause(),t.hasFocus=!1)}}),n.media.addEventListener("ended",function(){if(n.options.autoRewind)try{n.media.setCurrentTime(0),setTimeout(function(){var e=n.container.querySelector("."+n.options.classPrefix+"overlay-loading");e&&e.parentNode&&(e.parentNode.style.display="none")},20)}catch(e){}"function"==typeof n.media.stop?n.media.stop():n.media.pause(),n.setProgressRail&&n.setProgressRail(),n.setCurrentRail&&n.setCurrentRail(),n.options.loop?n.play():!n.options.alwaysShowControls&&n.controlsEnabled&&n.showControls()}),n.media.addEventListener("loadedmetadata",function(){(0,m.calculateTimeFormat)(n.duration,n.options,n.options.framesPerSecond||25),n.updateDuration&&n.updateDuration(),n.updateCurrent&&n.updateCurrent(),n.isFullScreen||(n.setPlayerSize(n.width,n.height),n.setControlsSize())});var y=null;n.media.addEventListener("timeupdate",function(){isNaN(n.media.getDuration())||y===n.media.getDuration()||(y=n.media.getDuration(),(0,m.calculateTimeFormat)(y,n.options,n.options.framesPerSecond||25),n.updateDuration&&n.updateDuration(),n.updateCurrent&&n.updateCurrent(),n.setControlsSize())}),n.container.addEventListener("click",function(e){v.addClass(e.currentTarget,n.options.classPrefix+"container-keyboard-inactive")}),n.container.addEventListener("focusin",function(e){v.removeClass(e.currentTarget,n.options.classPrefix+"container-keyboard-inactive"),n.controlsEnabled&&!n.options.alwaysShowControls&&n.showControls(!1)}),n.container.addEventListener("focusout",function(e){setTimeout(function(){e.relatedTarget&&n.keyboardAction&&!e.relatedTarget.closest("."+n.options.classPrefix+"container")&&(n.keyboardAction=!1,n.isVideo&&!n.options.alwaysShowControls&&n.hideControls(!0))},0)}),setTimeout(function(){n.setPlayerSize(n.width,n.height),n.setControlsSize()},0),n.globalBind("resize",function(){n.isFullScreen||f.HAS_TRUE_NATIVE_FULLSCREEN&&l.default.webkitIsFullScreen||n.setPlayerSize(n.width,n.height),n.setControlsSize()})}o&&a&&n.play(),n.options.success&&("string"==typeof n.options.success?s.default[n.options.success](n.media,n.domNode,n):n.options.success(n.media,n.domNode,n))}}},{key:"_handleError",value:function(e){var t=this;t.controls&&t.disableControls();var n=t.layers.querySelector("."+t.options.classPrefix+"overlay-play");n&&(n.style.display="none"),t.options.error&&t.options.error(e)}},{key:"setPlayerSize",value:function(e,t){var n=this;if(!n.options.setDimensions)return!1;switch(void 0!==e&&(n.width=e),void 0!==t&&(n.height=t),n.options.stretching){case"fill":n.isVideo?n.setFillMode():n.setDimensions(n.width,n.height);break;case"responsive":n.setResponsiveMode();break;case"none":n.setDimensions(n.width,n.height);break;default:!0===n.hasFluidMode()?n.setResponsiveMode():n.setDimensions(n.width,n.height)}}},{key:"hasFluidMode",value:function(){var e=this;return-1!==e.height.toString().indexOf("%")||e.node&&e.node.style.maxWidth&&"none"!==e.node.style.maxWidth&&e.node.style.maxWidth!==e.width||e.node&&e.node.currentStyle&&"100%"===e.node.currentStyle.maxWidth}},{key:"setResponsiveMode",value:function(){var e=this,t=function(){for(var t=void 0,n=e.container;n;){try{if(f.IS_FIREFOX&&"html"===n.tagName.toLowerCase()&&s.default.self!==s.default.top&&null!==s.default.frameElement)return s.default.frameElement;t=n.parentElement}catch(e){t=n.parentElement}if(t&&v.visible(t))return t;n=t}return null}(),n=t?getComputedStyle(t,null):getComputedStyle(l.default.body,null),i=function(){return e.isVideo?e.media.videoWidth&&e.media.videoWidth>0?e.media.videoWidth:e.node.getAttribute("width")?e.node.getAttribute("width"):e.options.defaultVideoWidth:e.options.defaultAudioWidth}(),o=function(){return e.isVideo?e.media.videoHeight&&e.media.videoHeight>0?e.media.videoHeight:e.node.getAttribute("height")?e.node.getAttribute("height"):e.options.defaultVideoHeight:e.options.defaultAudioHeight}(),a=function(){var t=1;return e.isVideo?(t=e.media.videoWidth&&e.media.videoWidth>0&&e.media.videoHeight&&e.media.videoHeight>0?e.height>=e.width?e.media.videoWidth/e.media.videoHeight:e.media.videoHeight/e.media.videoWidth:e.initialAspectRatio,(isNaN(t)||t<.01||t>100)&&(t=1),t):t}(),r=parseFloat(n.height),d=void 0,u=parseFloat(n.width);if(d=e.isVideo?"100%"===e.height?parseFloat(u*o/i,10):e.height>=e.width?parseFloat(u/a,10):parseFloat(u*a,10):o,isNaN(d)&&(d=r),e.container.parentNode.length>0&&"body"===e.container.parentNode.tagName.toLowerCase()&&(u=s.default.innerWidth||l.default.documentElement.clientWidth||l.default.body.clientWidth,d=s.default.innerHeight||l.default.documentElement.clientHeight||l.default.body.clientHeight),d&&u){e.container.style.width=u+"px",e.container.style.height=d+"px",e.node.style.width="100%",e.node.style.height="100%",e.isVideo&&e.media.setSize&&e.media.setSize(u,d);for(var c=e.layers.childNodes,p=0,m=c.length;p<m;p++)c[p].style.width="100%",c[p].style.height="100%"}}},{key:"setFillMode",value:function(){var e=this,t=void 0,n=!1;try{s.default.self!==s.default.top?(n=!0,t=s.default.frameElement):t=e.outerContainer}catch(n){t=e.outerContainer}var i=getComputedStyle(t);"none"!==e.node.style.height&&e.node.style.height!==e.height&&(e.node.style.height="auto"),"none"!==e.node.style.maxWidth&&e.node.style.maxWidth!==e.width&&(e.node.style.maxWidth="none"),"none"!==e.node.style.maxHeight&&e.node.style.maxHeight!==e.height&&(e.node.style.maxHeight="none"),e.node.currentStyle&&("100%"===e.node.currentStyle.height&&(e.node.currentStyle.height="auto"),"100%"===e.node.currentStyle.maxWidth&&(e.node.currentStyle.maxWidth="none"),"100%"===e.node.currentStyle.maxHeight&&(e.node.currentStyle.maxHeight="none")),n||parseFloat(i.width)||(t.style.width=e.media.offsetWidth+"px"),n||parseFloat(i.height)||(t.style.height=e.media.offsetHeight+"px"),i=getComputedStyle(t);var o=parseFloat(i.width),a=parseFloat(i.height);e.setDimensions("100%","100%");var r=e.container.querySelector(e.options.classPrefix+"poster img");r&&(r.style.display="");for(var l=e.container.querySelectorAll("object, embed, iframe, video"),d=e.height,u=e.width,c=o,f=d*o/u,p=u*a/d,m=a,h=p>o==!1,v=h?Math.floor(c):Math.floor(p),y=h?Math.floor(f):Math.floor(m),g=h?o+"px":v+"px",b=h?y+"px":a+"px",E=0,S=l.length;E<S;E++)l[E].style.height=b,l[E].style.width=g,e.media.setSize&&e.media.setSize(g,b),l[E].style.marginLeft=Math.floor((o-v)/2)+"px",l[E].style.marginTop=0}},{key:"setDimensions",value:function(e,t){var n=this;e=(0,p.isString)(e)&&e.indexOf("%")>-1?e:parseFloat(e)+"px",t=(0,p.isString)(t)&&t.indexOf("%")>-1?t:parseFloat(t)+"px",n.container.style.width=e,n.container.style.height=t;for(var i=n.layers.childNodes,o=0,a=i.length;o<a;o++)i[o].style.width=e,i[o].style.height=t}},{key:"setControlsSize",value:function(){var e=this;if(v.visible(e.container))if(e.rail&&v.visible(e.rail)){for(var t=e.total?getComputedStyle(e.total,null):null,n=t?parseFloat(t.marginLeft)+parseFloat(t.marginRight):0,i=getComputedStyle(e.rail),o=parseFloat(i.marginLeft)+parseFloat(i.marginRight),a=0,r=v.siblings(e.rail,function(t){return t!==e.rail}),s=r.length,l=0;l<s;l++)a+=r[l].offsetWidth;a+=n+(0===n?2*o:o)+1,e.container.style.minWidth=a+"px";var d=parseFloat(e.controls.offsetWidth);e.rail.style.width=(a>d?0:d-a)+"px";var u=(0,p.createEvent)("controlsresize",e.container);e.container.dispatchEvent(u)}else{for(var c=e.controls.childNodes,f=0,m=0,h=c.length;m<h;m++)f+=c[m].offsetWidth;e.container.style.minWidth=f+"px"}}},{key:"addControlElement",value:function(e,t){var n=this;if(void 0!==n.featurePosition[t]){var i=n.controls.childNodes[n.featurePosition[t]-1];i.parentNode.insertBefore(e,i.nextSibling)}else{n.controls.appendChild(e);for(var o=n.controls.childNodes,a=0,r=o.length;a<r;a++)if(e==o[a]){n.featurePosition[t]=a;break}}}},{key:"createIframeLayer",value:function(){var e=this;if(e.isVideo&&null!==e.media.rendererName&&e.media.rendererName.indexOf("iframe")>-1&&!l.default.getElementById(e.media.id+"-iframe-overlay")){var t=l.default.createElement("div"),n=l.default.getElementById(e.media.id+"_"+e.media.rendererName);t.id=e.media.id+"-iframe-overlay",t.className=e.options.classPrefix+"iframe-overlay",t.addEventListener("click",function(t){e.options.clickToPlayPause&&(e.media.paused?e.media.play():e.media.pause(),t.preventDefault(),t.stopPropagation())}),n.parentNode.insertBefore(t,n)}}},{key:"resetSize",value:function(){var e=this;setTimeout(function(){e.setPlayerSize(e.width,e.height),e.setControlsSize()},50)}},{key:"setPoster",value:function(e){var t=this,n=t.container.querySelector("."+t.options.classPrefix+"poster"),i=n.querySelector("img");i||((i=l.default.createElement("img")).className=t.options.classPrefix+"poster-img",i.width="100%",i.height="100%",n.appendChild(i)),i.setAttribute("src",e),n.style.backgroundImage='url("'+e+'")'}},{key:"changeSkin",value:function(e){var t=this;t.container.className=t.options.classPrefix+"container "+e,t.setPlayerSize(t.width,t.height),t.setControlsSize()}},{key:"globalBind",value:function(e,t){var n=this,i=n.node?n.node.ownerDocument:l.default;if((e=(0,p.splitEvents)(e,n.id)).d)for(var o=e.d.split(" "),a=0,r=o.length;a<r;a++)o[a].split(".").reduce(function(e,n){return i.addEventListener(n,t,!1),n},"");if(e.w)for(var d=e.w.split(" "),u=0,c=d.length;u<c;u++)d[u].split(".").reduce(function(e,n){return s.default.addEventListener(n,t,!1),n},"")}},{key:"globalUnbind",value:function(e,t){var n=this,i=n.node?n.node.ownerDocument:l.default;if((e=(0,p.splitEvents)(e,n.id)).d)for(var o=e.d.split(" "),a=0,r=o.length;a<r;a++)o[a].split(".").reduce(function(e,n){return i.removeEventListener(n,t,!1),n},"");if(e.w)for(var d=e.d.split(" "),u=0,c=d.length;u<c;u++)d[u].split(".").reduce(function(e,n){return s.default.removeEventListener(n,t,!1),n},"")}},{key:"buildposter",value:function(e,t,n,i){var o=this,a=l.default.createElement("div");a.className=o.options.classPrefix+"poster "+o.options.classPrefix+"layer",n.appendChild(a);var r=e.media.getAttribute("poster");""!==e.options.poster&&(r=e.options.poster),r?o.setPoster(r):a.style.display="none",i.addEventListener("play",function(){a.style.display="none"}),i.addEventListener("playing",function(){a.style.display="none"}),e.options.showPosterWhenEnded&&e.options.autoRewind&&i.addEventListener("ended",function(){a.style.display=""}),i.addEventListener("error",function(){a.style.display="none"}),e.options.showPosterWhenPaused&&i.addEventListener("pause",function(){i.ended||(a.style.display="")})}},{key:"buildoverlays",value:function(e,t,n,i){if(e.isVideo){var o=this,a=l.default.createElement("div"),r=l.default.createElement("div"),s=l.default.createElement("div"),d=t.querySelector("."+o.options.classPrefix+"time-buffering");a.style.display="none",a.className=o.options.classPrefix+"overlay "+o.options.classPrefix+"layer",a.innerHTML='<div class="'+o.options.classPrefix+'overlay-loading"><span class="'+o.options.classPrefix+'overlay-loading-bg-img"></span></div>',n.appendChild(a),r.style.display="none",r.className=o.options.classPrefix+"overlay "+o.options.classPrefix+"layer",r.innerHTML='<div class="'+o.options.classPrefix+'overlay-error"></div>',n.appendChild(r),s.className=o.options.classPrefix+"overlay "+o.options.classPrefix+"layer "+o.options.classPrefix+"overlay-play",s.innerHTML='<div class="'+o.options.classPrefix+'overlay-button" role="button" tabindex="0"aria-label="'+c.default.t("mejs.play")+'" aria-pressed="false"></div>',s.addEventListener("click",function(){if(o.options.clickToPlayPause){var e=o.container.querySelector("."+o.options.classPrefix+"overlay-button"),t=e.getAttribute("aria-pressed");i.paused?i.play():i.pause(),e.setAttribute("aria-pressed",!!t)}}),s.addEventListener("keydown",function(e){var t=e.keyCode||e.which||0;if(13===t||f.IS_FIREFOX&&32===t){var n=(0,p.createEvent)("click",s);return s.dispatchEvent(n),!1}}),n.appendChild(s),null!==o.media.rendererName&&(/(youtube|facebook)/i.test(o.media.rendererName)&&!e.media.originalNode.getAttribute("poster")&&!e.options.poster||f.IS_STOCK_ANDROID)&&(s.style.display="none"),i.addEventListener("play",function(){s.style.display="none",a.style.display="none",d&&(d.style.display="none"),r.style.display="none"}),i.addEventListener("playing",function(){s.style.display="none",a.style.display="none",d&&(d.style.display="none"),r.style.display="none"}),i.addEventListener("seeking",function(){s.style.display="none",a.style.display="",d&&(d.style.display="")}),i.addEventListener("seeked",function(){s.style.display=i.paused&&!f.IS_STOCK_ANDROID?"":"none",a.style.display="none",d&&(d.style.display="")}),i.addEventListener("pause",function(){a.style.display="none",f.IS_STOCK_ANDROID||(s.style.display=""),d&&(d.style.display="none")}),i.addEventListener("waiting",function(){a.style.display="",d&&(d.style.display="")}),i.addEventListener("loadeddata",function(){a.style.display="",d&&(d.style.display=""),f.IS_ANDROID&&(i.canplayTimeout=setTimeout(function(){if(l.default.createEvent){var e=l.default.createEvent("HTMLEvents");return e.initEvent("canplay",!0,!0),i.dispatchEvent(e)}},300))}),i.addEventListener("canplay",function(){a.style.display="none",d&&(d.style.display="none"),clearTimeout(i.canplayTimeout)}),i.addEventListener("error",function(e){o._handleError(e),a.style.display="none",s.style.display="none",d&&(d.style.display="none"),e.message&&(r.style.display="block",r.querySelector("."+o.options.classPrefix+"overlay-error").innerHTML=e.message)}),i.addEventListener("keydown",function(t){o.onkeydown(e,i,t)})}}},{key:"buildkeyboard",value:function(e,t,n,i){var o=this;o.container.addEventListener("keydown",function(){o.keyboardAction=!0}),o.globalBind("keydown",function(t){var n=l.default.activeElement.closest("."+o.options.classPrefix+"container"),a=o.media.closest("."+o.options.classPrefix+"container");return o.hasFocus=!(!n||!a||n.id!==a.id),o.onkeydown(e,i,t)}),o.globalBind("click",function(e){o.hasFocus=!!e.target.closest("."+o.options.classPrefix+"container")})}},{key:"onkeydown",value:function(e,t,n){if(e.hasFocus&&e.options.enableKeyboard)for(var i=0,o=e.options.keyActions.length;i<o;i++)for(var a=e.options.keyActions[i],r=0,s=a.keys.length;r<s;r++)n.keyCode===a.keys[r]&&(a.action(e,t,n.keyCode,n),n.preventDefault(),n.stopPropagation());return!0}},{key:"play",value:function(){var e=this;e.media.getCurrentTime()<=0&&e.load(),e.media.play()}},{key:"pause",value:function(){try{this.media.pause()}catch(e){}}},{key:"load",value:function(){var e=this;e.isLoaded||e.media.load(),e.isLoaded=!0}},{key:"setMuted",value:function(e){this.media.setMuted(e)}},{key:"setCurrentTime",value:function(e){this.media.setCurrentTime(e)}},{key:"getCurrentTime",value:function(){return this.media.currentTime}},{key:"getDuration",value:function(){return this.media.duration}},{key:"setVolume",value:function(e){this.media.setVolume(e)}},{key:"getVolume",value:function(){return this.media.volume}},{key:"setSrc",value:function(e){var t=this,n=l.default.getElementById(t.media.id+"-iframe-overlay");n&&n.remove(),t.media.setSrc(e),t.createIframeLayer()}},{key:"remove",value:function(){var e=this,t=e.media.rendererName;e.media.paused||e.media.pause();var n=e.media.getSrc();e.media.setSrc("");for(var i in e.options.features){var o=e.options.features[i];if(e["clean"+o])try{e["clean"+o](e)}catch(e){console.error("error cleaning "+o,e)}}var r=e.node.getAttribute("width"),s=e.node.getAttribute("height");r?-1===r.indexOf("%")&&(r+="px"):r="auto",s?-1===s.indexOf("%")&&(s+="px"):s="auto",e.node.style.width=r,e.node.style.height=s,e.isDynamic?e.container.parentNode.insertBefore(e.node,e.container):function(){e.node.setAttribute("controls",!0),e.node.setAttribute("id",e.node.getAttribute("id").replace("_"+t,"").replace("_from_mejs","")),delete e.node.autoplay,""!==e.media.canPlayType((0,h.getTypeFromFile)(n))&&e.node.setAttribute("src",n),~t.indexOf("iframe")&&l.default.getElementById(e.media.id+"-iframe-overlay").remove();var i=e.node.cloneNode();if(i.style.display="",e.container.parentNode.insertBefore(i,e.container),e.node.remove(),e.mediaFiles)for(var o=0,a=e.mediaFiles.length;o<a;o++){var r=l.default.createElement("source");r.setAttribute("src",e.mediaFiles[o].src),r.setAttribute("type",e.mediaFiles[o].type),i.appendChild(r)}if(e.trackFiles)for(var s=0,d=e.trackFiles.length;s<d;s++)!function(t,n){var o=e.trackFiles[t],a=l.default.createElement("track");a.kind=o.kind,a.label=o.label,a.srclang=o.srclang,a.src=o.src,i.appendChild(a),a.addEventListener("load",function(){this.mode="showing",i.textTracks[t].mode="showing"})}(s);delete e.node,delete e.mediaFiles,delete e.trackFiles}(),"function"==typeof e.media.destroy&&e.media.destroy(),delete d.default.players[e.id],"object"===a(e.container)&&(e.container.parentNode.querySelector("."+e.options.classPrefix+"offscreen").remove(),e.container.remove()),e.globalUnbind(),delete e.media.player}}]),e}();s.default.MediaElementPlayer=g,n.default=g,function(e){void 0!==e&&(e.fn.mediaelementplayer=function(t){return!1===t?this.each(function(){var t=e(this).data("mediaelementplayer");t&&t.remove(),e(this).removeData("mediaelementplayer")}):this.each(function(){e(this).data("mediaelementplayer",new g(this,t))}),this},e(l.default).ready(function(){e("."+y.classPrefix+"player").mediaelementplayer()}))}(d.default.$)},{2:2,23:23,24:24,25:25,26:26,28:28,3:3,4:4,5:5,6:6}],17:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=i(e(3)),r=i(e(6)),s=e(7),l=e(25),d=e(26),u=e(23),c=e(24),f={promise:null,load:function(e){"undefined"!=typeof dashjs?f._createPlayer(e):(e.options.path="string"==typeof e.options.path?e.options.path:"https://cdn.dashjs.org/latest/dash.all.min.js",f.promise=f.promise||(0,c.loadScript)(e.options.path),f.promise.then(function(){f._createPlayer(e)}))},_createPlayer:function(e){var t=dashjs.MediaPlayer().create();a.default["__ready__"+e.id](t)}},p={name:"native_dash",options:{prefix:"native_dash",dash:{path:"https://cdn.dashjs.org/latest/dash.all.min.js",debug:!1,drm:{}}},canPlayType:function(e){return u.HAS_MSE&&["application/dash+xml"].indexOf(e.toLowerCase())>-1},create:function(e,t,n){var i=e.originalNode,d=e.id+"_"+t.prefix,u=i.getAttribute("preload"),c=i.autoplay,p=null,m=null;p=i.cloneNode(!0),t=Object.assign(t,e.options);for(var h=r.default.html5media.properties,v=0,y=h.length;v<y;v++)!function(e){var t=""+e.substring(0,1).toUpperCase()+e.substring(1);p["get"+t]=function(){return null!==m?p[e]:null},p["set"+t]=function(t){-1===r.default.html5media.readOnlyProperties.indexOf(e)&&("src"===e?"string"==typeof t?(p[e]=t,null!==m&&(m.attachSource(t),c&&p.play())):t&&"object"===(void 0===t?"undefined":o(t))&&t.src&&(p[e]=t.src,null!==m&&(t&&"object"===(void 0===t?"undefined":o(t))&&t.drm&&m.setProtectionData(t.drm),m.attachSource(t.src),c&&p.play())):p[e]=t)}}(h[v]);if(a.default["__ready__"+d]=function(n){e.dashPlayer=m=n,m.getDebug().setLogToBrowserConsole(t.dash.debug),m.setScheduleWhilePaused(u&&"auto"===u||c);for(var i=r.default.html5media.events.concat(["click","mouseover","mouseout"]),o=dashjs.MediaPlayer.events,a=0,s=i.length;a<s;a++)!function(n){"loadedmetadata"===n&&(m.initialize(p,null,c),m.setFastSwitchEnabled(!0),r.default.Utils.isObjectEmpty(t.dash.drm)||m.setProtectionData(t.dash.drm),m.attachSource(p.src)),p.addEventListener(n,function(t){var n=(0,l.createEvent)(t.type,e);e.dispatchEvent(n)})}(i[a]);var d=function(t){var n=(0,l.createEvent)(t.type,p);n.data=t,e.dispatchEvent(n),"error"===t.type.toLowerCase()&&console.error(t)};for(var f in o)o.hasOwnProperty(f)&&m.on(o[f],d)},n&&n.length>0)for(var g=0,b=n.length;g<b;g++)if(s.renderer.renderers[t.prefix].canPlayType(n[g].type)){p.setAttribute("src",n[g].src),void 0!==n[g].drm&&(t.dash.drm=n[g].drm);break}p.setAttribute("id",d),i.parentNode.insertBefore(p,i),i.autoplay=!1,i.style.display="none",f.load({options:t.dash,id:d}),p.setSize=function(e,t){return p.style.width=e+"px",p.style.height=t+"px",p},p.hide=function(){return p.pause(),p.style.display="none",p},p.show=function(){return p.style.display="",p};var E=(0,l.createEvent)("rendererready",p);return e.dispatchEvent(E),p}};d.typeChecks.push(function(e){return~e.toLowerCase().indexOf(".mpd")?"application/dash+xml":null}),s.renderer.add(p)},{23:23,24:24,25:25,26:26,3:3,6:6,7:7}],18:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(n,"__esModule",{value:!0}),n.PluginDetector=void 0;var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=i(e(3)),r=i(e(2)),s=i(e(6)),l=i(e(4)),d=e(7),u=e(25),c=e(23),f=e(26),p=n.PluginDetector={plugins:[],hasPluginVersion:function(e,t){var n=p.plugins[e];return t[1]=t[1]||0,t[2]=t[2]||0,n[0]>t[0]||n[0]===t[0]&&n[1]>t[1]||n[0]===t[0]&&n[1]===t[1]&&n[2]>=t[2]},addPlugin:function(e,t,n,i,o){p.plugins[e]=p.detectPlugin(t,n,i,o)},detectPlugin:function(e,t,n,i){var r=[0,0,0],s=void 0,l=void 0;if(null!==c.NAV.plugins&&void 0!==c.NAV.plugins&&"object"===o(c.NAV.plugins[e])){if((s=c.NAV.plugins[e].description)&&(void 0===c.NAV.mimeTypes||!c.NAV.mimeTypes[t]||c.NAV.mimeTypes[t].enabledPlugin))for(var d=0,u=(r=s.replace(e,"").replace(/^\s+/,"").replace(/\sr/gi,".").split(".")).length;d<u;d++)r[d]=parseInt(r[d].match(/\d+/),10)}else if(void 0!==a.default.ActiveXObject)try{(l=new ActiveXObject(n))&&(r=i(l))}catch(e){}return r}};p.addPlugin("flash","Shockwave Flash","application/x-shockwave-flash","ShockwaveFlash.ShockwaveFlash",function(e){var t=[],n=e.GetVariable("$version");return n&&(n=n.split(" ")[1].split(","),t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]),t});var m={create:function(e,t,n){var i={};i.options=t,i.id=e.id+"_"+i.options.prefix,i.mediaElement=e,i.flashState={},i.flashApi=null,i.flashApiStack=[];for(var o=s.default.html5media.properties,p=0,m=o.length;p<m;p++)!function(e){i.flashState[e]=null;var t=""+e.substring(0,1).toUpperCase()+e.substring(1);i["get"+t]=function(){if(null!==i.flashApi){if("function"==typeof i.flashApi["get_"+e]){var t=i.flashApi["get_"+e]();return"buffered"===e?{start:function(){return 0},end:function(){return t},length:1}:t}return null}return null},i["set"+t]=function(t){if("src"===e&&(t=(0,f.absolutizeUrl)(t)),null!==i.flashApi&&void 0!==i.flashApi["set_"+e])try{i.flashApi["set_"+e](t)}catch(e){}else i.flashApiStack.push({type:"set",propName:e,value:t})}}(o[p]);var h=s.default.html5media.methods;h.push("stop");for(var v=0,y=h.length;v<y;v++)!function(e){i[e]=function(){if(null!==i.flashApi){if(i.flashApi["fire_"+e])try{i.flashApi["fire_"+e]()}catch(e){}}else i.flashApiStack.push({type:"call",methodName:e})}}(h[v]);for(var g=["rendererready"],b=0,E=g.length;b<E;b++){var S=(0,u.createEvent)(g[b],i);e.dispatchEvent(S)}a.default["__ready__"+i.id]=function(){if(i.flashReady=!0,i.flashApi=r.default.getElementById("__"+i.id),i.flashApiStack.length)for(var e=0,t=i.flashApiStack.length;e<t;e++){var n=i.flashApiStack[e];if("set"===n.type){var o=n.propName,a=""+o.substring(0,1).toUpperCase()+o.substring(1);i["set"+a](n.value)}else"call"===n.type&&i[n.methodName]()}},a.default["__event__"+i.id]=function(e,t){var n=(0,u.createEvent)(e,i);n.message=t||"",i.mediaElement.dispatchEvent(n)},i.flashWrapper=r.default.createElement("div"),-1===["always","sameDomain"].indexOf(i.options.shimScriptAccess)&&(i.options.shimScriptAccess="sameDomain");var x=e.originalNode.autoplay,w=["uid="+i.id,"autoplay="+x,"allowScriptAccess="+i.options.shimScriptAccess],P=null!==e.originalNode&&"video"===e.originalNode.tagName.toLowerCase(),T=P?e.originalNode.height:1,C=P?e.originalNode.width:1;e.originalNode.getAttribute("src")&&w.push("src="+e.originalNode.getAttribute("src")),!0===i.options.enablePseudoStreaming&&(w.push("pseudostreamstart="+i.options.pseudoStreamingStartQueryParam),w.push("pseudostreamtype="+i.options.pseudoStreamingType)),e.appendChild(i.flashWrapper),null!==e.originalNode&&(e.originalNode.style.display="none");var k=[];if(c.IS_IE){var _=r.default.createElement("div");i.flashWrapper.appendChild(_),k=['classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"','codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"','id="__'+i.id+'"','width="'+C+'"','height="'+T+'"'],P||k.push('style="clip: rect(0 0 0 0); position: absolute;"'),_.outerHTML="<object "+k.join(" ")+'><param name="movie" value="'+i.options.pluginPath+i.options.filename+"?x="+new Date+'" /><param name="flashvars" value="'+w.join("&")+'" /><param name="quality" value="high" /><param name="bgcolor" value="#000000" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="'+i.options.shimScriptAccess+'" /><param name="allowFullScreen" value="true" /><div>'+l.default.t("mejs.install-flash")+"</div></object>"}else k=['id="__'+i.id+'"','name="__'+i.id+'"','play="true"','loop="false"','quality="high"','bgcolor="#000000"','wmode="transparent"','allowScriptAccess="'+i.options.shimScriptAccess+'"','allowFullScreen="true"','type="application/x-shockwave-flash"','pluginspage="//www.macromedia.com/go/getflashplayer"','src="'+i.options.pluginPath+i.options.filename+'"','flashvars="'+w.join("&")+'"','width="'+C+'"','height="'+T+'"'],P||k.push('style="clip: rect(0 0 0 0); position: absolute;"'),i.flashWrapper.innerHTML="<embed "+k.join(" ")+">";if(i.flashNode=i.flashWrapper.lastChild,i.hide=function(){P&&(i.flashNode.style.display="none")},i.show=function(){P&&(i.flashNode.style.display="")},i.setSize=function(e,t){i.flashNode.style.width=e+"px",i.flashNode.style.height=t+"px",null!==i.flashApi&&"function"==typeof i.flashApi.fire_setSize&&i.flashApi.fire_setSize(e,t)},i.destroy=function(){i.flashNode.remove()},n&&n.length>0)for(var N=0,A=n.length;N<A;N++)if(d.renderer.renderers[t.prefix].canPlayType(n[N].type)){i.setSrc(n[N].src);break}return i}};if(p.hasPluginVersion("flash",[10,0,0])){f.typeChecks.push(function(e){return e=e.toLowerCase(),e.startsWith("rtmp")?~e.indexOf(".mp3")?"audio/rtmp":"video/rtmp":/\.og(a|g)/i.test(e)?"audio/ogg":~e.indexOf(".m3u8")?"application/x-mpegURL":~e.indexOf(".mpd")?"application/dash+xml":~e.indexOf(".flv")?"video/flv":null});var h={name:"flash_video",options:{prefix:"flash_video",filename:"mediaelement-flash-video.swf",enablePseudoStreaming:!1,pseudoStreamingStartQueryParam:"start",pseudoStreamingType:"byte"},canPlayType:function(e){return~["video/mp4","video/rtmp","audio/rtmp","rtmp/mp4","audio/mp4","video/flv","video/x-flv"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(h);var v={name:"flash_hls",options:{prefix:"flash_hls",filename:"mediaelement-flash-video-hls.swf"},canPlayType:function(e){return~["application/x-mpegurl","vnd.apple.mpegurl","audio/mpegurl","audio/hls","video/hls"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(v);var y={name:"flash_dash",options:{prefix:"flash_dash",filename:"mediaelement-flash-video-mdash.swf"},canPlayType:function(e){return~["application/dash+xml"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(y);var g={name:"flash_audio",options:{prefix:"flash_audio",filename:"mediaelement-flash-audio.swf"},canPlayType:function(e){return~["audio/mp3"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(g);var b={name:"flash_audio_ogg",options:{prefix:"flash_audio_ogg",filename:"mediaelement-flash-audio-ogg.swf"},canPlayType:function(e){return~["audio/ogg","audio/oga","audio/ogv"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(b)}},{2:2,23:23,25:25,26:26,3:3,4:4,6:6,7:7}],19:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(6)),r=e(7),s=e(25),l=e(23),d=e(26),u=e(24),c={promise:null,load:function(e){"undefined"!=typeof flvjs?c._createPlayer(e):(e.options.path="string"==typeof e.options.path?e.options.path:"https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.2.0/flv.min.js",c.promise=c.promise||(0,u.loadScript)(e.options.path),c.promise.then(function(){c._createPlayer(e)}))},_createPlayer:function(e){flvjs.LoggingControl.enableDebug=e.options.debug,flvjs.LoggingControl.enableVerbose=e.options.debug;var t=flvjs.createPlayer(e.options);return o.default["__ready__"+e.id](t),t}},f={name:"native_flv",options:{prefix:"native_flv",flv:{path:"https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.2.0/flv.min.js",cors:!0,debug:!1}},canPlayType:function(e){return l.HAS_MSE&&["video/x-flv","video/flv"].indexOf(e.toLowerCase())>-1},create:function(e,t,n){var i=e.originalNode,l=e.id+"_"+t.prefix,d=null,u=null;d=i.cloneNode(!0),t=Object.assign(t,e.options);for(var f=a.default.html5media.properties,p=0,m=f.length;p<m;p++)!function(e){var n=""+e.substring(0,1).toUpperCase()+e.substring(1);d["get"+n]=function(){return null!==u?d[e]:null},d["set"+n]=function(n){if(-1===a.default.html5media.readOnlyProperties.indexOf(e)&&(d[e]=n,null!==u&&"src"===e)){var i={};i.type="flv",i.url=n,i.cors=t.flv.cors,i.debug=t.flv.debug,i.path=t.flv.path,u.destroy(),(u=c._createPlayer({options:i,id:l})).attachMediaElement(d),u.load()}}}(f[p]);if(o.default["__ready__"+l]=function(t){e.flvPlayer=u=t;for(var n=a.default.html5media.events.concat(["click","mouseover","mouseout"]),i=0,o=n.length;i<o;i++)!function(t){"loadedmetadata"===t&&(u.unload(),u.detachMediaElement(),u.attachMediaElement(d),u.load()),d.addEventListener(t,function(t){var n=(0,s.createEvent)(t.type,e);e.dispatchEvent(n)})}(n[i])},n&&n.length>0)for(var h=0,v=n.length;h<v;h++)if(r.renderer.renderers[t.prefix].canPlayType(n[h].type)){d.setAttribute("src",n[h].src);break}d.setAttribute("id",l),i.parentNode.insertBefore(d,i),i.autoplay=!1,i.style.display="none";var y={};y.type="flv",y.url=d.src,y.cors=t.flv.cors,y.debug=t.flv.debug,y.path=t.flv.path,c.load({options:y,id:l}),d.setSize=function(e,t){return d.style.width=e+"px",d.style.height=t+"px",d},d.hide=function(){return null!==u&&u.pause(),d.style.display="none",d},d.show=function(){return d.style.display="",d},d.destroy=function(){null!==u&&u.destroy()};var g=(0,s.createEvent)("rendererready",d);return e.dispatchEvent(g),d}};d.typeChecks.push(function(e){return~e.toLowerCase().indexOf(".flv")?"video/flv":null}),r.renderer.add(f)},{23:23,24:24,25:25,26:26,3:3,6:6,7:7}],20:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(6)),r=e(7),s=e(25),l=e(23),d=e(26),u=e(24),c={promise:null,load:function(e){"undefined"!=typeof Hls?c._createPlayer(e):(e.options.path="string"==typeof e.options.path?e.options.path:"http://cdn.jsdelivr.net/npm/hls.js@latest",c.promise=c.promise||(0,u.loadScript)(e.options.path),c.promise.then(function(){c._createPlayer(e)}))},_createPlayer:function(e){var t=new Hls(e.options);return o.default["__ready__"+e.id](t),t}},f={name:"native_hls",options:{prefix:"native_hls",hls:{path:"http://cdn.jsdelivr.net/npm/hls.js@latest",autoStartLoad:!1,debug:!1}},canPlayType:function(e){return l.HAS_MSE&&["application/x-mpegurl","vnd.apple.mpegurl","audio/mpegurl","audio/hls","video/hls"].indexOf(e.toLowerCase())>-1},create:function(e,t,n){var i=e.originalNode,l=e.id+"_"+t.prefix,d=i.getAttribute("preload"),u=i.autoplay,f=null,p=null;p=i.cloneNode(!0),(t=Object.assign(t,e.options)).hls.autoStartLoad=d&&"none"!==d||u;for(var m=a.default.html5media.properties,h=0,v=m.length;h<v;h++)!function(e){var n=""+e.substring(0,1).toUpperCase()+e.substring(1);p["get"+n]=function(){return null!==f?p[e]:null},p["set"+n]=function(n){-1===a.default.html5media.readOnlyProperties.indexOf(e)&&(p[e]=n,null!==f&&"src"===e&&(f.destroy(),(f=c._createPlayer({options:t.hls,id:l})).loadSource(n),f.attachMedia(p)))}}(m[h]);if(o.default["__ready__"+l]=function(t){e.hlsPlayer=f=t;for(var n=a.default.html5media.events.concat(["click","mouseover","mouseout"]),i=Hls.Events,o=0,r=n.length;o<r;o++)!function(t){if("loadedmetadata"===t){var n=e.originalNode.src;f.detachMedia(),f.loadSource(n),f.attachMedia(p)}p.addEventListener(t,function(t){var n=(0,s.createEvent)(t.type,e);e.dispatchEvent(n)})}(n[o]);var l=void 0,d=void 0,u=function(t,n){var i=(0,s.createEvent)(t,p);if(i.data=n,e.dispatchEvent(i),"hlsError"===t&&(console.warn(t,n),n.fatal))switch(n.type){case"mediaError":var o=(new Date).getTime();!l||o-l>3e3?(l=(new Date).getTime(),f.recoverMediaError()):!d||o-d>3e3?(d=(new Date).getTime(),console.warn("Attempting to swap Audio Codec and recover from media error"),f.swapAudioCodec(),f.recoverMediaError()):console.error("Cannot recover, last media error recovery failed");break;case"networkError":console.error("Network error");break;default:f.destroy()}};for(var c in i)i.hasOwnProperty(c)&&f.on(i[c],u)},n&&n.length>0)for(var y=0,g=n.length;y<g;y++)if(r.renderer.renderers[t.prefix].canPlayType(n[y].type)){p.setAttribute("src",n[y].src);break}"auto"===d||u||(p.addEventListener("play",function(){null!==f&&f.startLoad()}),p.addEventListener("pause",function(){null!==f&&f.stopLoad()})),p.setAttribute("id",l),i.parentNode.insertBefore(p,i),i.autoplay=!1,i.style.display="none",c.load({options:t.hls,id:l}),p.setSize=function(e,t){return p.style.width=e+"px",p.style.height=t+"px",p},p.hide=function(){return p.pause(),p.style.display="none",p},p.show=function(){return p.style.display="",p},p.destroy=function(){null!==f&&f.destroy()},p.stop=function(){null!==f&&f.stopLoad()};var b=(0,s.createEvent)("rendererready",p);return e.dispatchEvent(b),p}};d.typeChecks.push(function(e){return~e.toLowerCase().indexOf(".m3u8")?"application/x-mpegURL":null}),r.renderer.add(f)},{23:23,24:24,25:25,26:26,3:3,6:6,7:7}],21:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(2)),r=i(e(6)),s=e(7),l=e(25),d=e(23),u={name:"html5",options:{prefix:"html5"},canPlayType:function(e){var t=a.default.createElement("video");return d.IS_ANDROID&&/\/mp(3|4)$/i.test(e)||~["application/x-mpegurl","vnd.apple.mpegurl","audio/mpegurl","audio/hls","video/hls"].indexOf(e.toLowerCase())&&d.SUPPORTS_NATIVE_HLS?"yes":t.canPlayType?t.canPlayType(e.toLowerCase()).replace(/no/,""):""},create:function(e,t,n){var i=e.id+"_"+t.prefix,o=null;void 0===e.originalNode||null===e.originalNode?(o=a.default.createElement("audio"),e.appendChild(o)):o=e.originalNode,o.setAttribute("id",i);for(var d=r.default.html5media.properties,u=0,c=d.length;u<c;u++)!function(e){var t=""+e.substring(0,1).toUpperCase()+e.substring(1);o["get"+t]=function(){return o[e]},o["set"+t]=function(t){-1===r.default.html5media.readOnlyProperties.indexOf(e)&&(o[e]=t)}}(d[u]);for(var f=r.default.html5media.events.concat(["click","mouseover","mouseout"]),p=0,m=f.length;p<m;p++)!function(t){o.addEventListener(t,function(t){var n=(0,l.createEvent)(t.type,e);e.dispatchEvent(n)})}(f[p]);if(o.setSize=function(e,t){return o.style.width=e+"px",o.style.height=t+"px",o},o.hide=function(){return o.style.display="none",o},o.show=function(){return o.style.display="",o},n&&n.length>0)for(var h=0,v=n.length;h<v;h++)if(s.renderer.renderers[t.prefix].canPlayType(n[h].type)){o.setAttribute("src",n[h].src);break}var y=(0,l.createEvent)("rendererready",o);return e.dispatchEvent(y),o}};o.default.HtmlMediaElement=r.default.HtmlMediaElement=u,s.renderer.add(u)},{2:2,23:23,25:25,3:3,6:6,7:7}],22:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=i(e(3)),r=i(e(2)),s=i(e(6)),l=e(7),d=e(25),u=e(26),c=e(24),f={isIframeStarted:!1,isIframeLoaded:!1,iframeQueue:[],enqueueIframe:function(e){f.isLoaded="undefined"!=typeof YT&&YT.loaded,f.isLoaded?f.createIframe(e):(f.loadIframeApi(),f.iframeQueue.push(e))},loadIframeApi:function(){f.isIframeStarted||((0,c.loadScript)("https://www.youtube.com/player_api"),f.isIframeStarted=!0)},iFrameReady:function(){for(f.isLoaded=!0,f.isIframeLoaded=!0;f.iframeQueue.length>0;){var e=f.iframeQueue.pop();f.createIframe(e)}},createIframe:function(e){return new YT.Player(e.containerId,e)},getYouTubeId:function(e){var t="";return e.indexOf("?")>0?""===(t=f.getYouTubeIdFromParam(e))&&(t=f.getYouTubeIdFromUrl(e)):t=f.getYouTubeIdFromUrl(e),t},getYouTubeIdFromParam:function(e){if(void 0===e||null===e||!e.trim().length)return null;for(var t=e.split("?")[1].split("&"),n="",i=0,o=t.length;i<o;i++){var a=t[i].split("=");if("v"===a[0]){n=a[1];break}}return n},getYouTubeIdFromUrl:function(e){return void 0!==e&&null!==e&&e.trim().length?(e=e.split("?")[0]).substring(e.lastIndexOf("/")+1):null},getYouTubeNoCookieUrl:function(e){if(void 0===e||null===e||!e.trim().length||-1===e.indexOf("//www.youtube"))return e;var t=e.split("/");return t[2]=t[2].replace(".com","-nocookie.com"),t.join("/")}},p={name:"youtube_iframe",options:{prefix:"youtube_iframe",youtube:{autoplay:0,controls:0,disablekb:1,end:0,loop:0,modestbranding:0,playsinline:0,rel:0,showinfo:0,start:0,iv_load_policy:3,nocookie:!1}},canPlayType:function(e){return~["video/youtube","video/x-youtube"].indexOf(e.toLowerCase())},create:function(e,t,n){var i={},o=[],l=null,u=!0,c=!1,p=null,m=1;i.options=t,i.id=e.id+"_"+t.prefix,i.mediaElement=e;for(var h=s.default.html5media.properties,v=0,y=h.length;v<y;v++)!function(t){var n=""+t.substring(0,1).toUpperCase()+t.substring(1);i["get"+n]=function(){if(null!==l){switch(t){case"currentTime":return l.getCurrentTime();case"duration":return l.getDuration();case"volume":return m=l.getVolume()/100;case"paused":return u;case"ended":return c;case"muted":return l.isMuted();case"buffered":var e=l.getVideoLoadedFraction(),n=l.getDuration();return{start:function(){return 0},end:function(){return e*n},length:1};case"src":return l.getVideoUrl();case"readyState":return 4}return null}return null},i["set"+n]=function(n){if(null!==l)switch(t){case"src":var a="string"==typeof n?n:n[0].src,r=f.getYouTubeId(a);e.originalNode.autoplay?l.loadVideoById(r):l.cueVideoById(r);break;case"currentTime":l.seekTo(n);break;case"muted":n?l.mute():l.unMute(),setTimeout(function(){var t=(0,d.createEvent)("volumechange",i);e.dispatchEvent(t)},50);break;case"volume":m=n,l.setVolume(100*n),setTimeout(function(){var t=(0,d.createEvent)("volumechange",i);e.dispatchEvent(t)},50);break;case"readyState":var s=(0,d.createEvent)("canplay",i);e.dispatchEvent(s)}else o.push({type:"set",propName:t,value:n})}}(h[v]);for(var g=s.default.html5media.methods,b=0,E=g.length;b<E;b++)!function(e){i[e]=function(){if(null!==l)switch(e){case"play":return u=!1,l.playVideo();case"pause":return u=!0,l.pauseVideo();case"load":return null}else o.push({type:"call",methodName:e})}}(g[b]);var S=r.default.createElement("div");S.id=i.id,i.options.youtube.nocookie&&e.originalNode.setAttribute("src",f.getYouTubeNoCookieUrl(n[0].src)),e.originalNode.parentNode.insertBefore(S,e.originalNode),e.originalNode.style.display="none";var x="audio"===e.originalNode.tagName.toLowerCase(),w=x?"1":e.originalNode.height,P=x?"1":e.originalNode.width,T=f.getYouTubeId(n[0].src),C={id:i.id,containerId:S.id,videoId:T,height:w,width:P,playerVars:Object.assign({controls:0,rel:0,disablekb:1,showinfo:0,modestbranding:0,html5:1,playsinline:0,start:0,end:0,iv_load_policy:3},i.options.youtube),origin:a.default.location.host,events:{onReady:function(t){if(e.youTubeApi=l=t.target,e.youTubeState={paused:!0,ended:!1},o.length)for(var n=0,a=o.length;n<a;n++){var r=o[n];if("set"===r.type){var s=r.propName,u=""+s.substring(0,1).toUpperCase()+s.substring(1);i["set"+u](r.value)}else"call"===r.type&&i[r.methodName]()}p=l.getIframe(),e.originalNode.getAttribute("muted")&&l.mute();for(var c=["mouseover","mouseout"],f=function(t){var n=(0,d.createEvent)(t.type,i);e.dispatchEvent(n)},m=0,h=c.length;m<h;m++)p.addEventListener(c[m],f,!1);for(var v=["rendererready","loadedmetadata","loadeddata","canplay"],y=0,g=v.length;y<g;y++){var b=(0,d.createEvent)(v[y],i);e.dispatchEvent(b)}},onStateChange:function(t){var n=[];switch(t.data){case-1:n=["loadedmetadata"],u=!0,c=!1;break;case 0:n=["ended"],u=!1,c=!i.options.youtube.loop,i.options.youtube.loop||i.stopInterval();break;case 1:n=["play","playing"],u=!1,c=!1,i.startInterval();break;case 2:n=["pause"],u=!0,c=!1,i.stopInterval();break;case 3:n=["progress"],c=!1;break;case 5:n=["loadeddata","loadedmetadata","canplay"],u=!0,c=!1}for(var o=0,a=n.length;o<a;o++){var r=(0,d.createEvent)(n[o],i);e.dispatchEvent(r)}},onError:function(t){var n=(0,d.createEvent)("error",i);n.data=t.data,e.dispatchEvent(n)}}};return x&&(C.playerVars.playsinline=1),e.originalNode.autoplay&&(C.playerVars.autoplay=1),e.originalNode.loop&&(C.playerVars.loop=1),f.enqueueIframe(C),i.onEvent=function(t,n,i){null!==i&&void 0!==i&&(e.youTubeState=i)},i.setSize=function(e,t){null!==l&&l.setSize(e,t)},i.hide=function(){i.stopInterval(),i.pause(),p&&(p.style.display="none")},i.show=function(){p&&(p.style.display="")},i.destroy=function(){l.destroy()},i.interval=null,i.startInterval=function(){i.interval=setInterval(function(){var t=(0,d.createEvent)("timeupdate",i);e.dispatchEvent(t)},250)},i.stopInterval=function(){i.interval&&clearInterval(i.interval)},i}};a.default.postMessage&&o(a.default.addEventListener)&&(a.default.onYouTubePlayerAPIReady=function(){f.iFrameReady()},u.typeChecks.push(function(e){return/\/\/(www\.youtube|youtu\.be)/i.test(e)?"video/x-youtube":null}),l.renderer.add(p))},{2:2,24:24,25:25,26:26,3:3,6:6,7:7}],23:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(n,"__esModule",{value:!0}),n.cancelFullScreen=n.requestFullScreen=n.isFullScreen=n.FULLSCREEN_EVENT_NAME=n.HAS_NATIVE_FULLSCREEN_ENABLED=n.HAS_TRUE_NATIVE_FULLSCREEN=n.HAS_IOS_FULLSCREEN=n.HAS_MS_NATIVE_FULLSCREEN=n.HAS_MOZ_NATIVE_FULLSCREEN=n.HAS_WEBKIT_NATIVE_FULLSCREEN=n.HAS_NATIVE_FULLSCREEN=n.SUPPORTS_NATIVE_HLS=n.SUPPORT_POINTER_EVENTS=n.HAS_MSE=n.IS_STOCK_ANDROID=n.IS_SAFARI=n.IS_FIREFOX=n.IS_CHROME=n.IS_EDGE=n.IS_IE=n.IS_ANDROID=n.IS_IOS=n.IS_IPHONE=n.IS_IPAD=n.UA=n.NAV=void 0;for(var o=i(e(3)),a=i(e(2)),r=i(e(6)),s=n.NAV=o.default.navigator,l=n.UA=s.userAgent.toLowerCase(),d=n.IS_IPAD=/ipad/i.test(l),u=n.IS_IPHONE=/iphone/i.test(l),c=(n.IS_IOS=u||d,n.IS_ANDROID=/android/i.test(l)),f=n.IS_IE=/(trident|microsoft)/i.test(s.appName),p=(n.IS_EDGE="msLaunchUri"in s&&!("documentMode"in a.default)),m=n.IS_CHROME=/chrome/i.test(l),h=n.IS_FIREFOX=/firefox/i.test(l),v=n.IS_SAFARI=/safari/i.test(l)&&!m,y=n.IS_STOCK_ANDROID=/^mozilla\/\d+\.\d+\s\(linux;\su;/i.test(l),g=(n.HAS_MSE="MediaSource"in o.default),b=(n.SUPPORT_POINTER_EVENTS=function(){var e=a.default.createElement("x"),t=a.default.documentElement,n=o.default.getComputedStyle;if(!("pointerEvents"in e.style))return!1;e.style.pointerEvents="auto",e.style.pointerEvents="x",t.appendChild(e);var i=n&&"auto"===n(e,"").pointerEvents;return e.remove(),!!i}()),E=["source","track","audio","video"],S=void 0,x=0,w=E.length;x<w;x++)S=a.default.createElement(E[x]);var P=n.SUPPORTS_NATIVE_HLS=v||c&&(m||y)||f&&/edge/i.test(l),T=void 0!==S.webkitEnterFullscreen,C=void 0!==S.requestFullscreen;T&&/mac os x 10_5/i.test(l)&&(C=!1,T=!1);var k=void 0!==S.webkitRequestFullScreen,_=void 0!==S.mozRequestFullScreen,N=void 0!==S.msRequestFullscreen,A=k||_||N,L=A,F="",j=void 0,I=void 0,M=void 0;_?L=a.default.mozFullScreenEnabled:N&&(L=a.default.msFullscreenEnabled),m&&(T=!1),A&&(k?F="webkitfullscreenchange":_?F="mozfullscreenchange":N&&(F="MSFullscreenChange"),n.isFullScreen=j=function(){return _?a.default.mozFullScreen:k?a.default.webkitIsFullScreen:N?null!==a.default.msFullscreenElement:void 0},n.requestFullScreen=I=function(e){k?e.webkitRequestFullScreen():_?e.mozRequestFullScreen():N&&e.msRequestFullscreen()},n.cancelFullScreen=M=function(){k?a.default.webkitCancelFullScreen():_?a.default.mozCancelFullScreen():N&&a.default.msExitFullscreen()});var O=n.HAS_NATIVE_FULLSCREEN=C,H=n.HAS_WEBKIT_NATIVE_FULLSCREEN=k,D=n.HAS_MOZ_NATIVE_FULLSCREEN=_,q=n.HAS_MS_NATIVE_FULLSCREEN=N,R=n.HAS_IOS_FULLSCREEN=T,V=n.HAS_TRUE_NATIVE_FULLSCREEN=A,U=n.HAS_NATIVE_FULLSCREEN_ENABLED=L,B=n.FULLSCREEN_EVENT_NAME=F;n.isFullScreen=j,n.requestFullScreen=I,n.cancelFullScreen=M,r.default.Features=r.default.Features||{},r.default.Features.isiPad=d,r.default.Features.isiPhone=u,r.default.Features.isiOS=r.default.Features.isiPhone||r.default.Features.isiPad,r.default.Features.isAndroid=c,r.default.Features.isIE=f,r.default.Features.isEdge=p,r.default.Features.isChrome=m,r.default.Features.isFirefox=h,r.default.Features.isSafari=v,r.default.Features.isStockAndroid=y,r.default.Features.hasMSE=g,r.default.Features.supportsNativeHLS=P,r.default.Features.supportsPointerEvents=b,r.default.Features.hasiOSFullScreen=R,r.default.Features.hasNativeFullscreen=O,r.default.Features.hasWebkitNativeFullScreen=H,r.default.Features.hasMozNativeFullScreen=D,r.default.Features.hasMsNativeFullScreen=q,r.default.Features.hasTrueNativeFullScreen=V,r.default.Features.nativeFullScreenEnabled=U,r.default.Features.fullScreenEventName=B,r.default.Features.isFullScreen=j,r.default.Features.requestFullScreen=I,r.default.Features.cancelFullScreen=M},{2:2,3:3,6:6}],24:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function o(e){function t(e){for(o=e;a=n.shift();)a[i]&&a[i](o)}var n=[],i=-1,o=void 0,a=void 0;return e(function(e){return t(e,i=0)},function(e){return t(e,i=1)}),{then:function(){for(var e=arguments.length,t=Array(e),a=0;a<e;a++)t[a]=arguments[a];~i?t[i]&&t[i](o):n.push(t)}}}function a(e){return o(function(t,n){var i=m.default.createElement("script");i.src=e,i.async=!0,i.onload=function(){i.remove(),t()},i.onerror=function(){i.remove(),n()},m.default.head.appendChild(i)})}function r(e){var t=e.getBoundingClientRect(),n=p.default.pageXOffset||m.default.documentElement.scrollLeft,i=p.default.pageYOffset||m.default.documentElement.scrollTop;return{top:t.top+i,left:t.left+n}}function s(e,t){b(e,t)?S(e,t):E(e,t)}function l(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:400,n=arguments[2];e.style.opacity||(e.style.opacity=1);var i=null;p.default.requestAnimationFrame(function o(a){var r=a-(i=i||a),s=parseFloat(1-r/t,2);e.style.opacity=s<0?0:s,r>t?n&&"function"==typeof n&&n():p.default.requestAnimationFrame(o)})}function d(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:400,n=arguments[2];e.style.opacity||(e.style.opacity=0);var i=null;p.default.requestAnimationFrame(function o(a){var r=a-(i=i||a),s=parseFloat(r/t,2);e.style.opacity=s>1?1:s,r>t?n&&"function"==typeof n&&n():p.default.requestAnimationFrame(o)})}function u(e,t){var n=[];e=e.parentNode.firstChild;do{t&&!t(e)||n.push(e)}while(e=e.nextSibling);return n}function c(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}function f(e,t,n,i){var o=p.default.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP"),a="application/x-www-form-urlencoded; charset=UTF-8",r=!1,s="*/".concat("*");switch(t){case"text":a="text/plain";break;case"json":a="application/json, text/javascript";break;case"html":a="text/html";break;case"xml":a="application/xml, text/xml"}"application/x-www-form-urlencoded"!==a&&(s=a+", */*; q=0.01"),o&&(o.open("GET",e,!0),o.setRequestHeader("Accept",s),o.onreadystatechange=function(){if(!r&&4===o.readyState)if(200===o.status){r=!0;var e=void 0;switch(t){case"json":e=JSON.parse(o.responseText);break;case"xml":e=o.responseXML;break;default:e=o.responseText}n(e)}else"function"==typeof i&&i(o.status)},o.send())}Object.defineProperty(n,"__esModule",{value:!0}),n.removeClass=n.addClass=n.hasClass=void 0,n.loadScript=a,n.offset=r,n.toggleClass=s,n.fadeOut=l,n.fadeIn=d,n.siblings=u,n.visible=c,n.ajax=f;var p=i(e(3)),m=i(e(2)),h=i(e(6)),v=void 0,y=void 0,g=void 0;"classList"in m.default.documentElement?(v=function(e,t){return void 0!==e.classList&&e.classList.contains(t)},y=function(e,t){return e.classList.add(t)},g=function(e,t){return e.classList.remove(t)}):(v=function(e,t){return new RegExp("\\b"+t+"\\b").test(e.className)},y=function(e,t){b(e,t)||(e.className+=" "+t)},g=function(e,t){e.className=e.className.replace(new RegExp("\\b"+t+"\\b","g"),"")});var b=n.hasClass=v,E=n.addClass=y,S=n.removeClass=g;h.default.Utils=h.default.Utils||{},h.default.Utils.offset=r,h.default.Utils.hasClass=b,h.default.Utils.addClass=E,h.default.Utils.removeClass=S,h.default.Utils.toggleClass=s,h.default.Utils.fadeIn=d,h.default.Utils.fadeOut=l,h.default.Utils.siblings=u,h.default.Utils.visible=c,h.default.Utils.ajax=f,h.default.Utils.loadScript=a},{2:2,3:3,6:6}],25:[function(e,t,n){"use strict";function i(e){if("string"!=typeof e)throw new Error("Argument passed must be a string");var t={"&":"&","<":"<",">":">",'"':"""};return e.replace(/[&<>"]/g,function(e){return t[e]})}function o(e,t){var n=this,i=arguments,o=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if("function"!=typeof e)throw new Error("First argument must be a function");if("number"!=typeof t)throw new Error("Second argument must be a numeric value");var a=void 0;return function(){var r=n,s=i,l=function(){a=null,o||e.apply(r,s)},d=o&&!a;clearTimeout(a),a=setTimeout(l,t),d&&e.apply(r,s)}}function a(e){return Object.getOwnPropertyNames(e).length<=0}function r(e,t){var n=/^((after|before)print|(before)?unload|hashchange|message|o(ff|n)line|page(hide|show)|popstate|resize|storage)\b/,i={d:[],w:[]};return(e||"").split(" ").forEach(function(e){var o=e+(t?"."+t:"");o.startsWith(".")?(i.d.push(o),i.w.push(o)):i[n.test(e)?"w":"d"].push(o)}),i.d=i.d.join(" "),i.w=i.w.join(" "),i}function s(e,t){if("string"!=typeof e)throw new Error("Event name must be a string");var n=e.match(/([a-z]+\.([a-z]+))/i),i={target:t};return null!==n&&(e=n[1],i.namespace=n[2]),new window.CustomEvent(e,{detail:i})}function l(e,t){return!!(e&&t&&2&e.compareDocumentPosition(t))}function d(e){return"string"==typeof e}Object.defineProperty(n,"__esModule",{value:!0}),n.escapeHTML=i,n.debounce=o,n.isObjectEmpty=a,n.splitEvents=r,n.createEvent=s,n.isNodeAfter=l,n.isString=d;var u=function(e){return e&&e.__esModule?e:{default:e}}(e(6));u.default.Utils=u.default.Utils||{},u.default.Utils.escapeHTML=i,u.default.Utils.debounce=o,u.default.Utils.isObjectEmpty=a,u.default.Utils.splitEvents=r,u.default.Utils.createEvent=s,u.default.Utils.isNodeAfter=l,u.default.Utils.isString=d},{6:6}],26:[function(e,t,n){"use strict";function i(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");var t=document.createElement("div");return t.innerHTML='<a href="'+(0,u.escapeHTML)(e)+'">x</a>',t.firstChild.href}function o(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e&&!t?r(e):a(t)}function a(e){if("string"!=typeof e)throw new Error("`type` argument must be a string");return e&&e.indexOf(";")>-1?e.substr(0,e.indexOf(";")):e}function r(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");for(var t=0,n=c.length;t<n;t++){var i=c[t](e);if(i)return i}var o=l(s(e)),a="video/mp4";return o&&(~["mp4","m4v","ogg","ogv","webm","flv","mpeg","mov"].indexOf(o)?a="video/"+o:~["mp3","oga","wav","mid","midi"].indexOf(o)&&(a="audio/"+o)),a}function s(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");var t=e.split("?")[0].split("\\").pop().split("/").pop();return~t.indexOf(".")?t.substring(t.lastIndexOf(".")+1):""}function l(e){if("string"!=typeof e)throw new Error("`extension` argument must be a string");switch(e){case"mp4":case"m4v":return"mp4";case"webm":case"webma":case"webmv":return"webm";case"ogg":case"oga":case"ogv":return"ogg";default:return e}}Object.defineProperty(n,"__esModule",{value:!0}),n.typeChecks=void 0,n.absolutizeUrl=i,n.formatType=o,n.getMimeFromType=a,n.getTypeFromFile=r,n.getExtension=s,n.normalizeExtension=l;var d=function(e){return e&&e.__esModule?e:{default:e}}(e(6)),u=e(25),c=n.typeChecks=[];d.default.Utils=d.default.Utils||{},d.default.Utils.typeChecks=c,d.default.Utils.absolutizeUrl=i,d.default.Utils.formatType=o,d.default.Utils.getMimeFromType=a,d.default.Utils.getTypeFromFile=r,d.default.Utils.getExtension=s,d.default.Utils.normalizeExtension=l},{25:25,6:6}],27:[function(e,t,n){"use strict";var i=function(e){return e&&e.__esModule?e:{default:e}}(e(2));!function(e){e.forEach(function(e){e.hasOwnProperty("remove")||Object.defineProperty(e,"remove",{configurable:!0,enumerable:!0,writable:!0,value:function(){this.parentNode.removeChild(this)}})})}([Element.prototype,CharacterData.prototype,DocumentType.prototype]),function(){function e(e,t){t=t||{bubbles:!1,cancelable:!1,detail:void 0};var n=i.default.createEvent("CustomEvent");return n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),n}if("function"==typeof window.CustomEvent)return!1;e.prototype=window.Event.prototype,window.CustomEvent=e}(),"function"!=typeof Object.assign&&(Object.assign=function(e){if(null===e||void 0===e)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(e),n=1,i=arguments.length;n<i;n++){var o=arguments[n];if(null!==o)for(var a in o)Object.prototype.hasOwnProperty.call(o,a)&&(t[a]=o[a])}return t}),String.prototype.startsWith||(String.prototype.startsWith=function(e,t){return t=t||0,this.substr(t,e.length)===e}),Element.prototype.matches||(Element.prototype.matches=Element.prototype.matchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||Element.prototype.webkitMatchesSelector||function(e){for(var t=(this.document||this.ownerDocument).querySelectorAll(e),n=t.length-1;--n>=0&&t.item(n)!==this;);return n>-1}),window.Element&&!Element.prototype.closest&&(Element.prototype.closest=function(e){var t=(this.document||this.ownerDocument).querySelectorAll(e),n=void 0,i=this;do{for(n=t.length;--n>=0&&t.item(n)!==i;);}while(n<0&&(i=i.parentElement));return i}),function(){for(var e=0,t=["ms","moz","webkit","o"],n=0;n<t.length&&!window.requestAnimationFrame;++n)window.requestAnimationFrame=window[t[n]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[t[n]+"CancelAnimationFrame"]||window[t[n]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(t){var n=(new Date).getTime(),i=Math.max(0,16-(n-e)),o=window.setTimeout(function(){t(n+i)},i);return e=n+i,o}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(e){clearTimeout(e)})}(),/firefox/i.test(navigator.userAgent)&&(window.mediaElementJsOldGetComputedStyle=window.getComputedStyle,window.getComputedStyle=function(e,t){var n=window.mediaElementJsOldGetComputedStyle(e,t);return null===n?{getPropertyValue:function(){}}:n})},{2:2}],28:[function(e,t,n){"use strict";function i(){return!((arguments.length>0&&void 0!==arguments[0]?arguments[0]:25)%1==0)}function o(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:25,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0;e=!e||"number"!=typeof e||e<0?0:e;var r=Math.round(.066666*o),s=Math.round(o),l=24*Math.round(3600*o),d=Math.round(600*o),u=i(o)?";":":",c=void 0,f=void 0,p=void 0,m=void 0,h=Math.round(e*o);if(i(o)){h<0&&(h=l+h);var v=(h%=l)%d;h+=9*r*Math.floor(h/d),v>r&&(h+=r*Math.floor((v-r)/Math.round(60*s-r)));var y=Math.floor(h/s);c=Math.floor(Math.floor(y/60)/60),f=Math.floor(y/60)%60,p=n?y%60:(h/s%60).toFixed(a)}else c=Math.floor(e/3600)%24,f=Math.floor(e/60)%60,p=n?Math.floor(e%60):(e%60).toFixed(a);c=c<=0?0:c,f=f<=0?0:f,p=p<=0?0:p;var g=t||c>0?(c<10?"0"+c:c)+":":"";return g+=(f<10?"0"+f:f)+":",g+=""+(p<10?"0"+p:p),n&&(g+=(m=(m=(h%s).toFixed(0))<=0?0:m)<10?u+"0"+m:""+u+m),g}function a(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25;if("string"!=typeof e)throw new TypeError("Time must be a string");if(e.indexOf(";")>0&&(e=e.replace(";",":")),!/\d{2}(\:\d{2}){0,3}/i.test(e))throw new TypeError("Time code must have the format `00:00:00`");var n=e.split(":"),o=void 0,a=0,r=0,s=0,l=0,d=0,u=Math.round(.066666*t),c=Math.round(t),f=3600*c,p=60*c;switch(n.length){default:case 1:s=parseInt(n[0],10);break;case 2:r=parseInt(n[0],10),s=parseInt(n[1],10);break;case 3:a=parseInt(n[0],10),r=parseInt(n[1],10),s=parseInt(n[2],10);break;case 4:a=parseInt(n[0],10),r=parseInt(n[1],10),s=parseInt(n[2],10),l=parseInt(n[3],10)}return o=i(t)?f*a+p*r+c*s+l-u*((d=60*a+r)-Math.floor(d/10)):(f*a+p*r+t*s+l)/t,parseFloat(o.toFixed(3))}function r(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:25;e=!e||"number"!=typeof e||e<0?0:e;for(var i=Math.floor(e/3600)%24,o=Math.floor(e/60)%60,a=Math.floor(e%60),r=[[Math.floor((e%1*n).toFixed(3)),"f"],[a,"s"],[o,"m"],[i,"h"]],s=t.timeFormat,l=s[1]===s[0],d=l?2:1,u=s.length<d?s[d]:":",c=s[0],f=!1,p=0,m=r.length;p<m;p++)if(~s.indexOf(r[p][1]))f=!0;else if(f){for(var h=!1,v=p;v<m;v++)if(r[v][0]>0){h=!0;break}if(!h)break;l||(s=c+s),s=r[p][1]+u+s,l&&(s=r[p][1]+s),c=r[p][1]}t.currentTimeFormat=s}function s(e){if("string"!=typeof e)throw new TypeError("Argument must be a string value");for(var t=~(e=e.replace(",",".")).indexOf(".")?e.split(".")[1].length:0,n=0,i=1,o=0,a=(e=e.split(":").reverse()).length;o<a;o++)i=1,o>0&&(i=Math.pow(60,o)),n+=Number(e[o])*i;return Number(n.toFixed(t))}Object.defineProperty(n,"__esModule",{value:!0}),n.isDropFrame=i,n.secondsToTimeCode=o,n.timeCodeToSeconds=a,n.calculateTimeFormat=r,n.convertSMPTEtoSeconds=s;var l=function(e){return e&&e.__esModule?e:{default:e}}(e(6));l.default.Utils=l.default.Utils||{},l.default.Utils.secondsToTimeCode=o,l.default.Utils.timeCodeToSeconds=a,l.default.Utils.calculateTimeFormat=r,l.default.Utils.convertSMPTEtoSeconds=s},{6:6}]},{},[27,5,4,14,21,18,17,19,20,22,15,16,8,9,10,11,12,13]); \ No newline at end of file +!function e(t,n,i){function o(r,s){if(!n[r]){if(!t[r]){var l="function"==typeof require&&require;if(!s&&l)return l(r,!0);if(a)return a(r,!0);var d=new Error("Cannot find module '"+r+"'");throw d.code="MODULE_NOT_FOUND",d}var u=n[r]={exports:{}};t[r][0].call(u.exports,function(e){var n=t[r][1][e];return o(n||e)},u,u.exports,e,t,n,i)}return n[r].exports}for(var a="function"==typeof require&&require,r=0;r<i.length;r++)o(i[r]);return o}({1:[function(e,t,n){},{}],2:[function(e,t,n){(function(n){var i,o=void 0!==n?n:"undefined"!=typeof window?window:{},a=e(1);"undefined"!=typeof document?i=document:(i=o["__GLOBAL_DOCUMENT_CACHE@4"])||(i=o["__GLOBAL_DOCUMENT_CACHE@4"]=a),t.exports=i}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1}],3:[function(e,t,n){(function(e){var n;n="undefined"!=typeof window?window:void 0!==e?e:"undefined"!=typeof self?self:{},t.exports=n}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],4:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o=function(e){return e&&e.__esModule?e:{default:e}}(e(6)),a=e(14),r=e(25),s={lang:"en",en:a.EN};s.language=function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];if(null!==t&&void 0!==t&&t.length){if("string"!=typeof t[0])throw new TypeError("Language code must be a string value");if(!/^[a-z]{2}(\-[a-z]{2})?$/i.test(t[0]))throw new TypeError("Language code must have format `xx` or `xx-xx`");s.lang=t[0],void 0===s[t[0]]?(t[1]=null!==t[1]&&void 0!==t[1]&&"object"===i(t[1])?t[1]:{},s[t[0]]=(0,r.isObjectEmpty)(t[1])?a.EN:t[1]):null!==t[1]&&void 0!==t[1]&&"object"===i(t[1])&&(s[t[0]]=t[1])}return s.lang},s.t=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if("string"==typeof e&&e.length){var n=void 0,o=void 0,a=s.language(),l=function(e,t,n){return"object"!==(void 0===e?"undefined":i(e))||"number"!=typeof t||"number"!=typeof n?e:[function(){return arguments.length<=1?void 0:arguments[1]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:arguments.length<=2?void 0:arguments[2]},function(){return 0===(arguments.length<=0?void 0:arguments[0])||1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:arguments.length<=2?void 0:arguments[2]},function(){return(arguments.length<=0?void 0:arguments[0])%10==1&&(arguments.length<=0?void 0:arguments[0])%100!=11?arguments.length<=1?void 0:arguments[1]:0!==(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 1===(arguments.length<=0?void 0:arguments[0])||11===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:2===(arguments.length<=0?void 0:arguments[0])||12===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:(arguments.length<=0?void 0:arguments[0])>2&&(arguments.length<=0?void 0:arguments[0])<20?arguments.length<=3?void 0:arguments[3]:arguments.length<=4?void 0:arguments[4]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:0===(arguments.length<=0?void 0:arguments[0])||(arguments.length<=0?void 0:arguments[0])%100>0&&(arguments.length<=0?void 0:arguments[0])%100<20?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return(arguments.length<=0?void 0:arguments[0])%10==1&&(arguments.length<=0?void 0:arguments[0])%100!=11?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10>=2&&((arguments.length<=0?void 0:arguments[0])%100<10||(arguments.length<=0?void 0:arguments[0])%100>=20)?arguments.length<=2?void 0:arguments[2]:[3]},function(){return(arguments.length<=0?void 0:arguments[0])%10==1&&(arguments.length<=0?void 0:arguments[0])%100!=11?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10>=2&&(arguments.length<=0?void 0:arguments[0])%10<=4&&((arguments.length<=0?void 0:arguments[0])%100<10||(arguments.length<=0?void 0:arguments[0])%100>=20)?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])>=2&&(arguments.length<=0?void 0:arguments[0])<=4?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10>=2&&(arguments.length<=0?void 0:arguments[0])%10<=4&&((arguments.length<=0?void 0:arguments[0])%100<10||(arguments.length<=0?void 0:arguments[0])%100>=20)?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return(arguments.length<=0?void 0:arguments[0])%100==1?arguments.length<=2?void 0:arguments[2]:(arguments.length<=0?void 0:arguments[0])%100==2?arguments.length<=3?void 0:arguments[3]:(arguments.length<=0?void 0:arguments[0])%100==3||(arguments.length<=0?void 0:arguments[0])%100==4?arguments.length<=4?void 0:arguments[4]:arguments.length<=1?void 0:arguments[1]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:2===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:(arguments.length<=0?void 0:arguments[0])>2&&(arguments.length<=0?void 0:arguments[0])<7?arguments.length<=3?void 0:arguments[3]:(arguments.length<=0?void 0:arguments[0])>6&&(arguments.length<=0?void 0:arguments[0])<11?arguments.length<=4?void 0:arguments[4]:arguments.length<=5?void 0:arguments[5]},function(){return 0===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:2===(arguments.length<=0?void 0:arguments[0])?arguments.length<=3?void 0:arguments[3]:(arguments.length<=0?void 0:arguments[0])%100>=3&&(arguments.length<=0?void 0:arguments[0])%100<=10?arguments.length<=4?void 0:arguments[4]:(arguments.length<=0?void 0:arguments[0])%100>=11?arguments.length<=5?void 0:arguments[5]:arguments.length<=6?void 0:arguments[6]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:0===(arguments.length<=0?void 0:arguments[0])||(arguments.length<=0?void 0:arguments[0])%100>1&&(arguments.length<=0?void 0:arguments[0])%100<11?arguments.length<=2?void 0:arguments[2]:(arguments.length<=0?void 0:arguments[0])%100>10&&(arguments.length<=0?void 0:arguments[0])%100<20?arguments.length<=3?void 0:arguments[3]:arguments.length<=4?void 0:arguments[4]},function(){return(arguments.length<=0?void 0:arguments[0])%10==1?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10==2?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 11!==(arguments.length<=0?void 0:arguments[0])&&(arguments.length<=0?void 0:arguments[0])%10==1?arguments.length<=1?void 0:arguments[1]:arguments.length<=2?void 0:arguments[2]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:(arguments.length<=0?void 0:arguments[0])%10>=2&&(arguments.length<=0?void 0:arguments[0])%10<=4&&((arguments.length<=0?void 0:arguments[0])%100<10||(arguments.length<=0?void 0:arguments[0])%100>=20)?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:2===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:8!==(arguments.length<=0?void 0:arguments[0])&&11!==(arguments.length<=0?void 0:arguments[0])?arguments.length<=3?void 0:arguments[3]:arguments.length<=4?void 0:arguments[4]},function(){return 0===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:arguments.length<=2?void 0:arguments[2]},function(){return 1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:2===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:3===(arguments.length<=0?void 0:arguments[0])?arguments.length<=3?void 0:arguments[3]:arguments.length<=4?void 0:arguments[4]},function(){return 0===(arguments.length<=0?void 0:arguments[0])?arguments.length<=1?void 0:arguments[1]:1===(arguments.length<=0?void 0:arguments[0])?arguments.length<=2?void 0:arguments[2]:arguments.length<=3?void 0:arguments[3]}][n].apply(null,[t].concat(e))};return void 0!==s[a]&&(n=s[a][e],null!==t&&"number"==typeof t&&(o=s[a]["mejs.plural-form"],n=l.apply(null,[n,t,o]))),!n&&s.en&&(n=s.en[e],null!==t&&"number"==typeof t&&(o=s.en["mejs.plural-form"],n=l.apply(null,[n,t,o]))),n=n||e,null!==t&&"number"==typeof t&&(n=n.replace("%1",t)),(0,r.escapeHTML)(n)}return e},o.default.i18n=s,"undefined"!=typeof mejsL10n&&o.default.i18n.language(mejsL10n.language,mejsL10n.strings),n.default=s},{14:14,25:25,6:6}],5:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r=i(e(3)),s=i(e(2)),l=i(e(6)),d=e(25),u=e(26),c=e(7),f=e(23),p=function e(t,n,i){var p=this;o(this,e);var m=this;i=Array.isArray(i)?i:null,m.defaults={renderers:[],fakeNodeName:"mediaelementwrapper",pluginPath:"build/",shimScriptAccess:"sameDomain",customError:""},n=Object.assign(m.defaults,n),m.mediaElement=s.default.createElement(n.fakeNodeName),m.mediaElement.options=n;var h=t,v=!1;if("string"==typeof t?m.mediaElement.originalNode=s.default.getElementById(t):(m.mediaElement.originalNode=t,h=t.id),h=h||"mejs_"+Math.random().toString().slice(2),void 0!==m.mediaElement.originalNode&&null!==m.mediaElement.originalNode&&m.mediaElement.appendChild){m.mediaElement.originalNode.setAttribute("id",h+"_from_mejs");var y=m.mediaElement.originalNode.tagName.toLowerCase();["video","audio"].indexOf(y)>-1&&!m.mediaElement.originalNode.getAttribute("preload")&&m.mediaElement.originalNode.setAttribute("preload","none"),m.mediaElement.originalNode.parentNode.insertBefore(m.mediaElement,m.mediaElement.originalNode),m.mediaElement.appendChild(m.mediaElement.originalNode)}m.mediaElement.id=h,m.mediaElement.renderers={},m.mediaElement.renderer=null,m.mediaElement.rendererName=null,m.mediaElement.changeRenderer=function(e,t){var n=p,i=Object.keys(t[0]).length>2?t[0]:t[0].src;if(void 0!==n.mediaElement.renderer&&null!==n.mediaElement.renderer&&n.mediaElement.renderer.name===e)return n.mediaElement.renderer.pause(),n.mediaElement.renderer.stop&&n.mediaElement.renderer.stop(),n.mediaElement.renderer.show(),n.mediaElement.renderer.setSrc(i),!0;void 0!==n.mediaElement.renderer&&null!==n.mediaElement.renderer&&(n.mediaElement.renderer.pause(),n.mediaElement.renderer.stop&&n.mediaElement.renderer.stop(),n.mediaElement.renderer.hide());var o=n.mediaElement.renderers[e],a=null;if(void 0!==o&&null!==o)return o.show(),o.setSrc(i),n.mediaElement.renderer=o,n.mediaElement.rendererName=e,!0;for(var r=n.mediaElement.options.renderers.length?n.mediaElement.options.renderers:c.renderer.order,s=0,l=r.length;s<l;s++){var d=r[s];if(d===e){a=c.renderer.renderers[d];var u=Object.assign(a.options,n.mediaElement.options);return o=a.create(n.mediaElement,u,t),o.name=e,n.mediaElement.renderers[a.name]=o,n.mediaElement.renderer=o,n.mediaElement.rendererName=e,o.show(),!0}}return!1},m.mediaElement.setSize=function(e,t){void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer&&m.mediaElement.renderer.setSize(e,t)},m.mediaElement.createErrorMessage=function(e){e=Array.isArray(e)?e:[];var t=s.default.createElement("div");t.className="me_cannotplay",t.style.width="100%",t.style.height="100%";var n=m.mediaElement.options.customError;if(!n){var i=m.mediaElement.originalNode.getAttribute("poster");i&&(n+='<img src="'+i+'" width="100%" height="100%" alt="'+l.default.i18n.t("mejs.download-file")+'">');for(var o=0,a=e.length;o<a;o++){var r=e[o];n+='<a href="'+r.src+'" data-type="'+r.type+'"><span>'+l.default.i18n.t("mejs.download-file")+": "+r.src+"</span></a>"}}t.innerHTML=n,m.mediaElement.originalNode.parentNode.insertBefore(t,m.mediaElement.originalNode),m.mediaElement.originalNode.style.display="none",v=!0};var g=l.default.html5media.properties,b=l.default.html5media.methods,E=function(e,t,n,i){var o=e[t];Object.defineProperty(e,t,{get:function(){return n.apply(e,[o])},set:function(t){return o=i.apply(e,[t])}})},S=function(){return void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer?m.mediaElement.renderer.getSrc():null},x=function(e){var t=[];if("string"==typeof e)t.push({src:e,type:e?(0,u.getTypeFromFile)(e):""});else if("object"===(void 0===e?"undefined":a(e))&&void 0!==e.src){var n=(0,u.absolutizeUrl)(e.src),i=e.type,o=Object.assign(e,{src:n,type:""!==i&&null!==i&&void 0!==i||!n?i:(0,u.getTypeFromFile)(n)});t.push(o)}else if(Array.isArray(e))for(var r=0,s=e.length;r<s;r++){var l=(0,u.absolutizeUrl)(e[r].src),f=e[r].type,p=Object.assign(e[r],{src:l,type:""!==f&&null!==f&&void 0!==f||!l?f:(0,u.getTypeFromFile)(l)});t.push(p)}var h=c.renderer.select(t,m.mediaElement.options.renderers.length?m.mediaElement.options.renderers:[]),v=void 0;if(m.mediaElement.paused||(m.mediaElement.pause(),v=(0,d.createEvent)("pause",m.mediaElement),m.mediaElement.dispatchEvent(v)),m.mediaElement.originalNode.setAttribute("src",t[0].src||""),m.mediaElement.querySelector(".me_cannotplay")&&m.mediaElement.querySelector(".me_cannotplay").remove(),null===h)return m.mediaElement.createErrorMessage(t),v=(0,d.createEvent)("error",m.mediaElement),v.message="No renderer found",void m.mediaElement.dispatchEvent(v);m.mediaElement.changeRenderer(h.rendererName,t),void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer||((v=(0,d.createEvent)("error",m.mediaElement)).message="Error creating renderer",m.mediaElement.dispatchEvent(v),m.mediaElement.createErrorMessage(t))};E(m.mediaElement,"src",S,x),m.mediaElement.getSrc=S,m.mediaElement.setSrc=x;for(var w=0,P=g.length;w<P;w++)!function(e){if("src"!==e){var t=""+e.substring(0,1).toUpperCase()+e.substring(1),n=function(){return void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer&&"function"==typeof m.mediaElement.renderer["get"+t]?m.mediaElement.renderer["get"+t]():null},i=function(e){void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer&&"function"==typeof m.mediaElement.renderer["set"+t]&&m.mediaElement.renderer["set"+t](e)};E(m.mediaElement,e,n,i),m.mediaElement["get"+t]=n,m.mediaElement["set"+t]=i}}(g[w]);for(var T=0,C=b.length;T<C;T++)!function(e){m.mediaElement[e]=function(){for(var t=arguments.length,n=Array(t),i=0;i<t;i++)n[i]=arguments[i];if(void 0!==m.mediaElement.renderer&&null!==m.mediaElement.renderer&&"function"==typeof m.mediaElement.renderer[e])try{m.mediaElement.renderer[e](n)}catch(e){m.mediaElement.createErrorMessage()}return null}}(b[T]);m.mediaElement.events={},m.mediaElement.addEventListener=function(e,t){m.mediaElement.events[e]=m.mediaElement.events[e]||[],m.mediaElement.events[e].push(t)},m.mediaElement.removeEventListener=function(e,t){if(!e)return m.mediaElement.events={},!0;var n=m.mediaElement.events[e];if(!n)return!0;if(!t)return m.mediaElement.events[e]=[],!0;for(var i=0;i<n.length;i++)if(n[i]===t)return m.mediaElement.events[e].splice(i,1),!0;return!1},m.mediaElement.dispatchEvent=function(e){var t=m.mediaElement.events[e.type];if(t)for(var n=0;n<t.length;n++)t[n].apply(null,[e])};var k=function(e,t){if(l.default.html5media.mediaTypes.indexOf(t)>-1&&"https:"===r.default.location.protocol&&f.IS_IOS&&!r.default.MSStream){var n=new XMLHttpRequest;n.onreadystatechange=function(){if(4===this.readyState&&200===this.status){var t=(r.default.URL||r.default.webkitURL).createObjectURL(this.response);return m.mediaElement.originalNode.setAttribute("src",t),t}return e},n.open("GET",e),n.responseType="blob",n.send()}return e},_=void 0;if(null!==i)_=i;else if(null!==m.mediaElement.originalNode)switch(_=[],m.mediaElement.originalNode.nodeName.toLowerCase()){case"iframe":_.push({type:"",src:m.mediaElement.originalNode.getAttribute("src")});break;case"audio":case"video":var N=m.mediaElement.originalNode.childNodes.length,A=m.mediaElement.originalNode.getAttribute("src");if(A){var L=m.mediaElement.originalNode,F=(0,u.formatType)(A,L.getAttribute("type"));_.push({type:F,src:k(A,F)})}for(var j=0;j<N;j++){var I=m.mediaElement.originalNode.childNodes[j];if(I.nodeType===Node.ELEMENT_NODE&&"source"===I.tagName.toLowerCase()){var M=I.getAttribute("src"),O=(0,u.formatType)(M,I.getAttribute("type"));_.push({type:O,src:k(M,O)})}}}return _.length&&(m.mediaElement.src=_),m.mediaElement.options.success&&m.mediaElement.options.success(m.mediaElement,m.mediaElement.originalNode),v&&m.mediaElement.options.error&&m.mediaElement.options.error(m.mediaElement,m.mediaElement.originalNode),m.mediaElement};r.default.MediaElement=p,n.default=p},{2:2,23:23,25:25,26:26,3:3,6:6,7:7}],6:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var i=function(e){return e&&e.__esModule?e:{default:e}}(e(3)),o={};o.version="4.1.2",o.html5media={properties:["volume","src","currentTime","muted","duration","paused","ended","buffered","error","networkState","readyState","seeking","seekable","currentSrc","preload","bufferedBytes","bufferedTime","initialTime","startOffsetTime","defaultPlaybackRate","playbackRate","played","autoplay","loop","controls"],readOnlyProperties:["duration","paused","ended","buffered","error","networkState","readyState","seeking","seekable"],methods:["load","play","pause","canPlayType"],events:["loadstart","progress","suspend","abort","error","emptied","stalled","play","pause","loadedmetadata","loadeddata","waiting","playing","canplay","canplaythrough","seeking","seeked","timeupdate","ended","ratechange","durationchange","volumechange"],mediaTypes:["audio/mp3","audio/ogg","audio/oga","audio/wav","audio/x-wav","audio/wave","audio/x-pn-wav","audio/mpeg","audio/mp4","video/mp4","video/webm","video/ogg","video/ogv"]},i.default.mejs=o,n.default=o},{3:3}],7:[function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0}),n.renderer=void 0;var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),r=function(e){return e&&e.__esModule?e:{default:e}}(e(6)),s=function(){function e(){i(this,e),this.renderers={},this.order=[]}return a(e,[{key:"add",value:function(e){if(void 0===e.name)throw new TypeError("renderer must contain at least `name` property");this.renderers[e.name]=e,this.order.push(e.name)}},{key:"select",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=t.length;if(t=t.length?t:this.order,!n){var i=[/^(html5|native)/i,/^flash/i,/iframe$/i],o=function(e){for(var t=0,n=i.length;t<n;t++)if(i[t].test(e))return t;return i.length};t.sort(function(e,t){return o(e)-o(t)})}for(var a=0,r=t.length;a<r;a++){var s=t[a],l=this.renderers[s];if(null!==l&&void 0!==l)for(var d=0,u=e.length;d<u;d++)if("function"==typeof l.canPlayType&&"string"==typeof e[d].type&&l.canPlayType(e[d].type))return{rendererName:l.name,src:e[d].src}}return null}},{key:"order",set:function(e){if(!Array.isArray(e))throw new TypeError("order must be an array of strings.");this._order=e},get:function(){return this._order}},{key:"renderers",set:function(e){if(null!==e&&"object"!==(void 0===e?"undefined":o(e)))throw new TypeError("renderers must be an array of objects.");this._renderers=e},get:function(){return this._renderers}}]),e}(),l=n.renderer=new s;r.default.Renderers=l},{6:6}],8:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(2)),r=i(e(4)),s=e(16),l=i(s),d=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}(e(23)),u=e(25),c=e(24);Object.assign(s.config,{usePluginFullScreen:!0,fullscreenText:null}),Object.assign(l.default.prototype,{isFullScreen:!1,isNativeFullScreen:!1,isInIframe:!1,isPluginClickThroughCreated:!1,fullscreenMode:"",containerSizeTimeout:null,buildfullscreen:function(e){if(e.isVideo){e.isInIframe=o.default.location!==o.default.parent.location,e.detectFullscreenMode();var t=this,n=(0,u.isString)(t.options.fullscreenText)?t.options.fullscreenText:r.default.t("mejs.fullscreen"),i=a.default.createElement("div");if(i.className=t.options.classPrefix+"button "+t.options.classPrefix+"fullscreen-button",i.innerHTML='<button type="button" aria-controls="'+t.id+'" title="'+n+'" aria-label="'+n+'" tabindex="0"></button>',t.addControlElement(i,"fullscreen"),i.addEventListener("click",function(){d.HAS_TRUE_NATIVE_FULLSCREEN&&d.IS_FULLSCREEN||e.isFullScreen?e.exitFullScreen():e.enterFullScreen()}),e.fullscreenBtn=i,t.globalBind("keydown",function(n){27===(n.which||n.keyCode||0)&&(d.HAS_TRUE_NATIVE_FULLSCREEN&&d.IS_FULLSCREEN||t.isFullScreen)&&e.exitFullScreen()}),t.normalHeight=0,t.normalWidth=0,d.HAS_TRUE_NATIVE_FULLSCREEN){e.globalBind(d.FULLSCREEN_EVENT_NAME,function(){e.isFullScreen&&(d.isFullScreen()?(e.isNativeFullScreen=!0,e.setControlsSize()):(e.isNativeFullScreen=!1,e.exitFullScreen()))})}}},detectFullscreenMode:function(){var e=this,t=null!==e.media.rendererName&&/(native|html5)/i.test(e.media.rendererName),n="";return n=d.HAS_TRUE_NATIVE_FULLSCREEN&&t?"native-native":d.HAS_TRUE_NATIVE_FULLSCREEN&&!t?"plugin-native":e.usePluginFullScreen&&d.SUPPORT_POINTER_EVENTS?"plugin-click":"fullwindow",e.fullscreenMode=n,n},cleanfullscreen:function(e){e.exitFullScreen()},enterFullScreen:function(){var e=this,t=null!==e.media.rendererName&&/(html5|native)/i.test(e.media.rendererName),n=getComputedStyle(e.container);if(d.IS_IOS&&d.HAS_IOS_FULLSCREEN)"function"==typeof e.media.webkitEnterFullscreen?e.media.webkitEnterFullscreen():e.media.originalNode.webkitEnterFullscreen();else{if((0,c.addClass)(a.default.documentElement,e.options.classPrefix+"fullscreen"),(0,c.addClass)(e.container,e.options.classPrefix+"container-fullscreen"),e.normalHeight=parseFloat(n.height),e.normalWidth=parseFloat(n.width),"native-native"!==e.fullscreenMode&&"plugin-native"!==e.fullscreenMode||(d.requestFullScreen(e.container),e.isInIframe&&setTimeout(function t(){if(e.isNativeFullScreen){var n=o.default.innerWidth||a.default.documentElement.clientWidth||a.default.body.clientWidth,i=screen.width;Math.abs(i-n)>.002*i?e.exitFullScreen():setTimeout(t,500)}},1e3)),e.container.style.width="100%",e.container.style.height="100%",e.containerSizeTimeout=setTimeout(function(){e.container.style.width="100%",e.container.style.height="100%",e.setControlsSize()},500),t)e.node.style.width="100%",e.node.style.height="100%";else for(var i=e.container.querySelectorAll("iframe, embed, object, video"),r=i.length,s=0;s<r;s++)i[s].style.width="100%",i[s].style.height="100%";e.options.setDimensions&&"function"==typeof e.media.setSize&&e.media.setSize(screen.width,screen.height);for(var l=e.layers.childNodes,f=l.length,p=0;p<f;p++)l[p].style.width="100%",l[p].style.height="100%";e.fullscreenBtn&&((0,c.removeClass)(e.fullscreenBtn,e.options.classPrefix+"fullscreen"),(0,c.addClass)(e.fullscreenBtn,e.options.classPrefix+"unfullscreen")),e.setControlsSize(),e.isFullScreen=!0;var m=Math.min(screen.width/e.width,screen.height/e.height),h=e.container.querySelector("."+e.options.classPrefix+"captions-text");h&&(h.style.fontSize=100*m+"%",h.style.lineHeight="normal",e.container.querySelector("."+e.options.classPrefix+"captions-position").style.bottom="45px");var v=(0,u.createEvent)("enteredfullscreen",e.container);e.container.dispatchEvent(v)}},exitFullScreen:function(){var e=this,t=null!==e.media.rendererName&&/(native|html5)/i.test(e.media.rendererName);if(clearTimeout(e.containerSizeTimeout),d.HAS_TRUE_NATIVE_FULLSCREEN&&(d.IS_FULLSCREEN||e.isFullScreen)&&d.cancelFullScreen(),(0,c.removeClass)(a.default.documentElement,e.options.classPrefix+"fullscreen"),(0,c.removeClass)(e.container,e.options.classPrefix+"container-fullscreen"),e.options.setDimensions){if(e.container.style.width=e.normalWidth+"px",e.container.style.height=e.normalHeight+"px",t)e.node.style.width=e.normalWidth+"px",e.node.style.height=e.normalHeight+"px";else for(var n=e.container.querySelectorAll("iframe, embed, object, video"),i=n.length,o=0;o<i;o++)n[o].style.width=e.normalWidth+"px",n[o].style.height=e.normalHeight+"px";"function"==typeof e.media.setSize&&e.media.setSize(e.normalWidth,e.normalHeight);for(var r=e.layers.childNodes,s=r.length,l=0;l<s;l++)r[l].style.width=e.normalWidth+"px",r[l].style.height=e.normalHeight+"px"}e.fullscreenBtn&&((0,c.removeClass)(e.fullscreenBtn,e.options.classPrefix+"unfullscreen"),(0,c.addClass)(e.fullscreenBtn,e.options.classPrefix+"fullscreen")),e.setControlsSize(),e.isFullScreen=!1;var f=e.container.querySelector("."+e.options.classPrefix+"captions-text");f&&(f.style.fontSize="",f.style.lineHeight="",e.container.querySelector("."+e.options.classPrefix+"captions-position").style.bottom="");var p=(0,u.createEvent)("exitedfullscreen",e.container);e.container.dispatchEvent(p)}})},{16:16,2:2,23:23,24:24,25:25,3:3,4:4}],9:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=e(16),r=i(a),s=i(e(4)),l=e(25),d=e(24);Object.assign(a.config,{playText:null,pauseText:null}),Object.assign(r.default.prototype,{buildplaypause:function(e,t,n,i){function a(e){"play"===e?((0,d.removeClass)(p,r.options.classPrefix+"play"),(0,d.removeClass)(p,r.options.classPrefix+"replay"),(0,d.addClass)(p,r.options.classPrefix+"pause"),m.setAttribute("title",f),m.setAttribute("aria-label",f)):((0,d.removeClass)(p,r.options.classPrefix+"pause"),(0,d.removeClass)(p,r.options.classPrefix+"replay"),(0,d.addClass)(p,r.options.classPrefix+"play"),m.setAttribute("title",c),m.setAttribute("aria-label",c))}var r=this,u=r.options,c=(0,l.isString)(u.playText)?u.playText:s.default.t("mejs.play"),f=(0,l.isString)(u.pauseText)?u.pauseText:s.default.t("mejs.pause"),p=o.default.createElement("div");p.className=r.options.classPrefix+"button "+r.options.classPrefix+"playpause-button "+r.options.classPrefix+"play",p.innerHTML='<button type="button" aria-controls="'+r.id+'" title="'+c+'" aria-label="'+f+'" tabindex="0"></button>',p.addEventListener("click",function(){i.paused?i.play():i.pause()});var m=p.querySelector("button");r.addControlElement(p,"playpause"),a("pse"),i.addEventListener("loadedmetadata",function(){-1===i.rendererName.indexOf("flash")&&a("pse")}),i.addEventListener("play",function(){a("play")}),i.addEventListener("playing",function(){a("play")}),i.addEventListener("pause",function(){a("pse")}),i.addEventListener("ended",function(){e.options.loop||((0,d.removeClass)(p,r.options.classPrefix+"pause"),(0,d.removeClass)(p,r.options.classPrefix+"play"),(0,d.addClass)(p,r.options.classPrefix+"replay"),m.setAttribute("title",c),m.setAttribute("aria-label",c))})}})},{16:16,2:2,24:24,25:25,4:4}],10:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=e(16),r=i(a),s=i(e(4)),l=e(23),d=e(28),u=e(24);Object.assign(a.config,{enableProgressTooltip:!0,useSmoothHover:!0}),Object.assign(r.default.prototype,{buildprogress:function(e,t,n,i){var a=0,r=!1,c=!1,f=this,p=e.options.autoRewind,m=e.options.enableProgressTooltip?'<span class="'+f.options.classPrefix+'time-float"><span class="'+f.options.classPrefix+'time-float-current">00:00</span><span class="'+f.options.classPrefix+'time-float-corner"></span></span>':"",h=o.default.createElement("div");h.className=f.options.classPrefix+"time-rail",h.innerHTML='<span class="'+f.options.classPrefix+"time-total "+f.options.classPrefix+'time-slider"><span class="'+f.options.classPrefix+'time-buffering"></span><span class="'+f.options.classPrefix+'time-loaded"></span><span class="'+f.options.classPrefix+'time-current"></span><span class="'+f.options.classPrefix+'time-hovered no-hover"></span><span class="'+f.options.classPrefix+'time-handle"><span class="'+f.options.classPrefix+'time-handle-content"></span></span>'+m+"</span>",f.addControlElement(h,"progress"),t.querySelector("."+f.options.classPrefix+"time-buffering").style.display="none",f.rail=t.querySelector("."+f.options.classPrefix+"time-rail"),f.total=t.querySelector("."+f.options.classPrefix+"time-total"),f.loaded=t.querySelector("."+f.options.classPrefix+"time-loaded"),f.current=t.querySelector("."+f.options.classPrefix+"time-current"),f.handle=t.querySelector("."+f.options.classPrefix+"time-handle"),f.timefloat=t.querySelector("."+f.options.classPrefix+"time-float"),f.timefloatcurrent=t.querySelector("."+f.options.classPrefix+"time-float-current"),f.slider=t.querySelector("."+f.options.classPrefix+"time-slider"),f.hovered=t.querySelector("."+f.options.classPrefix+"time-hovered"),f.newTime=0,f.forcedHandlePause=!1,f.setTransformStyle=function(e,t){e.style.transform=t,e.style.webkitTransform=t,e.style.MozTransform=t,e.style.msTransform=t,e.style.OTransform=t};var v=function(t){var n=getComputedStyle(f.total),i=(0,u.offset)(f.total),o=parseFloat(n.width),a=void 0!==n.webkitTransform?"webkitTransform":void 0!==n.mozTransform?"mozTransform ":void 0!==n.oTransform?"oTransform":void 0!==n.msTransform?"msTransform":"transform",s="WebKitCSSMatrix"in window?"WebKitCSSMatrix":"MSCSSMatrix"in window?"MSCSSMatrix":"CSSMatrix"in window?"CSSMatrix":void 0,c=0,p=0,m=void 0;if(m=t.originalEvent&&t.originalEvent.changedTouches?t.originalEvent.changedTouches[0].pageX:t.changedTouches?t.changedTouches[0].pageX:t.pageX,f.getDuration()&&(m<i.left?m=i.left:m>o+i.left&&(m=o+i.left),p=m-i.left,c=p/o,f.newTime=c<=.02?0:c*f.getDuration(),r&&null!==f.getCurrentTime()&&f.newTime.toFixed(4)!==f.getCurrentTime().toFixed(4)&&(f.setCurrentRailHandle(f.newTime),f.updateCurrent(f.newTime)),!l.IS_IOS&&!l.IS_ANDROID&&f.timefloat)){if(p<0&&(p=0),f.options.useSmoothHover&&null!==s&&void 0!==window[s]){var h=new window[s](getComputedStyle(f.handle)[a]).m41,v=p/parseFloat(getComputedStyle(f.total).width)-h/parseFloat(getComputedStyle(f.total).width);f.hovered.style.left=h+"px",f.setTransformStyle(f.hovered,"scaleX("+v+")"),f.hovered.setAttribute("pos",p),v>=0?(0,u.removeClass)(f.hovered,"negative"):(0,u.addClass)(f.hovered,"negative")}f.timefloat.style.left=p+"px",f.timefloatcurrent.innerHTML=(0,d.secondsToTimeCode)(f.newTime,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength),f.timefloat.style.display="block"}},y=function(){var t=f.getCurrentTime(),n=s.default.t("mejs.time-slider"),o=(0,d.secondsToTimeCode)(t,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength),a=f.getDuration();f.slider.setAttribute("role","slider"),f.slider.tabIndex=0,i.paused?(f.slider.setAttribute("aria-label",n),f.slider.setAttribute("aria-valuemin",0),f.slider.setAttribute("aria-valuemax",a),f.slider.setAttribute("aria-valuenow",t),f.slider.setAttribute("aria-valuetext",o)):(f.slider.removeAttribute("aria-label"),f.slider.removeAttribute("aria-valuemin"),f.slider.removeAttribute("aria-valuemax"),f.slider.removeAttribute("aria-valuenow"),f.slider.removeAttribute("aria-valuetext"))},g=function(){new Date-a>=1e3&&i.play()},b=function(){r&&null!==f.getCurrentTime()&&f.newTime.toFixed(4)!==f.getCurrentTime().toFixed(4)&&(f.setCurrentTime(f.newTime),e.setCurrentRail(),f.updateCurrent(f.newTime)),f.forcedHandlePause&&f.media.play(),f.forcedHandlePause=!1};f.slider.addEventListener("focus",function(){e.options.autoRewind=!1}),f.slider.addEventListener("blur",function(){e.options.autoRewind=p}),f.slider.addEventListener("keydown",function(t){if(new Date-a>=1e3&&(c=i.paused),f.options.keyActions.length){var n=t.which||t.keyCode||0,o=f.getDuration(),r=e.options.defaultSeekForwardInterval(i),s=e.options.defaultSeekBackwardInterval(i),d=f.getCurrentTime();switch(n){case 37:case 40:f.getDuration()!==1/0&&(d-=s);break;case 39:case 38:f.getDuration()!==1/0&&(d+=r);break;case 36:d=0;break;case 35:d=o;break;case 32:return void(l.IS_FIREFOX||(i.paused?i.play():i.pause()));case 13:return void(i.paused?i.play():i.pause());default:return}d=d<0?0:d>=o?o:Math.floor(d),a=new Date,c||i.pause(),d<f.getDuration()&&!c&&setTimeout(g,1100),f.setCurrentTime(d),t.preventDefault(),t.stopPropagation()}});var E=["mousedown","touchstart"];f.slider.addEventListener("dragstart",function(){return!1});for(var S=0,x=E.length;S<x;S++)f.slider.addEventListener(E[S],function(e){if(f.forcedHandlePause=!1,f.getDuration()!==1/0&&(1===e.which||0===e.which)){i.paused||(f.media.pause(),f.forcedHandlePause=!0),r=!0,v(e);for(var t=["mouseup","touchend"],n=0,o=t.length;n<o;n++)f.container.addEventListener(t[n],function(e){var t=e.target;(t===f.slider||t.closest("."+f.options.classPrefix+"time-slider"))&&v(e)});f.globalBind("mouseup.dur touchend.dur",function(){b(),r=!1,f.timefloat&&(f.timefloat.style.display="none"),f.globalUnbind("mousemove.dur touchmove.dur mouseup.dur touchend.dur")})}});f.slider.addEventListener("mouseenter",function(e){e.target===f.slider&&f.getDuration()!==1/0&&(f.container.addEventListener("mousemove",function(e){var t=e.target;(t===f.slider||t.closest("."+f.options.classPrefix+"time-slider"))&&v(e)}),!f.timefloat||l.IS_IOS||l.IS_ANDROID||(f.timefloat.style.display="block"),f.hovered&&!l.IS_IOS&&!l.IS_ANDROID&&f.options.useSmoothHover&&(0,u.removeClass)(f.hovered,"no-hover"))}),f.slider.addEventListener("mouseleave",function(){f.getDuration()!==1/0&&(r||(f.globalUnbind("mousemove.dur"),f.timefloat&&(f.timefloat.style.display="none"),f.hovered&&f.options.useSmoothHover&&(0,u.addClass)(f.hovered,"no-hover")))}),i.addEventListener("progress",function(n){var i=t.querySelector("."+f.options.classPrefix+"broadcast");if(f.getDuration()!==1/0)i&&(f.slider.style.display="",i.remove()),e.setProgressRail(n),f.forcedHandlePause||e.setCurrentRail(n);else if(!i){var a=o.default.createElement("span");a.className=f.options.classPrefix+"broadcast",a.innerText=s.default.t("mejs.live-broadcast"),f.slider.style.display="none"}}),i.addEventListener("timeupdate",function(n){var i=t.querySelector("."+f.options.classPrefix+"broadcast");if(f.getDuration()!==1/0)i&&(f.slider.style.display="",i.remove()),e.setProgressRail(n),f.forcedHandlePause||e.setCurrentRail(n),y();else if(!i){var a=o.default.createElement("span");a.className=f.options.classPrefix+"broadcast",a.innerText=s.default.t("mejs.live-broadcast"),t.querySelector("."+f.options.classPrefix+"time-rail").appendChild(a),f.slider.style.display="none"}}),f.container.addEventListener("controlsresize",function(t){f.getDuration()!==1/0&&(e.setProgressRail(t),f.forcedHandlePause||e.setCurrentRail(t))})},setProgressRail:function(e){var t=this,n=void 0!==e?e.detail.target||e.target:t.media,i=null;n&&n.buffered&&n.buffered.length>0&&n.buffered.end&&t.getDuration()?i=n.buffered.end(n.buffered.length-1)/t.getDuration():n&&void 0!==n.bytesTotal&&n.bytesTotal>0&&void 0!==n.bufferedBytes?i=n.bufferedBytes/n.bytesTotal:e&&e.lengthComputable&&0!==e.total&&(i=e.loaded/e.total),null!==i&&(i=Math.min(1,Math.max(0,i)),t.loaded&&t.setTransformStyle(t.loaded,"scaleX("+i+")"))},setCurrentRailHandle:function(e){var t=this;t.setCurrentRailMain(t,e)},setCurrentRail:function(){var e=this;e.setCurrentRailMain(e)},setCurrentRailMain:function(e,t){if(void 0!==e.getCurrentTime()&&e.getDuration()){var n=void 0===t?e.getCurrentTime():t;if(e.total&&e.handle){var i=parseFloat(getComputedStyle(e.total).width),o=Math.round(i*n/e.getDuration()),a=o-Math.round(e.handle.offsetWidth/2);if(a=a<0?0:a,e.setTransformStyle(e.current,"scaleX("+o/i+")"),e.setTransformStyle(e.handle,"translateX("+a+"px)"),e.options.useSmoothHover&&!(0,u.hasClass)(e.hovered,"no-hover")){var r=parseInt(e.hovered.getAttribute("pos")),s=(r=isNaN(r)?0:r)/i-a/i;e.hovered.style.left=a+"px",e.setTransformStyle(e.hovered,"scaleX("+s+")"),s>=0?(0,u.removeClass)(e.hovered,"negative"):(0,u.addClass)(e.hovered,"negative")}}}}})},{16:16,2:2,23:23,24:24,28:28,4:4}],11:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=e(16),r=i(a),s=e(28),l=e(24);Object.assign(a.config,{duration:0,timeAndDurationSeparator:"<span> | </span>"}),Object.assign(r.default.prototype,{buildcurrent:function(e,t,n,i){var a=this,r=o.default.createElement("div");r.className=a.options.classPrefix+"time",r.setAttribute("role","timer"),r.setAttribute("aria-live","off"),r.innerHTML='<span class="'+a.options.classPrefix+'currenttime">'+(0,s.secondsToTimeCode)(0,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength)+"</span>",a.addControlElement(r,"current"),i.addEventListener("timeupdate",function(){a.controlsAreVisible&&e.updateCurrent()})},buildduration:function(e,t,n,i){var a=this;if(t.lastChild.querySelector("."+a.options.classPrefix+"currenttime"))t.querySelector("."+a.options.classPrefix+"time").innerHTML+=a.options.timeAndDurationSeparator+'<span class="'+a.options.classPrefix+'duration">'+(0,s.secondsToTimeCode)(a.options.duration,a.options.alwaysShowHours,a.options.showTimecodeFrameCount,a.options.framesPerSecond,a.options.secondsDecimalLength)+"</span>";else{t.querySelector("."+a.options.classPrefix+"currenttime")&&(0,l.addClass)(t.querySelector("."+a.options.classPrefix+"currenttime").parentNode,a.options.classPrefix+"currenttime-container");var r=o.default.createElement("div");r.className=a.options.classPrefix+"time "+a.options.classPrefix+"duration-container",r.innerHTML='<span class="'+a.options.classPrefix+'duration">'+(0,s.secondsToTimeCode)(a.options.duration,a.options.alwaysShowHours,a.options.showTimecodeFrameCount,a.options.framesPerSecond,a.options.secondsDecimalLength)+"</span>",a.addControlElement(r,"duration")}i.addEventListener("timeupdate",function(){a.controlsAreVisible&&e.updateDuration()})},updateCurrent:function(){var e=this,t=e.getCurrentTime();isNaN(t)&&(t=0),e.controls.querySelector("."+e.options.classPrefix+"currenttime")&&(e.controls.querySelector("."+e.options.classPrefix+"currenttime").innerText=(0,s.secondsToTimeCode)(t,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength))},updateDuration:function(){var e=this,t=e.getDuration();(isNaN(t)||t===1/0||t<0)&&(e.media.duration=e.options.duration=t=0),e.options.duration>0&&(t=e.options.duration);var n=(0,s.secondsToTimeCode)(t,e.options.alwaysShowHours,e.options.showTimecodeFrameCount,e.options.framesPerSecond,e.options.secondsDecimalLength);n.length>5&&(0,l.toggleClass)(e.container,e.options.classPrefix+"long-video"),e.controls.querySelector("."+e.options.classPrefix+"duration")&&t>0&&(e.controls.querySelector("."+e.options.classPrefix+"duration").innerHTML=n)}})},{16:16,2:2,24:24,28:28}],12:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=i(e(6)),r=i(e(4)),s=e(16),l=i(s),d=e(28),u=e(25),c=e(24);Object.assign(s.config,{startLanguage:"",tracksText:null,chaptersText:null,tracksAriaLive:!1,hideCaptionsButtonWhenEmpty:!0,toggleCaptionsButtonWhenOnlyOne:!1,slidesSelector:""}),Object.assign(l.default.prototype,{hasChapters:!1,buildtracks:function(e,t,n,i){if(e.tracks.length||e.trackFiles&&0!==!e.trackFiles.length){var a=this,s=a.options.tracksAriaLive?' role="log" aria-live="assertive" aria-atomic="false"':"",l=(0,u.isString)(a.options.tracksText)?a.options.tracksText:r.default.t("mejs.captions-subtitles"),d=(0,u.isString)(a.options.chaptersText)?a.options.chaptersText:r.default.t("mejs.captions-chapters"),f=null===e.trackFiles?e.tracks.length:e.trackFiles.length;if(a.domNode.textTracks)for(var p=a.domNode.textTracks.length-1;p>=0;p--)a.domNode.textTracks[p].mode="hidden";a.cleartracks(e),e.captions=o.default.createElement("div"),e.captions.className=a.options.classPrefix+"captions-layer "+a.options.classPrefix+"layer",e.captions.innerHTML='<div class="'+a.options.classPrefix+"captions-position "+a.options.classPrefix+'captions-position-hover"'+s+'><span class="'+a.options.classPrefix+'captions-text"></span></div>',e.captions.style.display="none",n.insertBefore(e.captions,n.firstChild),e.captionsText=e.captions.querySelector("."+a.options.classPrefix+"captions-text"),e.captionsButton=o.default.createElement("div"),e.captionsButton.className=a.options.classPrefix+"button "+a.options.classPrefix+"captions-button",e.captionsButton.innerHTML='<button type="button" aria-controls="'+a.id+'" title="'+l+'" aria-label="'+l+'" tabindex="0"></button><div class="'+a.options.classPrefix+"captions-selector "+a.options.classPrefix+'offscreen"><ul class="'+a.options.classPrefix+'captions-selector-list"><li class="'+a.options.classPrefix+'captions-selector-list-item"><input type="radio" class="'+a.options.classPrefix+'captions-selector-input" name="'+e.id+'_captions" id="'+e.id+'_captions_none" value="none" checked disabled><label class="'+a.options.classPrefix+"captions-selector-label "+a.options.classPrefix+'captions-selected" for="'+e.id+'_captions_none">'+r.default.t("mejs.none")+"</label></li></ul></div>",a.addControlElement(e.captionsButton,"tracks"),e.captionsButton.querySelector("."+a.options.classPrefix+"captions-selector-input").disabled=!1,e.chaptersButton=o.default.createElement("div"),e.chaptersButton.className=a.options.classPrefix+"button "+a.options.classPrefix+"chapters-button",e.chaptersButton.innerHTML='<button type="button" aria-controls="'+a.id+'" title="'+d+'" aria-label="'+d+'" tabindex="0"></button><div class="'+a.options.classPrefix+"chapters-selector "+a.options.classPrefix+'offscreen"><ul class="'+a.options.classPrefix+'chapters-selector-list"></ul></div>';for(var m=0,h=0;h<f;h++){var v=e.tracks[h].kind;"subtitles"===v||"captions"===v?m++:"chapters"!==v||t.querySelector("."+a.options.classPrefix+"chapter-selector")||e.captionsButton.parentNode.insertBefore(e.chaptersButton,e.captionsButton)}e.trackToLoad=-1,e.selectedTrack=null,e.isLoadingTrack=!1;for(var y=0;y<f;y++){var g=e.tracks[y].kind;"subtitles"!==g&&"captions"!==g||e.addTrackButton(e.tracks[y].trackId,e.tracks[y].srclang,e.tracks[y].label)}e.loadNextTrack();var b=["mouseenter","focusin"],E=["mouseleave","focusout"];if(a.options.toggleCaptionsButtonWhenOnlyOne&&1===m)e.captionsButton.addEventListener("click",function(){var t="none";null===e.selectedTrack&&(t=e.tracks[0].trackId),e.setTrack(t)});else{for(var S=e.captionsButton.querySelectorAll("."+a.options.classPrefix+"captions-selector-label"),x=e.captionsButton.querySelectorAll("input[type=radio]"),w=0,P=b.length;w<P;w++)e.captionsButton.addEventListener(b[w],function(){(0,c.removeClass)(this.querySelector("."+a.options.classPrefix+"captions-selector"),a.options.classPrefix+"offscreen")});for(var T=0,C=E.length;T<C;T++)e.captionsButton.addEventListener(E[T],function(){(0,c.addClass)(this.querySelector("."+a.options.classPrefix+"captions-selector"),a.options.classPrefix+"offscreen")});for(var k=0,_=x.length;k<_;k++)x[k].addEventListener("click",function(){e.setTrack(this.value)});for(var N=0,A=S.length;N<A;N++)S[N].addEventListener("click",function(){var e=(0,c.siblings)(this,function(e){return"INPUT"===e.tagName})[0],t=(0,u.createEvent)("click",e);e.dispatchEvent(t)});e.captionsButton.addEventListener("keydown",function(e){e.stopPropagation()})}for(var L=0,F=b.length;L<F;L++)e.chaptersButton.addEventListener(b[L],function(){this.querySelector("."+a.options.classPrefix+"chapters-selector-list").childNodes.length&&(0,c.removeClass)(this.querySelector("."+a.options.classPrefix+"chapters-selector"),a.options.classPrefix+"offscreen")});for(var j=0,I=E.length;j<I;j++)e.chaptersButton.addEventListener(E[j],function(){(0,c.addClass)(this.querySelector("."+a.options.classPrefix+"chapters-selector"),a.options.classPrefix+"offscreen")});e.chaptersButton.addEventListener("keydown",function(e){e.stopPropagation()}),e.options.alwaysShowControls?(0,c.addClass)(e.container.querySelector("."+a.options.classPrefix+"captions-position"),a.options.classPrefix+"captions-position-hover"):(e.container.addEventListener("controlsshown",function(){(0,c.addClass)(e.container.querySelector("."+a.options.classPrefix+"captions-position"),a.options.classPrefix+"captions-position-hover")}),e.container.addEventListener("controlshidden",function(){i.paused||(0,c.removeClass)(e.container.querySelector("."+a.options.classPrefix+"captions-position"),a.options.classPrefix+"captions-position-hover")})),i.addEventListener("timeupdate",function(){e.displayCaptions()}),""!==e.options.slidesSelector&&(e.slidesContainer=o.default.querySelectorAll(e.options.slidesSelector),i.addEventListener("timeupdate",function(){e.displaySlides()}))}},cleartracks:function(e){e&&(e.captions&&e.captions.remove(),e.chapters&&e.chapters.remove(),e.captionsText&&e.captionsText.remove(),e.captionsButton&&e.captionsButton.remove(),e.chaptersButton&&e.chaptersButton.remove())},rebuildtracks:function(){var e=this;e.findTracks(),e.buildtracks(e,e.controls,e.layers,e.media)},findTracks:function(){var e=this,t=null===e.trackFiles?e.node.querySelectorAll("track"):e.trackFiles,n=t.length;e.tracks=[];for(var i=0;i<n;i++){var o=t[i],a=o.getAttribute("srclang").toLowerCase()||"",r=e.id+"_track_"+i+"_"+o.getAttribute("kind")+"_"+a;e.tracks.push({trackId:r,srclang:a,src:o.getAttribute("src"),kind:o.getAttribute("kind"),label:o.getAttribute("label")||"",entries:[],isLoaded:!1})}},setTrack:function(e){for(var t=this,n=t.captionsButton.querySelectorAll('input[type="radio"]'),i=t.captionsButton.querySelectorAll("."+t.options.classPrefix+"captions-selected"),o=t.captionsButton.querySelector('input[value="'+e+'"]'),a=0,r=n.length;a<r;a++)n[a].checked=!1;for(var s=0,l=i.length;s<l;s++)(0,c.removeClass)(i[s],t.options.classPrefix+"captions-selected");o.checked=!0;for(var d=(0,c.siblings)(o,function(e){return(0,c.hasClass)(e,t.options.classPrefix+"captions-selector-label")}),f=0,p=d.length;f<p;f++)(0,c.addClass)(d[f],t.options.classPrefix+"captions-selected");if("none"===e)t.selectedTrack=null,(0,c.removeClass)(t.captionsButton,t.options.classPrefix+"captions-enabled");else for(var m=0,h=t.tracks.length;m<h;m++){var v=t.tracks[m];if(v.trackId===e){null===t.selectedTrack&&(0,c.addClass)(t.captionsButton,t.options.classPrefix+"captions-enabled"),t.selectedTrack=v,t.captions.setAttribute("lang",t.selectedTrack.srclang),t.displayCaptions();break}}var y=(0,u.createEvent)("captionschange",t.media);y.detail.caption=t.selectedTrack,t.media.dispatchEvent(y)},loadNextTrack:function(){var e=this;e.trackToLoad++,e.trackToLoad<e.tracks.length?(e.isLoadingTrack=!0,e.loadTrack(e.trackToLoad)):(e.isLoadingTrack=!1,e.checkForTracks())},loadTrack:function(e){var t=this,n=t.tracks[e];void 0===n||void 0===n.src&&""===n.src||(0,c.ajax)(n.src,"text",function(e){n.entries="string"==typeof e&&/<tt\s+xml/gi.exec(e)?a.default.TrackFormatParser.dfxp.parse(e):a.default.TrackFormatParser.webvtt.parse(e),n.isLoaded=!0,t.enableTrackButton(n),t.loadNextTrack(),"slides"===n.kind?t.setupSlides(n):"chapters"!==n.kind||t.hasChapters||(t.drawChapters(n),t.hasChapters=!0)},function(){t.removeTrackButton(n.trackId),t.loadNextTrack()})},enableTrackButton:function(e){var t=this,n=e.srclang,i=o.default.getElementById(""+e.trackId);if(i){var s=e.label;""===s&&(s=r.default.t(a.default.language.codes[n])||n),i.disabled=!1;for(var l=(0,c.siblings)(i,function(e){return(0,c.hasClass)(e,t.options.classPrefix+"captions-selector-label")}),d=0,f=l.length;d<f;d++)l[d].innerHTML=s;if(t.options.startLanguage===n){i.checked=!0;var p=(0,u.createEvent)("click",i);i.dispatchEvent(p)}}},removeTrackButton:function(e){var t=o.default.getElementById(""+e);if(t){var n=t.closest("li");n&&n.remove()}},addTrackButton:function(e,t,n){var i=this;""===n&&(n=r.default.t(a.default.language.codes[t])||t),i.captionsButton.querySelector("ul").innerHTML+='<li class="'+i.options.classPrefix+'captions-selector-list-item"><input type="radio" class="'+i.options.classPrefix+'captions-selector-input" name="'+i.id+'_captions" id="'+e+'" value="'+e+'" disabled><label class="'+i.options.classPrefix+'captions-selector-label"for="'+e+'">'+n+" (loading)</label></li>"},checkForTracks:function(){var e=this,t=!1;if(e.options.hideCaptionsButtonWhenEmpty){for(var n=0,i=e.tracks.length;n<i;n++){var o=e.tracks[n].kind;if(("subtitles"===o||"captions"===o)&&e.tracks[n].isLoaded){t=!0;break}}e.captionsButton.style.display=t?"":"none",e.setControlsSize()}},displayCaptions:function(){if(void 0!==this.tracks){var e=this,t=e.selectedTrack;if(null!==t&&t.isLoaded){var n=e.searchTrackPosition(t.entries,e.media.currentTime);if(n>-1)return e.captionsText.innerHTML=function(e){var t=o.default.createElement("div");t.innerHTML=e;for(var n=t.getElementsByTagName("script"),i=n.length;i--;)n[i].remove();for(var a=t.getElementsByTagName("*"),r=0,s=a.length;r<s;r++)for(var l=a[r].attributes,d=Array.prototype.slice.call(l),u=0,c=d.length;u<c;u++)d[u].name.startsWith("on")||d[u].value.startsWith("javascript")?a[r].remove():"style"===d[u].name&&a[r].removeAttribute(d[u].name);return t.innerHTML}(t.entries[n].text),e.captionsText.className=e.options.classPrefix+"captions-text "+(t.entries[n].identifier||""),e.captions.style.display="",void(e.captions.style.height="0px");e.captions.style.display="none"}else e.captions.style.display="none"}},setupSlides:function(e){var t=this;t.slides=e,t.slides.entries.imgs=[t.slides.entries.length],t.showSlide(0)},showSlide:function(e){var t=this,n=this;if(void 0!==n.tracks&&void 0!==n.slidesContainer){var i=n.slides.entries[e].text,a=n.slides.entries[e].imgs;if(void 0===a||void 0===a.fadeIn){var r=o.default.createElement("img");r.src=i,r.addEventListener("load",function(){var e=t,i=(0,c.siblings)(e,function(e){return i(e)});e.style.display="none",n.slidesContainer.innerHTML+=e.innerHTML,(0,c.fadeIn)(n.slidesContainer.querySelector(r));for(var o=0,a=i.length;o<a;o++)(0,c.fadeOut)(i[o],400)}),n.slides.entries[e].imgs=a=r}else if(!(0,c.visible)(a)){var s=(0,c.siblings)(self,function(e){return s(e)});(0,c.fadeIn)(n.slidesContainer.querySelector(a));for(var l=0,d=s.length;l<d;l++)(0,c.fadeOut)(s[l])}}},displaySlides:function(){var e=this;if(void 0!==this.slides){var t=e.slides,n=e.searchTrackPosition(t.entries,e.media.currentTime);n>-1&&e.showSlide(n)}},drawChapters:function(e){var t=this,n=e.entries.length;if(n){t.chaptersButton.querySelector("ul").innerHTML="";for(var i=0;i<n;i++)t.chaptersButton.querySelector("ul").innerHTML+='<li class="'+t.options.classPrefix+'chapters-selector-list-item" role="menuitemcheckbox" aria-live="polite" aria-disabled="false" aria-checked="false"><input type="radio" class="'+t.options.classPrefix+'captions-selector-input" name="'+t.id+'_chapters" id="'+t.id+"_chapters_"+i+'" value="'+e.entries[i].start+'" disabled><label class="'+t.options.classPrefix+'chapters-selector-label"for="'+t.id+"_chapters_"+i+'">'+e.entries[i].text+"</label></li>";for(var o=t.chaptersButton.querySelectorAll('input[type="radio"]'),a=t.chaptersButton.querySelectorAll("."+t.options.classPrefix+"chapters-selector-label"),r=0,s=o.length;r<s;r++)o[r].disabled=!1,o[r].checked=!1,o[r].addEventListener("click",function(){var e=this,n=t.chaptersButton.querySelectorAll("li"),i=(0,c.siblings)(e,function(e){return(0,c.hasClass)(e,t.options.classPrefix+"chapters-selector-label")})[0];e.checked=!0,e.parentNode.setAttribute("aria-checked",!0),(0,c.addClass)(i,t.options.classPrefix+"chapters-selected"),(0,c.removeClass)(t.chaptersButton.querySelector("."+t.options.classPrefix+"chapters-selected"),t.options.classPrefix+"chapters-selected");for(var o=0,a=n.length;o<a;o++)n[o].setAttribute("aria-checked",!1);t.media.setCurrentTime(parseFloat(e.value)),t.media.paused&&t.media.play()});for(var l=0,d=a.length;l<d;l++)a[l].addEventListener("click",function(){var e=(0,c.siblings)(this,function(e){return"INPUT"===e.tagName})[0],t=(0,u.createEvent)("click",e);e.dispatchEvent(t)})}},searchTrackPosition:function(e,t){for(var n=0,i=e.length-1,o=void 0,a=void 0,r=void 0;n<=i;){if(o=n+i>>1,a=e[o].start,r=e[o].stop,t>=a&&t<r)return o;a<t?n=o+1:a>t&&(i=o-1)}return-1}}),a.default.language={codes:{af:"mejs.afrikaans",sq:"mejs.albanian",ar:"mejs.arabic",be:"mejs.belarusian",bg:"mejs.bulgarian",ca:"mejs.catalan",zh:"mejs.chinese","zh-cn":"mejs.chinese-simplified","zh-tw":"mejs.chines-traditional",hr:"mejs.croatian",cs:"mejs.czech",da:"mejs.danish",nl:"mejs.dutch",en:"mejs.english",et:"mejs.estonian",fl:"mejs.filipino",fi:"mejs.finnish",fr:"mejs.french",gl:"mejs.galician",de:"mejs.german",el:"mejs.greek",ht:"mejs.haitian-creole",iw:"mejs.hebrew",hi:"mejs.hindi",hu:"mejs.hungarian",is:"mejs.icelandic",id:"mejs.indonesian",ga:"mejs.irish",it:"mejs.italian",ja:"mejs.japanese",ko:"mejs.korean",lv:"mejs.latvian",lt:"mejs.lithuanian",mk:"mejs.macedonian",ms:"mejs.malay",mt:"mejs.maltese",no:"mejs.norwegian",fa:"mejs.persian",pl:"mejs.polish",pt:"mejs.portuguese",ro:"mejs.romanian",ru:"mejs.russian",sr:"mejs.serbian",sk:"mejs.slovak",sl:"mejs.slovenian",es:"mejs.spanish",sw:"mejs.swahili",sv:"mejs.swedish",tl:"mejs.tagalog",th:"mejs.thai",tr:"mejs.turkish",uk:"mejs.ukrainian",vi:"mejs.vietnamese",cy:"mejs.welsh",yi:"mejs.yiddish"}},a.default.TrackFormatParser={webvtt:{pattern:/^((?:[0-9]{1,2}:)?[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ((?:[0-9]{1,2}:)?[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,parse:function(e){for(var t=e.split(/\r?\n/),n=[],i=void 0,o=void 0,a=void 0,r=0,s=t.length;r<s;r++){if((i=this.pattern.exec(t[r]))&&r<t.length){for(r-1>=0&&""!==t[r-1]&&(a=t[r-1]),o=t[++r],r++;""!==t[r]&&r<t.length;)o=o+"\n"+t[r],r++;o=o.trim().replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi,"<a href='$1' target='_blank'>$1</a>"),n.push({identifier:a,start:0===(0,d.convertSMPTEtoSeconds)(i[1])?.2:(0,d.convertSMPTEtoSeconds)(i[1]),stop:(0,d.convertSMPTEtoSeconds)(i[3]),text:o,settings:i[5]})}a=""}return n}},dfxp:{parse:function(e){var t=(e=$(e).filter("tt")).firstChild,n=t.querySelectorAll("p"),i=e.getElementById(""+t.attr("style")),o=[],a=void 0;if(i.length){i.removeAttribute("id");var r=i.attributes;if(r.length){a={};for(var s=0,l=r.length;s<l;s++)a[r[s].name.split(":")[1]]=r[s].value}}for(var u=0,c=n.length;u<c;u++){var f=void 0,p={start:null,stop:null,style:null,text:null};if(n.eq(u).attr("begin")&&(p.start=(0,d.convertSMPTEtoSeconds)(n.eq(u).attr("begin"))),!p.start&&n.eq(u-1).attr("end")&&(p.start=(0,d.convertSMPTEtoSeconds)(n.eq(u-1).attr("end"))),n.eq(u).attr("end")&&(p.stop=(0,d.convertSMPTEtoSeconds)(n.eq(u).attr("end"))),!p.stop&&n.eq(u+1).attr("begin")&&(p.stop=(0,d.convertSMPTEtoSeconds)(n.eq(u+1).attr("begin"))),a){f="";for(var m in a)f+=m+":"+a[m]+";"}f&&(p.style=f),0===p.start&&(p.start=.2),p.text=n.eq(u).innerHTML.trim().replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi,"<a href='$1' target='_blank'>$1</a>"),o.push(p)}return o}}}},{16:16,2:2,24:24,25:25,28:28,4:4,6:6}],13:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(2)),a=e(16),r=i(a),s=i(e(4)),l=e(23),d=e(25),u=e(24);Object.assign(a.config,{muteText:null,unmuteText:null,allyVolumeControlText:null,hideVolumeOnTouchDevices:!0,audioVolume:"horizontal",videoVolume:"vertical",startVolume:.8}),Object.assign(r.default.prototype,{buildvolume:function(e,t,n,i){if(!l.IS_ANDROID&&!l.IS_IOS||!this.options.hideVolumeOnTouchDevices){var a=this,r=a.isVideo?a.options.videoVolume:a.options.audioVolume,c=(0,d.isString)(a.options.muteText)?a.options.muteText:s.default.t("mejs.mute"),f=(0,d.isString)(a.options.unmuteText)?a.options.unmuteText:s.default.t("mejs.unmute"),p=(0,d.isString)(a.options.allyVolumeControlText)?a.options.allyVolumeControlText:s.default.t("mejs.volume-help-text"),m=o.default.createElement("div");if(m.className=a.options.classPrefix+"button "+a.options.classPrefix+"volume-button "+a.options.classPrefix+"mute",m.innerHTML="horizontal"===r?'<button type="button" aria-controls="'+a.id+'" title="'+c+'" aria-label="'+c+'" tabindex="0"></button>':'<button type="button" aria-controls="'+a.id+'" title="'+c+'" aria-label="'+c+'" tabindex="0"></button><a href="javascript:void(0);" class="'+a.options.classPrefix+'volume-slider" aria-label="'+s.default.t("mejs.volume-slider")+'" aria-valuemin="0" aria-valuemax="100" role="slider" aria-orientation="vertical"><span class="'+a.options.classPrefix+'offscreen">'+p+'</span><div class="'+a.options.classPrefix+'volume-total"><div class="'+a.options.classPrefix+'volume-current"></div><div class="'+a.options.classPrefix+'volume-handle"></div></div></a>',a.addControlElement(m,"volume"),"horizontal"===r){var h=o.default.createElement("a");h.className=a.options.classPrefix+"horizontal-volume-slider",h.href="javascript:void(0);",h.setAttribute("aria-label",s.default.t("mejs.volume-slider")),h.setAttribute("aria-valuemin",0),h.setAttribute("aria-valuemax",100),h.setAttribute("role","slider"),h.innerHTML+='<span class="'+a.options.classPrefix+'offscreen">'+p+'</span><div class="'+a.options.classPrefix+'horizontal-volume-total"><div class="'+a.options.classPrefix+'horizontal-volume-current"></div><div class="'+a.options.classPrefix+'horizontal-volume-handle"></div></div>',m.parentNode.insertBefore(h,m.nextSibling)}var v=!1,y=!1,g=!1,b=function(){var e=Math.floor(100*i.volume);E.setAttribute("aria-valuenow",e),E.setAttribute("aria-valuetext",e+"%")},E="vertical"===r?a.container.querySelector("."+a.options.classPrefix+"volume-slider"):a.container.querySelector("."+a.options.classPrefix+"horizontal-volume-slider"),S="vertical"===r?a.container.querySelector("."+a.options.classPrefix+"volume-total"):a.container.querySelector("."+a.options.classPrefix+"horizontal-volume-total"),x="vertical"===r?a.container.querySelector("."+a.options.classPrefix+"volume-current"):a.container.querySelector("."+a.options.classPrefix+"horizontal-volume-current"),w="vertical"===r?a.container.querySelector("."+a.options.classPrefix+"volume-handle"):a.container.querySelector("."+a.options.classPrefix+"horizontal-volume-handle"),P=function(e){if(null!==e&&!isNaN(e)&&void 0!==e){if(e=Math.max(0,e),0===(e=Math.min(e,1))){(0,u.removeClass)(m,a.options.classPrefix+"mute"),(0,u.addClass)(m,a.options.classPrefix+"unmute");var t=m.firstElementChild;t.setAttribute("title",f),t.setAttribute("aria-label",f)}else{(0,u.removeClass)(m,a.options.classPrefix+"unmute"),(0,u.addClass)(m,a.options.classPrefix+"mute");var n=m.firstElementChild;n.setAttribute("title",c),n.setAttribute("aria-label",c)}var i=100*e+"%",o=getComputedStyle(w);"vertical"===r?(x.style.bottom=0,x.style.height=i,w.style.bottom=i,w.style.marginBottom=-parseFloat(o.height)/2+"px"):(x.style.left=0,x.style.width=i,w.style.left=i,w.style.marginLeft=-parseFloat(o.width)/2+"px")}},T=function(e){var t=(0,u.offset)(S),n=getComputedStyle(S);g=!0;var o=null;if("vertical"===r){var a=parseFloat(n.height);if(o=(a-(e.pageY-t.top))/a,0===t.top||0===t.left)return}else{var s=parseFloat(n.width);o=(e.pageX-t.left)/s}o=Math.max(0,o),o=Math.min(o,1),P(o),i.setMuted(0===o),i.setVolume(o),e.preventDefault(),e.stopPropagation()};m.addEventListener("mouseenter",function(e){e.target===m&&(E.style.display="block",y=!0,e.preventDefault(),e.stopPropagation())}),m.addEventListener("focusin",function(){E.style.display="block",y=!0}),m.addEventListener("focusout",function(e){e.relatedTarget&&(!e.relatedTarget||e.relatedTarget.matches("."+a.options.classPrefix+"volume-slider"))||"vertical"!==r||(E.style.display="none")}),m.addEventListener("mouseleave",function(){y=!1,v||"vertical"!==r||(E.style.display="none")}),m.addEventListener("focusout",function(){y=!1}),m.addEventListener("keydown",function(e){if(a.options.keyActions.length){var t=e.which||e.keyCode||0,n=i.volume;switch(t){case 38:n=Math.min(n+.1,1);break;case 40:n=Math.max(0,n-.1);break;default:return!0}v=!1,P(n),i.setVolume(n),e.preventDefault(),e.stopPropagation()}}),m.querySelector("button").addEventListener("click",function(){i.setMuted(!i.muted);var e=(0,d.createEvent)("volumechange",i);i.dispatchEvent(e)}),E.addEventListener("dragstart",function(){return!1}),E.addEventListener("mouseover",function(){y=!0}),E.addEventListener("focusin",function(){E.style.display="block",y=!0}),E.addEventListener("focusout",function(){y=!1,v||"vertical"!==r||(E.style.display="none")}),E.addEventListener("mousedown",function(e){T(e),a.globalBind("mousemove.vol",function(e){var t=e.target;v&&(t===E||t.closest("vertical"===r?"."+a.options.classPrefix+"volume-slider":"."+a.options.classPrefix+"horizontal-volume-slider"))&&T(e)}),a.globalBind("mouseup.vol",function(){v=!1,a.globalUnbind("mousemove.vol mouseup.vol"),y||"vertical"!==r||(E.style.display="none")}),v=!0,e.preventDefault(),e.stopPropagation()}),i.addEventListener("volumechange",function(e){v||(i.muted?(P(0),(0,u.removeClass)(m,a.options.classPrefix+"mute"),(0,u.addClass)(m,a.options.classPrefix+"unmute")):(P(i.volume),(0,u.removeClass)(m,a.options.classPrefix+"unmute"),(0,u.addClass)(m,a.options.classPrefix+"mute"))),b()});var C=!1;i.addEventListener("rendererready",function(){g||setTimeout(function(){C=!0,0===e.options.startVolume&&i.setMuted(!0),i.setVolume(e.options.startVolume),a.setControlsSize()},250)}),i.addEventListener("loadedmetadata",function(){setTimeout(function(){g||C||(0===e.options.startVolume&&i.setMuted(!0),i.setVolume(e.options.startVolume),a.setControlsSize()),C=!1},250)}),0===e.options.startVolume&&i.setMuted(!0),i.setVolume(e.options.startVolume),a.container.addEventListener("controlsresize",function(){i.muted?(P(0),(0,u.removeClass)(m,a.options.classPrefix+"mute"),(0,u.addClass)(m,a.options.classPrefix+"unmute")):(P(i.volume),(0,u.removeClass)(m,a.options.classPrefix+"unmute"),(0,u.addClass)(m,a.options.classPrefix+"mute"))})}}})},{16:16,2:2,23:23,24:24,25:25,4:4}],14:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});n.EN={"mejs.plural-form":1,"mejs.download-file":"Download File","mejs.install-flash":"You are using a browser that does not have Flash player enabled or installed. Please turn on your Flash player plugin or download the latest version from https://get.adobe.com/flashplayer/","mejs.fullscreen":"Fullscreen","mejs.play":"Play","mejs.pause":"Pause","mejs.time-slider":"Time Slider","mejs.time-help-text":"Use Left/Right Arrow keys to advance one second, Up/Down arrows to advance ten seconds.","mejs.live-broadcast":"Live Broadcast","mejs.volume-help-text":"Use Up/Down Arrow keys to increase or decrease volume.","mejs.unmute":"Unmute","mejs.mute":"Mute","mejs.volume-slider":"Volume Slider","mejs.video-player":"Video Player","mejs.audio-player":"Audio Player","mejs.captions-subtitles":"Captions/Subtitles","mejs.captions-chapters":"Chapters","mejs.none":"None","mejs.afrikaans":"Afrikaans","mejs.albanian":"Albanian","mejs.arabic":"Arabic","mejs.belarusian":"Belarusian","mejs.bulgarian":"Bulgarian","mejs.catalan":"Catalan","mejs.chinese":"Chinese","mejs.chinese-simplified":"Chinese (Simplified)","mejs.chinese-traditional":"Chinese (Traditional)","mejs.croatian":"Croatian","mejs.czech":"Czech","mejs.danish":"Danish","mejs.dutch":"Dutch","mejs.english":"English","mejs.estonian":"Estonian","mejs.filipino":"Filipino","mejs.finnish":"Finnish","mejs.french":"French","mejs.galician":"Galician","mejs.german":"German","mejs.greek":"Greek","mejs.haitian-creole":"Haitian Creole","mejs.hebrew":"Hebrew","mejs.hindi":"Hindi","mejs.hungarian":"Hungarian","mejs.icelandic":"Icelandic","mejs.indonesian":"Indonesian","mejs.irish":"Irish","mejs.italian":"Italian","mejs.japanese":"Japanese","mejs.korean":"Korean","mejs.latvian":"Latvian","mejs.lithuanian":"Lithuanian","mejs.macedonian":"Macedonian","mejs.malay":"Malay","mejs.maltese":"Maltese","mejs.norwegian":"Norwegian","mejs.persian":"Persian","mejs.polish":"Polish","mejs.portuguese":"Portuguese","mejs.romanian":"Romanian","mejs.russian":"Russian","mejs.serbian":"Serbian","mejs.slovak":"Slovak","mejs.slovenian":"Slovenian","mejs.spanish":"Spanish","mejs.swahili":"Swahili","mejs.swedish":"Swedish","mejs.tagalog":"Tagalog","mejs.thai":"Thai","mejs.turkish":"Turkish","mejs.ukrainian":"Ukrainian","mejs.vietnamese":"Vietnamese","mejs.welsh":"Welsh","mejs.yiddish":"Yiddish"}},{}],15:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(6));"undefined"!=typeof jQuery?a.default.$=o.default.jQuery=o.default.$=jQuery:"undefined"!=typeof Zepto?a.default.$=o.default.Zepto=o.default.$=Zepto:"undefined"!=typeof ender&&(a.default.$=o.default.ender=o.default.$=ender)},{3:3,6:6}],16:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0}),n.config=void 0;var a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),s=i(e(3)),l=i(e(2)),d=i(e(6)),u=i(e(5)),c=i(e(4)),f=e(23),p=e(25),m=e(28),h=e(26),v=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}(e(24));d.default.mepIndex=0,d.default.players={};var y=n.config={poster:"",showPosterWhenEnded:!1,showPosterWhenPaused:!1,defaultVideoWidth:480,defaultVideoHeight:270,videoWidth:-1,videoHeight:-1,defaultAudioWidth:400,defaultAudioHeight:40,defaultSeekBackwardInterval:function(e){return.05*e.getDuration()},defaultSeekForwardInterval:function(e){return.05*e.getDuration()},setDimensions:!0,audioWidth:-1,audioHeight:-1,loop:!1,autoRewind:!0,enableAutosize:!0,timeFormat:"",alwaysShowHours:!1,showTimecodeFrameCount:!1,framesPerSecond:25,alwaysShowControls:!1,hideVideoControlsOnLoad:!1,hideVideoControlsOnPause:!1,clickToPlayPause:!0,controlsTimeoutDefault:1500,controlsTimeoutMouseEnter:2500,controlsTimeoutMouseLeave:1e3,iPadUseNativeControls:!1,iPhoneUseNativeControls:!1,AndroidUseNativeControls:!1,features:["playpause","current","progress","duration","tracks","volume","fullscreen"],isVideo:!0,stretching:"auto",classPrefix:"mejs__",enableKeyboard:!0,pauseOtherPlayers:!0,secondsDecimalLength:0,keyActions:[{keys:[32,179],action:function(e,t){f.IS_FIREFOX||(t.paused||t.ended?t.play():t.pause())}},{keys:[38],action:function(e,t){(e.container.querySelector("."+y.classPrefix+"volume-button>button").matches(":focus")||e.container.querySelector("."+y.classPrefix+"volume-slider").matches(":focus"))&&(e.container.querySelector("."+y.classPrefix+"volume-slider").style.display=""),e.isVideo&&(e.showControls(),e.startControlsTimer());var n=Math.min(t.volume+.1,1);t.setVolume(n),n>0&&t.setMuted(!1)}},{keys:[40],action:function(e,t){(e.container.querySelector("."+y.classPrefix+"volume-button>button").matches(":focus")||e.container.querySelector("."+y.classPrefix+"volume-slider").matches(":focus"))&&(e.container.querySelector("."+y.classPrefix+"volume-slider").style.display=""),e.isVideo&&(e.showControls(),e.startControlsTimer());var n=Math.max(t.volume-.1,0);t.setVolume(n),n<=.1&&t.setMuted(!0)}},{keys:[37,227],action:function(e,t){if(!isNaN(t.duration)&&t.duration>0){e.isVideo&&(e.showControls(),e.startControlsTimer());var n=Math.max(t.currentTime-e.options.defaultSeekBackwardInterval(t),0);t.setCurrentTime(n)}}},{keys:[39,228],action:function(e,t){if(!isNaN(t.duration)&&t.duration>0){e.isVideo&&(e.showControls(),e.startControlsTimer());var n=Math.min(t.currentTime+e.options.defaultSeekForwardInterval(t),t.duration);t.setCurrentTime(n)}}},{keys:[70],action:function(e,t,n,i){i.ctrlKey||void 0!==e.enterFullScreen&&(e.isFullScreen?e.exitFullScreen():e.enterFullScreen())}},{keys:[77],action:function(e){e.container.querySelector("."+y.classPrefix+"volume-slider").style.display="",e.isVideo&&(e.showControls(),e.startControlsTimer()),e.media.muted?e.setMuted(!1):e.setMuted(!0)}}]};d.default.MepDefaults=y;var g=function(){function e(t,n){o(this,e);var i=this,a="string"==typeof t?l.default.getElementById(t):t;if(i.hasFocus=!1,i.controlsAreVisible=!0,i.controlsEnabled=!0,i.controlsTimer=null,!(i instanceof e))return new e(a,n);if(i.node=i.media=a,i.node){if(void 0!==i.media.player)return i.media.player;if(void 0===n){var r=i.node.getAttribute("data-mejsoptions");n=r?JSON.parse(r):{}}i.options=Object.assign({},y,n),i.options.timeFormat||(i.options.timeFormat="mm:ss",i.options.alwaysShowHours&&(i.options.timeFormat="hh:mm:ss"),i.options.showTimecodeFrameCount&&(i.options.timeFormat+=":ff")),(0,m.calculateTimeFormat)(0,i.options,i.options.framesPerSecond||25),i.id="mep_"+d.default.mepIndex++,d.default.players[i.id]=i;var s=Object.assign({},i.options,{success:function(e,t){i._meReady(e,t)},error:function(e){i._handleError(e)}}),g=i.node.tagName.toLowerCase();if(i.isDynamic="audio"!==g&&"video"!==g,i.isVideo=i.isDynamic?i.options.isVideo:"audio"!==g&&i.options.isVideo,i.mediaFiles=null,i.trackFiles=null,f.IS_IPAD&&i.options.iPadUseNativeControls||f.IS_IPHONE&&i.options.iPhoneUseNativeControls)i.node.setAttribute("controls",!0),f.IS_IPAD&&i.node.getAttribute("autoplay")&&i.play();else if(!(i.isVideo||!i.isVideo&&i.options.features.length)||f.IS_ANDROID&&i.options.AndroidUseNativeControls)i.isVideo||i.options.features.length||(i.node.style.display="none");else{i.node.removeAttribute("controls");var b=i.isVideo?c.default.t("mejs.video-player"):c.default.t("mejs.audio-player"),E=l.default.createElement("span");if(E.className=i.options.classPrefix+"offscreen",E.innerText=b,i.media.parentNode.insertBefore(E,i.media),i.container=l.default.createElement("div"),i.container.id=i.id,i.container.className=i.options.classPrefix+"container "+i.options.classPrefix+"container-keyboard-inactive "+i.media.className,i.container.tabIndex=0,i.container.setAttribute("role","application"),i.container.setAttribute("aria-label",b),i.container.innerHTML='<div class="'+i.options.classPrefix+'inner"><div class="'+i.options.classPrefix+'mediaelement"></div><div class="'+i.options.classPrefix+'layers"></div><div class="'+i.options.classPrefix+'controls"></div><div class="'+i.options.classPrefix+'clear"></div></div>',i.container.addEventListener("focus",function(e){if(!i.controlsAreVisible&&!i.hasFocus&&i.controlsEnabled){i.showControls(!0);var t=(0,p.isNodeAfter)(e.relatedTarget,i.container)?"."+i.options.classPrefix+"controls ."+i.options.classPrefix+"button:last-child > button":"."+i.options.classPrefix+"playpause-button > button";i.container.querySelector(t).focus()}}),i.node.parentNode.insertBefore(i.container,i.node),i.options.features.length||(i.container.style.background="transparent",i.container.querySelector("."+i.options.classPrefix+"controls").style.display="none"),i.isVideo&&"fill"===i.options.stretching&&!v.hasClass(i.container.parentNode,i.options.classPrefix+"fill-container")){i.outerContainer=i.media.parentNode;var S=l.default.createElement("div");S.className=i.options.classPrefix+"fill-container",i.container.parentNode.insertBefore(S,i.container),S.appendChild(i.container)}if(f.IS_ANDROID&&v.addClass(i.container,i.options.classPrefix+"android"),f.IS_IOS&&v.addClass(i.container,i.options.classPrefix+"ios"),f.IS_IPAD&&v.addClass(i.container,i.options.classPrefix+"ipad"),f.IS_IPHONE&&v.addClass(i.container,i.options.classPrefix+"iphone"),v.addClass(i.container,i.isVideo?i.options.classPrefix+"video":i.options.classPrefix+"audio"),f.IS_SAFARI&&!f.IS_IOS){v.addClass(i.container,i.options.classPrefix+"hide-cues");for(var x=i.node.cloneNode(),w=i.node.childNodes,P=[],T=[],C=0,k=w.length;C<k;C++){var _=w[C];_&&_.nodeType!==Node.TEXT_NODE&&function(){switch(_.tagName.toLowerCase()){case"source":var e={};Array.prototype.slice.call(_.attributes).forEach(function(t){e[t.name]=t.value}),e.type=(0,h.formatType)(e.src,e.type),P.push(e);break;case"track":_.mode="hidden",T.push(_);break;default:x.appendChild(_)}}()}i.node.remove(),i.node=i.media=x,P.length&&(i.mediaFiles=P),T.length&&(i.trackFiles=T)}i.container.querySelector("."+i.options.classPrefix+"mediaelement").appendChild(i.node),i.media.player=i,i.controls=i.container.querySelector("."+i.options.classPrefix+"controls"),i.layers=i.container.querySelector("."+i.options.classPrefix+"layers");var N=i.isVideo?"video":"audio",A=N.substring(0,1).toUpperCase()+N.substring(1);i.options[N+"Width"]>0||i.options[N+"Width"].toString().indexOf("%")>-1?i.width=i.options[N+"Width"]:""!==i.node.style.width&&null!==i.node.style.width?i.width=i.node.style.width:i.node.getAttribute("width")?i.width=i.node.getAttribute("width"):i.width=i.options["default"+A+"Width"],i.options[N+"Height"]>0||i.options[N+"Height"].toString().indexOf("%")>-1?i.height=i.options[N+"Height"]:""!==i.node.style.height&&null!==i.node.style.height?i.height=i.node.style.height:i.node.getAttribute("height")?i.height=i.node.getAttribute("height"):i.height=i.options["default"+A+"Height"],i.initialAspectRatio=i.height>=i.width?i.width/i.height:i.height/i.width,i.setPlayerSize(i.width,i.height),s.pluginWidth=i.width,s.pluginHeight=i.height}if(new u.default(i.media,s,i.mediaFiles),void 0!==i.container&&i.options.features.length&&i.controlsAreVisible&&!i.options.hideVideoControlsOnLoad){var L=(0,p.createEvent)("controlsshown",i.container);i.container.dispatchEvent(L)}return i}}return r(e,[{key:"showControls",value:function(e){var t=this;if(e=void 0===e||e,!t.controlsAreVisible&&t.isVideo){if(e)!function(){v.fadeIn(t.controls,200,function(){v.removeClass(t.controls,t.options.classPrefix+"offscreen");var e=(0,p.createEvent)("controlsshown",t.container);t.container.dispatchEvent(e)});for(var e=t.container.querySelectorAll("."+t.options.classPrefix+"control"),n=0,i=e.length;n<i;n++)!function(n,i){v.fadeIn(e[n],200,function(){v.removeClass(e[n],t.options.classPrefix+"offscreen")})}(n)}();else{v.removeClass(t.controls,t.options.classPrefix+"offscreen"),t.controls.style.display="",t.controls.style.opacity=1;for(var n=t.container.querySelectorAll("."+t.options.classPrefix+"control"),i=0,o=n.length;i<o;i++)v.removeClass(n[i],t.options.classPrefix+"offscreen"),n[i].style.display="";var a=(0,p.createEvent)("controlsshown",t.container);t.container.dispatchEvent(a)}t.controlsAreVisible=!0,t.setControlsSize()}}},{key:"hideControls",value:function(e,t){var n=this;if(e=void 0===e||e,!0===t||!(!n.controlsAreVisible||n.options.alwaysShowControls||n.keyboardAction||n.media.paused&&4===n.media.readyState&&(!n.options.hideVideoControlsOnLoad&&n.media.currentTime<=0||!n.options.hideVideoControlsOnPause&&n.media.currentTime>0)||n.isVideo&&!n.options.hideVideoControlsOnLoad&&!n.media.readyState||n.media.ended)){if(e)!function(){v.fadeOut(n.controls,200,function(){v.addClass(n.controls,n.options.classPrefix+"offscreen"),n.controls.style.display="";var e=(0,p.createEvent)("controlshidden",n.container);n.container.dispatchEvent(e)});for(var e=n.container.querySelectorAll("."+n.options.classPrefix+"control"),t=0,i=e.length;t<i;t++)!function(t,i){v.fadeOut(e[t],200,function(){v.addClass(e[t],n.options.classPrefix+"offscreen"),e[t].style.display=""})}(t)}();else{v.addClass(n.controls,n.options.classPrefix+"offscreen"),n.controls.style.display="",n.controls.style.opacity=0;for(var i=n.container.querySelectorAll("."+n.options.classPrefix+"control"),o=0,a=i.length;o<a;o++)v.addClass(i[o],n.options.classPrefix+"offscreen"),i[o].style.display="";var r=(0,p.createEvent)("controlshidden",n.container);n.container.dispatchEvent(r)}n.controlsAreVisible=!1}}},{key:"startControlsTimer",value:function(e){var t=this;e=void 0!==e?e:t.options.controlsTimeoutDefault,t.killControlsTimer("start"),t.controlsTimer=setTimeout(function(){t.hideControls(),t.killControlsTimer("hide")},e)}},{key:"killControlsTimer",value:function(){var e=this;null!==e.controlsTimer&&(clearTimeout(e.controlsTimer),delete e.controlsTimer,e.controlsTimer=null)}},{key:"disableControls",value:function(){var e=this;e.killControlsTimer(),e.controlsEnabled=!0,e.hideControls(!1,!0)}},{key:"enableControls",value:function(){var e=this;e.controlsEnabled=!0,e.showControls(!1)}},{key:"_meReady",value:function(e,t){var n=this,i=t.getAttribute("autoplay"),o=!(void 0===i||null===i||"false"===i),a=null!==e.rendererName&&/(native|html5)/i.test(n.media.rendererName);if(n.controls&&n.enableControls(),n.container&&n.container.querySelector("."+n.options.classPrefix+"overlay-play")&&(n.container.querySelector("."+n.options.classPrefix+"overlay-play").style.display=""),!n.created){if(n.created=!0,n.media=e,n.domNode=t,!(f.IS_ANDROID&&n.options.AndroidUseNativeControls||f.IS_IPAD&&n.options.iPadUseNativeControls||f.IS_IPHONE&&n.options.iPhoneUseNativeControls)){if(!n.isVideo&&!n.options.features.length)return o&&a&&n.play(),void(n.options.success&&("string"==typeof n.options.success?s.default[n.options.success](n.media,n.domNode,n):n.options.success(n.media,n.domNode,n)));n.buildposter(n,n.controls,n.layers,n.media),n.buildkeyboard(n,n.controls,n.layers,n.media),n.buildoverlays(n,n.controls,n.layers,n.media),n.findTracks(),n.featurePosition={};for(var r=0,u=n.options.features.length;r<u;r++){var c=n.options.features[r];if(n["build"+c])try{n["build"+c](n,n.controls,n.layers,n.media)}catch(e){console.error("error building "+c,e)}}var h=(0,p.createEvent)("controlsready",n.container);n.container.dispatchEvent(h),n.setPlayerSize(n.width,n.height),n.setControlsSize(),n.isVideo&&(n.clickToPlayPauseCallback=function(){if(n.options.clickToPlayPause){var e=n.container.querySelector("."+n.options.classPrefix+"overlay-button"),t=e.getAttribute("aria-pressed");n.media.paused&&t?n.pause():n.media.paused?n.play():n.pause(),e.setAttribute("aria-pressed",!t)}},n.createIframeLayer(),n.media.addEventListener("click",n.clickToPlayPauseCallback),!f.IS_ANDROID&&!f.IS_IOS||n.options.alwaysShowControls?(n.container.addEventListener("mouseenter",function(){n.controlsEnabled&&(n.options.alwaysShowControls||(n.killControlsTimer("enter"),n.showControls(),n.startControlsTimer(n.options.controlsTimeoutMouseEnter)))}),n.container.addEventListener("mousemove",function(){n.controlsEnabled&&(n.controlsAreVisible||n.showControls(),n.options.alwaysShowControls||n.startControlsTimer(n.options.controlsTimeoutMouseEnter))}),n.container.addEventListener("mouseleave",function(){n.controlsEnabled&&(n.media.paused||n.options.alwaysShowControls||n.startControlsTimer(n.options.controlsTimeoutMouseLeave))})):n.node.addEventListener("touchstart",function(){n.controlsAreVisible?n.hideControls(!1):n.controlsEnabled&&n.showControls(!1)}),n.options.hideVideoControlsOnLoad&&n.hideControls(!1),o&&!n.options.alwaysShowControls&&n.hideControls(),n.options.enableAutosize&&n.media.addEventListener("loadedmetadata",function(e){var t=void 0!==e?e.detail.target||e.target:n.media;n.options.videoHeight<=0&&!n.domNode.getAttribute("height")&&null!==t&&!isNaN(t.videoHeight)&&(n.setPlayerSize(t.videoWidth,t.videoHeight),n.setControlsSize(),n.media.setSize(t.videoWidth,t.videoHeight))})),n.media.addEventListener("play",function(){n.hasFocus=!0;for(var e in d.default.players)if(d.default.players.hasOwnProperty(e)){var t=d.default.players[e];t.id===n.id||!n.options.pauseOtherPlayers||t.paused||t.ended||(t.pause(),t.hasFocus=!1)}}),n.media.addEventListener("ended",function(){if(n.options.autoRewind)try{n.media.setCurrentTime(0),setTimeout(function(){var e=n.container.querySelector("."+n.options.classPrefix+"overlay-loading");e&&e.parentNode&&(e.parentNode.style.display="none")},20)}catch(e){}"function"==typeof n.media.stop?n.media.stop():n.media.pause(),n.setProgressRail&&n.setProgressRail(),n.setCurrentRail&&n.setCurrentRail(),n.options.loop?n.play():!n.options.alwaysShowControls&&n.controlsEnabled&&n.showControls()}),n.media.addEventListener("loadedmetadata",function(){(0,m.calculateTimeFormat)(n.duration,n.options,n.options.framesPerSecond||25),n.updateDuration&&n.updateDuration(),n.updateCurrent&&n.updateCurrent(),n.isFullScreen||(n.setPlayerSize(n.width,n.height),n.setControlsSize())});var y=null;n.media.addEventListener("timeupdate",function(){isNaN(n.media.getDuration())||y===n.media.getDuration()||(y=n.media.getDuration(),(0,m.calculateTimeFormat)(y,n.options,n.options.framesPerSecond||25),n.updateDuration&&n.updateDuration(),n.updateCurrent&&n.updateCurrent(),n.setControlsSize())}),n.container.addEventListener("click",function(e){v.addClass(e.currentTarget,n.options.classPrefix+"container-keyboard-inactive")}),n.container.addEventListener("focusin",function(e){v.removeClass(e.currentTarget,n.options.classPrefix+"container-keyboard-inactive"),n.controlsEnabled&&!n.options.alwaysShowControls&&n.showControls(!1)}),n.container.addEventListener("focusout",function(e){setTimeout(function(){e.relatedTarget&&n.keyboardAction&&!e.relatedTarget.closest("."+n.options.classPrefix+"container")&&(n.keyboardAction=!1,n.isVideo&&!n.options.alwaysShowControls&&n.hideControls(!0))},0)}),setTimeout(function(){n.setPlayerSize(n.width,n.height),n.setControlsSize()},0),n.globalBind("resize",function(){n.isFullScreen||f.HAS_TRUE_NATIVE_FULLSCREEN&&l.default.webkitIsFullScreen||n.setPlayerSize(n.width,n.height),n.setControlsSize()})}o&&a&&n.play(),n.options.success&&("string"==typeof n.options.success?s.default[n.options.success](n.media,n.domNode,n):n.options.success(n.media,n.domNode,n))}}},{key:"_handleError",value:function(e){var t=this;t.controls&&t.disableControls();var n=t.layers.querySelector("."+t.options.classPrefix+"overlay-play");n&&(n.style.display="none"),t.options.error&&t.options.error(e)}},{key:"setPlayerSize",value:function(e,t){var n=this;if(!n.options.setDimensions)return!1;switch(void 0!==e&&(n.width=e),void 0!==t&&(n.height=t),n.options.stretching){case"fill":n.isVideo?n.setFillMode():n.setDimensions(n.width,n.height);break;case"responsive":n.setResponsiveMode();break;case"none":n.setDimensions(n.width,n.height);break;default:!0===n.hasFluidMode()?n.setResponsiveMode():n.setDimensions(n.width,n.height)}}},{key:"hasFluidMode",value:function(){var e=this;return-1!==e.height.toString().indexOf("%")||e.node&&e.node.style.maxWidth&&"none"!==e.node.style.maxWidth&&e.node.style.maxWidth!==e.width||e.node&&e.node.currentStyle&&"100%"===e.node.currentStyle.maxWidth}},{key:"setResponsiveMode",value:function(){var e=this,t=function(){for(var t=void 0,n=e.container;n;){try{if(f.IS_FIREFOX&&"html"===n.tagName.toLowerCase()&&s.default.self!==s.default.top&&null!==s.default.frameElement)return s.default.frameElement;t=n.parentElement}catch(e){t=n.parentElement}if(t&&v.visible(t))return t;n=t}return null}(),n=t?getComputedStyle(t,null):getComputedStyle(l.default.body,null),i=e.isVideo?e.media.videoWidth&&e.media.videoWidth>0?e.media.videoWidth:e.node.getAttribute("width")?e.node.getAttribute("width"):e.options.defaultVideoWidth:e.options.defaultAudioWidth,o=e.isVideo?e.media.videoHeight&&e.media.videoHeight>0?e.media.videoHeight:e.node.getAttribute("height")?e.node.getAttribute("height"):e.options.defaultVideoHeight:e.options.defaultAudioHeight,a=function(){var t=1;return e.isVideo?(t=e.media.videoWidth&&e.media.videoWidth>0&&e.media.videoHeight&&e.media.videoHeight>0?e.height>=e.width?e.media.videoWidth/e.media.videoHeight:e.media.videoHeight/e.media.videoWidth:e.initialAspectRatio,(isNaN(t)||t<.01||t>100)&&(t=1),t):t}(),r=parseFloat(n.height),d=void 0,u=parseFloat(n.width);if(d=e.isVideo?"100%"===e.height?parseFloat(u*o/i,10):e.height>=e.width?parseFloat(u/a,10):parseFloat(u*a,10):o,isNaN(d)&&(d=r),e.container.parentNode.length>0&&"body"===e.container.parentNode.tagName.toLowerCase()&&(u=s.default.innerWidth||l.default.documentElement.clientWidth||l.default.body.clientWidth,d=s.default.innerHeight||l.default.documentElement.clientHeight||l.default.body.clientHeight),d&&u){e.container.style.width=u+"px",e.container.style.height=d+"px",e.node.style.width="100%",e.node.style.height="100%",e.isVideo&&e.media.setSize&&e.media.setSize(u,d);for(var c=e.layers.childNodes,p=0,m=c.length;p<m;p++)c[p].style.width="100%",c[p].style.height="100%"}}},{key:"setFillMode",value:function(){var e=this,t=void 0,n=!1;try{s.default.self!==s.default.top?(n=!0,t=s.default.frameElement):t=e.outerContainer}catch(n){t=e.outerContainer}var i=getComputedStyle(t);"none"!==e.node.style.height&&e.node.style.height!==e.height&&(e.node.style.height="auto"),"none"!==e.node.style.maxWidth&&e.node.style.maxWidth!==e.width&&(e.node.style.maxWidth="none"),"none"!==e.node.style.maxHeight&&e.node.style.maxHeight!==e.height&&(e.node.style.maxHeight="none"),e.node.currentStyle&&("100%"===e.node.currentStyle.height&&(e.node.currentStyle.height="auto"),"100%"===e.node.currentStyle.maxWidth&&(e.node.currentStyle.maxWidth="none"),"100%"===e.node.currentStyle.maxHeight&&(e.node.currentStyle.maxHeight="none")),n||parseFloat(i.width)||(t.style.width=e.media.offsetWidth+"px"),n||parseFloat(i.height)||(t.style.height=e.media.offsetHeight+"px"),i=getComputedStyle(t);var o=parseFloat(i.width),a=parseFloat(i.height);e.setDimensions("100%","100%");var r=e.container.querySelector(e.options.classPrefix+"poster img");r&&(r.style.display="");for(var l=e.container.querySelectorAll("object, embed, iframe, video"),d=e.height,u=e.width,c=o,f=d*o/u,p=u*a/d,m=a,h=p>o==!1,v=h?Math.floor(c):Math.floor(p),y=h?Math.floor(f):Math.floor(m),g=h?o+"px":v+"px",b=h?y+"px":a+"px",E=0,S=l.length;E<S;E++)l[E].style.height=b,l[E].style.width=g,e.media.setSize&&e.media.setSize(g,b),l[E].style.marginLeft=Math.floor((o-v)/2)+"px",l[E].style.marginTop=0}},{key:"setDimensions",value:function(e,t){var n=this;e=(0,p.isString)(e)&&e.indexOf("%")>-1?e:parseFloat(e)+"px",t=(0,p.isString)(t)&&t.indexOf("%")>-1?t:parseFloat(t)+"px",n.container.style.width=e,n.container.style.height=t;for(var i=n.layers.childNodes,o=0,a=i.length;o<a;o++)i[o].style.width=e,i[o].style.height=t}},{key:"setControlsSize",value:function(){var e=this;if(v.visible(e.container))if(e.rail&&v.visible(e.rail)){for(var t=e.total?getComputedStyle(e.total,null):null,n=t?parseFloat(t.marginLeft)+parseFloat(t.marginRight):0,i=getComputedStyle(e.rail),o=parseFloat(i.marginLeft)+parseFloat(i.marginRight),a=0,r=v.siblings(e.rail,function(t){return t!==e.rail}),s=r.length,l=0;l<s;l++)a+=r[l].offsetWidth;a+=n+(0===n?2*o:o)+1,e.container.style.minWidth=a+"px";var d=parseFloat(e.controls.offsetWidth);e.rail.style.width=(a>d?0:d-a)+"px";var u=(0,p.createEvent)("controlsresize",e.container);e.container.dispatchEvent(u)}else{for(var c=e.controls.childNodes,f=0,m=0,h=c.length;m<h;m++)f+=c[m].offsetWidth;e.container.style.minWidth=f+"px"}}},{key:"addControlElement",value:function(e,t){var n=this;if(void 0!==n.featurePosition[t]){var i=n.controls.childNodes[n.featurePosition[t]-1];i.parentNode.insertBefore(e,i.nextSibling)}else{n.controls.appendChild(e);for(var o=n.controls.childNodes,a=0,r=o.length;a<r;a++)if(e==o[a]){n.featurePosition[t]=a;break}}}},{key:"createIframeLayer",value:function(){var e=this;if(e.isVideo&&null!==e.media.rendererName&&e.media.rendererName.indexOf("iframe")>-1&&!l.default.getElementById(e.media.id+"-iframe-overlay")){var t=l.default.createElement("div"),n=l.default.getElementById(e.media.id+"_"+e.media.rendererName);t.id=e.media.id+"-iframe-overlay",t.className=e.options.classPrefix+"iframe-overlay",t.addEventListener("click",function(t){e.options.clickToPlayPause&&(e.media.paused?e.media.play():e.media.pause(),t.preventDefault(),t.stopPropagation())}),n.parentNode.insertBefore(t,n)}}},{key:"resetSize",value:function(){var e=this;setTimeout(function(){e.setPlayerSize(e.width,e.height),e.setControlsSize()},50)}},{key:"setPoster",value:function(e){var t=this,n=t.container.querySelector("."+t.options.classPrefix+"poster"),i=n.querySelector("img");i||((i=l.default.createElement("img")).className=t.options.classPrefix+"poster-img",i.width="100%",i.height="100%",n.appendChild(i)),i.setAttribute("src",e),n.style.backgroundImage='url("'+e+'")'}},{key:"changeSkin",value:function(e){var t=this;t.container.className=t.options.classPrefix+"container "+e,t.setPlayerSize(t.width,t.height),t.setControlsSize()}},{key:"globalBind",value:function(e,t){var n=this,i=n.node?n.node.ownerDocument:l.default;if((e=(0,p.splitEvents)(e,n.id)).d)for(var o=e.d.split(" "),a=0,r=o.length;a<r;a++)o[a].split(".").reduce(function(e,n){return i.addEventListener(n,t,!1),n},"");if(e.w)for(var d=e.w.split(" "),u=0,c=d.length;u<c;u++)d[u].split(".").reduce(function(e,n){return s.default.addEventListener(n,t,!1),n},"")}},{key:"globalUnbind",value:function(e,t){var n=this,i=n.node?n.node.ownerDocument:l.default;if((e=(0,p.splitEvents)(e,n.id)).d)for(var o=e.d.split(" "),a=0,r=o.length;a<r;a++)o[a].split(".").reduce(function(e,n){return i.removeEventListener(n,t,!1),n},"");if(e.w)for(var d=e.d.split(" "),u=0,c=d.length;u<c;u++)d[u].split(".").reduce(function(e,n){return s.default.removeEventListener(n,t,!1),n},"")}},{key:"buildposter",value:function(e,t,n,i){var o=this,a=l.default.createElement("div");a.className=o.options.classPrefix+"poster "+o.options.classPrefix+"layer",n.appendChild(a);var r=e.media.getAttribute("poster");""!==e.options.poster&&(r=e.options.poster),r?o.setPoster(r):a.style.display="none",i.addEventListener("play",function(){a.style.display="none"}),i.addEventListener("playing",function(){a.style.display="none"}),e.options.showPosterWhenEnded&&e.options.autoRewind&&i.addEventListener("ended",function(){a.style.display=""}),i.addEventListener("error",function(){a.style.display="none"}),e.options.showPosterWhenPaused&&i.addEventListener("pause",function(){i.ended||(a.style.display="")})}},{key:"buildoverlays",value:function(e,t,n,i){if(e.isVideo){var o=this,a=l.default.createElement("div"),r=l.default.createElement("div"),s=l.default.createElement("div"),d=t.querySelector("."+o.options.classPrefix+"time-buffering");a.style.display="none",a.className=o.options.classPrefix+"overlay "+o.options.classPrefix+"layer",a.innerHTML='<div class="'+o.options.classPrefix+'overlay-loading"><span class="'+o.options.classPrefix+'overlay-loading-bg-img"></span></div>',n.appendChild(a),r.style.display="none",r.className=o.options.classPrefix+"overlay "+o.options.classPrefix+"layer",r.innerHTML='<div class="'+o.options.classPrefix+'overlay-error"></div>',n.appendChild(r),s.className=o.options.classPrefix+"overlay "+o.options.classPrefix+"layer "+o.options.classPrefix+"overlay-play",s.innerHTML='<div class="'+o.options.classPrefix+'overlay-button" role="button" tabindex="0"aria-label="'+c.default.t("mejs.play")+'" aria-pressed="false"></div>',s.addEventListener("click",function(){if(o.options.clickToPlayPause){var e=o.container.querySelector("."+o.options.classPrefix+"overlay-button"),t=e.getAttribute("aria-pressed");i.paused?i.play():i.pause(),e.setAttribute("aria-pressed",!!t)}}),s.addEventListener("keydown",function(e){var t=e.keyCode||e.which||0;if(13===t||f.IS_FIREFOX&&32===t){var n=(0,p.createEvent)("click",s);return s.dispatchEvent(n),!1}}),n.appendChild(s),null!==o.media.rendererName&&(/(youtube|facebook)/i.test(o.media.rendererName)&&!e.media.originalNode.getAttribute("poster")&&!e.options.poster||f.IS_STOCK_ANDROID)&&(s.style.display="none"),i.addEventListener("play",function(){s.style.display="none",a.style.display="none",d&&(d.style.display="none"),r.style.display="none"}),i.addEventListener("playing",function(){s.style.display="none",a.style.display="none",d&&(d.style.display="none"),r.style.display="none"}),i.addEventListener("seeking",function(){s.style.display="none",a.style.display="",d&&(d.style.display="")}),i.addEventListener("seeked",function(){s.style.display=i.paused&&!f.IS_STOCK_ANDROID?"":"none",a.style.display="none",d&&(d.style.display="")}),i.addEventListener("pause",function(){a.style.display="none",f.IS_STOCK_ANDROID||(s.style.display=""),d&&(d.style.display="none")}),i.addEventListener("waiting",function(){a.style.display="",d&&(d.style.display="")}),i.addEventListener("loadeddata",function(){a.style.display="",d&&(d.style.display=""),f.IS_ANDROID&&(i.canplayTimeout=setTimeout(function(){if(l.default.createEvent){var e=l.default.createEvent("HTMLEvents");return e.initEvent("canplay",!0,!0),i.dispatchEvent(e)}},300))}),i.addEventListener("canplay",function(){a.style.display="none",d&&(d.style.display="none"),clearTimeout(i.canplayTimeout)}),i.addEventListener("error",function(e){o._handleError(e),a.style.display="none",s.style.display="none",d&&(d.style.display="none"),e.message&&(r.style.display="block",r.querySelector("."+o.options.classPrefix+"overlay-error").innerHTML=e.message)}),i.addEventListener("keydown",function(t){o.onkeydown(e,i,t)})}}},{key:"buildkeyboard",value:function(e,t,n,i){var o=this;o.container.addEventListener("keydown",function(){o.keyboardAction=!0}),o.globalBind("keydown",function(t){var n=l.default.activeElement.closest("."+o.options.classPrefix+"container"),a=o.media.closest("."+o.options.classPrefix+"container");return o.hasFocus=!(!n||!a||n.id!==a.id),o.onkeydown(e,i,t)}),o.globalBind("click",function(e){o.hasFocus=!!e.target.closest("."+o.options.classPrefix+"container")})}},{key:"onkeydown",value:function(e,t,n){if(e.hasFocus&&e.options.enableKeyboard)for(var i=0,o=e.options.keyActions.length;i<o;i++)for(var a=e.options.keyActions[i],r=0,s=a.keys.length;r<s;r++)n.keyCode===a.keys[r]&&(a.action(e,t,n.keyCode,n),n.preventDefault(),n.stopPropagation());return!0}},{key:"play",value:function(){var e=this;e.media.getCurrentTime()<=0&&e.load(),e.media.play()}},{key:"pause",value:function(){try{this.media.pause()}catch(e){}}},{key:"load",value:function(){var e=this;e.isLoaded||e.media.load(),e.isLoaded=!0}},{key:"setMuted",value:function(e){this.media.setMuted(e)}},{key:"setCurrentTime",value:function(e){this.media.setCurrentTime(e)}},{key:"getCurrentTime",value:function(){return this.media.currentTime}},{key:"getDuration",value:function(){return this.media.duration}},{key:"setVolume",value:function(e){this.media.setVolume(e)}},{key:"getVolume",value:function(){return this.media.volume}},{key:"setSrc",value:function(e){var t=this,n=l.default.getElementById(t.media.id+"-iframe-overlay");n&&n.remove(),t.media.setSrc(e),t.createIframeLayer()}},{key:"remove",value:function(){var e=this,t=e.media.rendererName;e.media.paused||e.media.pause();var n=e.media.getSrc();e.media.setSrc("");for(var i in e.options.features){var o=e.options.features[i];if(e["clean"+o])try{e["clean"+o](e)}catch(e){console.error("error cleaning "+o,e)}}var r=e.node.getAttribute("width"),s=e.node.getAttribute("height");r?-1===r.indexOf("%")&&(r+="px"):r="auto",s?-1===s.indexOf("%")&&(s+="px"):s="auto",e.node.style.width=r,e.node.style.height=s,e.isDynamic?e.container.parentNode.insertBefore(e.node,e.container):function(){e.node.setAttribute("controls",!0),e.node.setAttribute("id",e.node.getAttribute("id").replace("_"+t,"").replace("_from_mejs","")),delete e.node.autoplay,""!==e.media.canPlayType((0,h.getTypeFromFile)(n))&&e.node.setAttribute("src",n),~t.indexOf("iframe")&&l.default.getElementById(e.media.id+"-iframe-overlay").remove();var i=e.node.cloneNode();if(i.style.display="",e.container.parentNode.insertBefore(i,e.container),e.node.remove(),e.mediaFiles)for(var o=0,a=e.mediaFiles.length;o<a;o++){var r=l.default.createElement("source");r.setAttribute("src",e.mediaFiles[o].src),r.setAttribute("type",e.mediaFiles[o].type),i.appendChild(r)}if(e.trackFiles)for(var s=0,d=e.trackFiles.length;s<d;s++)!function(t,n){var o=e.trackFiles[t],a=l.default.createElement("track");a.kind=o.kind,a.label=o.label,a.srclang=o.srclang,a.src=o.src,i.appendChild(a),a.addEventListener("load",function(){this.mode="showing",i.textTracks[t].mode="showing"})}(s);delete e.node,delete e.mediaFiles,delete e.trackFiles}(),"function"==typeof e.media.destroy&&e.media.destroy(),delete d.default.players[e.id],"object"===a(e.container)&&(e.container.parentNode.querySelector("."+e.options.classPrefix+"offscreen").remove(),e.container.remove()),e.globalUnbind(),delete e.media.player}}]),e}();s.default.MediaElementPlayer=g,n.default=g,function(e){void 0!==e&&(e.fn.mediaelementplayer=function(t){return!1===t?this.each(function(){var t=e(this).data("mediaelementplayer");t&&t.remove(),e(this).removeData("mediaelementplayer")}):this.each(function(){e(this).data("mediaelementplayer",new g(this,t))}),this},e(l.default).ready(function(){e("."+y.classPrefix+"player").mediaelementplayer()}))}(d.default.$)},{2:2,23:23,24:24,25:25,26:26,28:28,3:3,4:4,5:5,6:6}],17:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=i(e(3)),r=i(e(6)),s=e(7),l=e(25),d=e(26),u=e(23),c=e(24),f={promise:null,load:function(e){"undefined"!=typeof dashjs?f._createPlayer(e):(e.options.path="string"==typeof e.options.path?e.options.path:"https://cdn.dashjs.org/latest/dash.all.min.js",f.promise=f.promise||(0,c.loadScript)(e.options.path),f.promise.then(function(){f._createPlayer(e)}))},_createPlayer:function(e){var t=dashjs.MediaPlayer().create();a.default["__ready__"+e.id](t)}},p={name:"native_dash",options:{prefix:"native_dash",dash:{path:"https://cdn.dashjs.org/latest/dash.all.min.js",debug:!1,drm:{}}},canPlayType:function(e){return u.HAS_MSE&&["application/dash+xml"].indexOf(e.toLowerCase())>-1},create:function(e,t,n){var i=e.originalNode,d=e.id+"_"+t.prefix,u=i.getAttribute("preload"),c=i.autoplay,p=null,m=null;p=i.cloneNode(!0),t=Object.assign(t,e.options);for(var h=r.default.html5media.properties,v=0,y=h.length;v<y;v++)!function(e){var t=""+e.substring(0,1).toUpperCase()+e.substring(1);p["get"+t]=function(){return null!==m?p[e]:null},p["set"+t]=function(t){-1===r.default.html5media.readOnlyProperties.indexOf(e)&&("src"===e?"string"==typeof t?(p[e]=t,null!==m&&(m.attachSource(t),c&&p.play())):t&&"object"===(void 0===t?"undefined":o(t))&&t.src&&(p[e]=t.src,null!==m&&(t&&"object"===(void 0===t?"undefined":o(t))&&t.drm&&m.setProtectionData(t.drm),m.attachSource(t.src),c&&p.play())):p[e]=t)}}(h[v]);if(a.default["__ready__"+d]=function(n){e.dashPlayer=m=n,m.getDebug().setLogToBrowserConsole(t.dash.debug),m.setScheduleWhilePaused(u&&"auto"===u||c);for(var i=r.default.html5media.events.concat(["click","mouseover","mouseout"]),o=dashjs.MediaPlayer.events,a=0,s=i.length;a<s;a++)!function(n){"loadedmetadata"===n&&(m.initialize(p,null,u&&"auto"===u||c),m.setFastSwitchEnabled(!0),r.default.Utils.isObjectEmpty(t.dash.drm)||m.setProtectionData(t.dash.drm),m.attachSource(p.src)),p.addEventListener(n,function(t){var n=(0,l.createEvent)(t.type,e);e.dispatchEvent(n)})}(i[a]);for(var d in o)o.hasOwnProperty(d)&&m.on(o[d],function(t){var n=(0,l.createEvent)(t.type,p);n.data=t,e.dispatchEvent(n),"error"===t.type.toLowerCase()&&console.error(t)})},n&&n.length>0)for(var g=0,b=n.length;g<b;g++)if(s.renderer.renderers[t.prefix].canPlayType(n[g].type)){p.setAttribute("src",n[g].src),void 0!==n[g].drm&&(t.dash.drm=n[g].drm);break}p.setAttribute("id",d),i.parentNode.insertBefore(p,i),i.autoplay=!1,i.style.display="none",f.load({options:t.dash,id:d}),p.setSize=function(e,t){return p.style.width=e+"px",p.style.height=t+"px",p},p.hide=function(){return p.pause(),p.style.display="none",p},p.show=function(){return p.style.display="",p};var E=(0,l.createEvent)("rendererready",p);return e.dispatchEvent(E),p}};d.typeChecks.push(function(e){return~e.toLowerCase().indexOf(".mpd")?"application/dash+xml":null}),s.renderer.add(p)},{23:23,24:24,25:25,26:26,3:3,6:6,7:7}],18:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(n,"__esModule",{value:!0}),n.PluginDetector=void 0;var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=i(e(3)),r=i(e(2)),s=i(e(6)),l=i(e(4)),d=e(7),u=e(25),c=e(23),f=e(26),p=n.PluginDetector={plugins:[],hasPluginVersion:function(e,t){var n=p.plugins[e];return t[1]=t[1]||0,t[2]=t[2]||0,n[0]>t[0]||n[0]===t[0]&&n[1]>t[1]||n[0]===t[0]&&n[1]===t[1]&&n[2]>=t[2]},addPlugin:function(e,t,n,i,o){p.plugins[e]=p.detectPlugin(t,n,i,o)},detectPlugin:function(e,t,n,i){var r=[0,0,0],s=void 0,l=void 0;if(null!==c.NAV.plugins&&void 0!==c.NAV.plugins&&"object"===o(c.NAV.plugins[e])){if((s=c.NAV.plugins[e].description)&&(void 0===c.NAV.mimeTypes||!c.NAV.mimeTypes[t]||c.NAV.mimeTypes[t].enabledPlugin))for(var d=0,u=(r=s.replace(e,"").replace(/^\s+/,"").replace(/\sr/gi,".").split(".")).length;d<u;d++)r[d]=parseInt(r[d].match(/\d+/),10)}else if(void 0!==a.default.ActiveXObject)try{(l=new ActiveXObject(n))&&(r=i(l))}catch(e){}return r}};p.addPlugin("flash","Shockwave Flash","application/x-shockwave-flash","ShockwaveFlash.ShockwaveFlash",function(e){var t=[],n=e.GetVariable("$version");return n&&(n=n.split(" ")[1].split(","),t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]),t});var m={create:function(e,t,n){var i={};i.options=t,i.id=e.id+"_"+i.options.prefix,i.mediaElement=e,i.flashState={},i.flashApi=null,i.flashApiStack=[];for(var o=s.default.html5media.properties,p=0,m=o.length;p<m;p++)!function(e){i.flashState[e]=null;var t=""+e.substring(0,1).toUpperCase()+e.substring(1);i["get"+t]=function(){if(null!==i.flashApi){if("function"==typeof i.flashApi["get_"+e]){var t=i.flashApi["get_"+e]();return"buffered"===e?{start:function(){return 0},end:function(){return t},length:1}:t}return null}return null},i["set"+t]=function(t){if("src"===e&&(t=(0,f.absolutizeUrl)(t)),null!==i.flashApi&&void 0!==i.flashApi["set_"+e])try{i.flashApi["set_"+e](t)}catch(e){}else i.flashApiStack.push({type:"set",propName:e,value:t})}}(o[p]);var h=s.default.html5media.methods;h.push("stop");for(var v=0,y=h.length;v<y;v++)!function(e){i[e]=function(){if(null!==i.flashApi){if(i.flashApi["fire_"+e])try{i.flashApi["fire_"+e]()}catch(e){}}else i.flashApiStack.push({type:"call",methodName:e})}}(h[v]);for(var g=["rendererready"],b=0,E=g.length;b<E;b++){var S=(0,u.createEvent)(g[b],i);e.dispatchEvent(S)}a.default["__ready__"+i.id]=function(){if(i.flashReady=!0,i.flashApi=r.default.getElementById("__"+i.id),i.flashApiStack.length)for(var e=0,t=i.flashApiStack.length;e<t;e++){var n=i.flashApiStack[e];if("set"===n.type){var o=n.propName,a=""+o.substring(0,1).toUpperCase()+o.substring(1);i["set"+a](n.value)}else"call"===n.type&&i[n.methodName]()}},a.default["__event__"+i.id]=function(e,t){var n=(0,u.createEvent)(e,i);n.message=t||"",i.mediaElement.dispatchEvent(n)},i.flashWrapper=r.default.createElement("div"),-1===["always","sameDomain"].indexOf(i.options.shimScriptAccess)&&(i.options.shimScriptAccess="sameDomain");var x=e.originalNode.autoplay,w=["uid="+i.id,"autoplay="+x,"allowScriptAccess="+i.options.shimScriptAccess],P=null!==e.originalNode&&"video"===e.originalNode.tagName.toLowerCase(),T=P?e.originalNode.height:1,C=P?e.originalNode.width:1;e.originalNode.getAttribute("src")&&w.push("src="+e.originalNode.getAttribute("src")),!0===i.options.enablePseudoStreaming&&(w.push("pseudostreamstart="+i.options.pseudoStreamingStartQueryParam),w.push("pseudostreamtype="+i.options.pseudoStreamingType)),e.appendChild(i.flashWrapper),null!==e.originalNode&&(e.originalNode.style.display="none");var k=[];if(c.IS_IE){var _=r.default.createElement("div");i.flashWrapper.appendChild(_),k=['classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"','codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"','id="__'+i.id+'"','width="'+C+'"','height="'+T+'"'],P||k.push('style="clip: rect(0 0 0 0); position: absolute;"'),_.outerHTML="<object "+k.join(" ")+'><param name="movie" value="'+i.options.pluginPath+i.options.filename+"?x="+new Date+'" /><param name="flashvars" value="'+w.join("&")+'" /><param name="quality" value="high" /><param name="bgcolor" value="#000000" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="'+i.options.shimScriptAccess+'" /><param name="allowFullScreen" value="true" /><div>'+l.default.t("mejs.install-flash")+"</div></object>"}else k=['id="__'+i.id+'"','name="__'+i.id+'"','play="true"','loop="false"','quality="high"','bgcolor="#000000"','wmode="transparent"','allowScriptAccess="'+i.options.shimScriptAccess+'"','allowFullScreen="true"','type="application/x-shockwave-flash"','pluginspage="//www.macromedia.com/go/getflashplayer"','src="'+i.options.pluginPath+i.options.filename+'"','flashvars="'+w.join("&")+'"','width="'+C+'"','height="'+T+'"'],P||k.push('style="clip: rect(0 0 0 0); position: absolute;"'),i.flashWrapper.innerHTML="<embed "+k.join(" ")+">";if(i.flashNode=i.flashWrapper.lastChild,i.hide=function(){P&&(i.flashNode.style.display="none")},i.show=function(){P&&(i.flashNode.style.display="")},i.setSize=function(e,t){i.flashNode.style.width=e+"px",i.flashNode.style.height=t+"px",null!==i.flashApi&&"function"==typeof i.flashApi.fire_setSize&&i.flashApi.fire_setSize(e,t)},i.destroy=function(){i.flashNode.remove()},n&&n.length>0)for(var N=0,A=n.length;N<A;N++)if(d.renderer.renderers[t.prefix].canPlayType(n[N].type)){i.setSrc(n[N].src);break}return i}};if(p.hasPluginVersion("flash",[10,0,0])){f.typeChecks.push(function(e){return(e=e.toLowerCase()).startsWith("rtmp")?~e.indexOf(".mp3")?"audio/rtmp":"video/rtmp":/\.og(a|g)/i.test(e)?"audio/ogg":~e.indexOf(".m3u8")?"application/x-mpegURL":~e.indexOf(".mpd")?"application/dash+xml":~e.indexOf(".flv")?"video/flv":null});var h={name:"flash_video",options:{prefix:"flash_video",filename:"mediaelement-flash-video.swf",enablePseudoStreaming:!1,pseudoStreamingStartQueryParam:"start",pseudoStreamingType:"byte"},canPlayType:function(e){return~["video/mp4","video/rtmp","audio/rtmp","rtmp/mp4","audio/mp4","video/flv","video/x-flv"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(h);var v={name:"flash_hls",options:{prefix:"flash_hls",filename:"mediaelement-flash-video-hls.swf"},canPlayType:function(e){return~["application/x-mpegurl","vnd.apple.mpegurl","audio/mpegurl","audio/hls","video/hls"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(v);var y={name:"flash_dash",options:{prefix:"flash_dash",filename:"mediaelement-flash-video-mdash.swf"},canPlayType:function(e){return~["application/dash+xml"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(y);var g={name:"flash_audio",options:{prefix:"flash_audio",filename:"mediaelement-flash-audio.swf"},canPlayType:function(e){return~["audio/mp3"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(g);var b={name:"flash_audio_ogg",options:{prefix:"flash_audio_ogg",filename:"mediaelement-flash-audio-ogg.swf"},canPlayType:function(e){return~["audio/ogg","audio/oga","audio/ogv"].indexOf(e.toLowerCase())},create:m.create};d.renderer.add(b)}},{2:2,23:23,25:25,26:26,3:3,4:4,6:6,7:7}],19:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(6)),r=e(7),s=e(25),l=e(23),d=e(26),u=e(24),c={promise:null,load:function(e){"undefined"!=typeof flvjs?c._createPlayer(e):(e.options.path="string"==typeof e.options.path?e.options.path:"https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.2.0/flv.min.js",c.promise=c.promise||(0,u.loadScript)(e.options.path),c.promise.then(function(){c._createPlayer(e)}))},_createPlayer:function(e){flvjs.LoggingControl.enableDebug=e.options.debug,flvjs.LoggingControl.enableVerbose=e.options.debug;var t=flvjs.createPlayer(e.options);return o.default["__ready__"+e.id](t),t}},f={name:"native_flv",options:{prefix:"native_flv",flv:{path:"https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.2.0/flv.min.js",cors:!0,withCredentials:!0,debug:!1}},canPlayType:function(e){return l.HAS_MSE&&["video/x-flv","video/flv"].indexOf(e.toLowerCase())>-1},create:function(e,t,n){var i=e.originalNode,l=e.id+"_"+t.prefix,d=null,u=null;d=i.cloneNode(!0),t=Object.assign(t,e.options);for(var f=a.default.html5media.properties,p=0,m=f.length;p<m;p++)!function(e){var n=""+e.substring(0,1).toUpperCase()+e.substring(1);d["get"+n]=function(){return null!==u?d[e]:null},d["set"+n]=function(n){if(-1===a.default.html5media.readOnlyProperties.indexOf(e)&&(d[e]=n,null!==u&&"src"===e)){var i={};i.type="flv",i.url=n,i.cors=t.flv.cors,i.debug=t.flv.debug,i.path=t.flv.path,i.withCredentials=t.flv.withCredentials,u.destroy(),(u=c._createPlayer({options:i,id:l})).attachMediaElement(d),u.load()}}}(f[p]);if(o.default["__ready__"+l]=function(t){e.flvPlayer=u=t;for(var n=a.default.html5media.events.concat(["click","mouseover","mouseout"]),i=0,o=n.length;i<o;i++)!function(t){"loadedmetadata"===t&&(u.unload(),u.detachMediaElement(),u.attachMediaElement(d),u.load()),d.addEventListener(t,function(t){var n=(0,s.createEvent)(t.type,e);e.dispatchEvent(n)})}(n[i])},n&&n.length>0)for(var h=0,v=n.length;h<v;h++)if(r.renderer.renderers[t.prefix].canPlayType(n[h].type)){d.setAttribute("src",n[h].src);break}d.setAttribute("id",l),i.parentNode.insertBefore(d,i),i.autoplay=!1,i.style.display="none";var y={};y.type="flv",y.url=d.src,y.cors=t.flv.cors,y.debug=t.flv.debug,y.path=t.flv.path,y.withCredentials=t.flv.withCredentials,c.load({options:y,id:l}),d.setSize=function(e,t){return d.style.width=e+"px",d.style.height=t+"px",d},d.hide=function(){return null!==u&&u.pause(),d.style.display="none",d},d.show=function(){return d.style.display="",d},d.destroy=function(){null!==u&&u.destroy()};var g=(0,s.createEvent)("rendererready",d);return e.dispatchEvent(g),d}};d.typeChecks.push(function(e){return~e.toLowerCase().indexOf(".flv")?"video/flv":null}),r.renderer.add(f)},{23:23,24:24,25:25,26:26,3:3,6:6,7:7}],20:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(6)),r=e(7),s=e(25),l=e(23),d=e(26),u=e(24),c={promise:null,load:function(e){"undefined"!=typeof Hls?c._createPlayer(e):(e.options.path="string"==typeof e.options.path?e.options.path:"http://cdn.jsdelivr.net/npm/hls.js@latest",c.promise=c.promise||(0,u.loadScript)(e.options.path),c.promise.then(function(){c._createPlayer(e)}))},_createPlayer:function(e){var t=new Hls(e.options);return o.default["__ready__"+e.id](t),t}},f={name:"native_hls",options:{prefix:"native_hls",hls:{path:"http://cdn.jsdelivr.net/npm/hls.js@latest",autoStartLoad:!1,debug:!1}},canPlayType:function(e){return l.HAS_MSE&&["application/x-mpegurl","vnd.apple.mpegurl","audio/mpegurl","audio/hls","video/hls"].indexOf(e.toLowerCase())>-1},create:function(e,t,n){var i=e.originalNode,l=e.id+"_"+t.prefix,d=i.getAttribute("preload"),u=i.autoplay,f=null,p=null;p=i.cloneNode(!0),(t=Object.assign(t,e.options)).hls.autoStartLoad=d&&"none"!==d||u;for(var m=a.default.html5media.properties,h=0,v=m.length;h<v;h++)!function(e){var n=""+e.substring(0,1).toUpperCase()+e.substring(1);p["get"+n]=function(){return null!==f?p[e]:null},p["set"+n]=function(n){-1===a.default.html5media.readOnlyProperties.indexOf(e)&&(p[e]=n,null!==f&&"src"===e&&(f.destroy(),(f=c._createPlayer({options:t.hls,id:l})).loadSource(n),f.attachMedia(p)))}}(m[h]);if(o.default["__ready__"+l]=function(t){e.hlsPlayer=f=t;for(var n=a.default.html5media.events.concat(["click","mouseover","mouseout"]),i=Hls.Events,o=0,r=n.length;o<r;o++)!function(t){if("loadedmetadata"===t){var n=e.originalNode.src;f.detachMedia(),f.loadSource(n),f.attachMedia(p)}p.addEventListener(t,function(t){var n=(0,s.createEvent)(t.type,e);e.dispatchEvent(n)})}(n[o]);var l=void 0,d=void 0;for(var u in i)i.hasOwnProperty(u)&&f.on(i[u],function(t,n){var i=(0,s.createEvent)(t,p);if(i.data=n,e.dispatchEvent(i),"hlsError"===t&&(console.warn(t,n),n.fatal))switch(n.type){case"mediaError":var o=(new Date).getTime();!l||o-l>3e3?(l=(new Date).getTime(),f.recoverMediaError()):!d||o-d>3e3?(d=(new Date).getTime(),console.warn("Attempting to swap Audio Codec and recover from media error"),f.swapAudioCodec(),f.recoverMediaError()):console.error("Cannot recover, last media error recovery failed");break;case"networkError":console.error("Network error");break;default:f.destroy()}})},n&&n.length>0)for(var y=0,g=n.length;y<g;y++)if(r.renderer.renderers[t.prefix].canPlayType(n[y].type)){p.setAttribute("src",n[y].src);break}"auto"===d||u||(p.addEventListener("play",function(){null!==f&&f.startLoad()}),p.addEventListener("pause",function(){null!==f&&f.stopLoad()})),p.setAttribute("id",l),i.parentNode.insertBefore(p,i),i.autoplay=!1,i.style.display="none",c.load({options:t.hls,id:l}),p.setSize=function(e,t){return p.style.width=e+"px",p.style.height=t+"px",p},p.hide=function(){return p.pause(),p.style.display="none",p},p.show=function(){return p.style.display="",p},p.destroy=function(){null!==f&&f.destroy()},p.stop=function(){null!==f&&f.stopLoad()};var b=(0,s.createEvent)("rendererready",p);return e.dispatchEvent(b),p}};d.typeChecks.push(function(e){return~e.toLowerCase().indexOf(".m3u8")?"application/x-mpegURL":null}),r.renderer.add(f)},{23:23,24:24,25:25,26:26,3:3,6:6,7:7}],21:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o=i(e(3)),a=i(e(2)),r=i(e(6)),s=e(7),l=e(25),d=e(23),u={name:"html5",options:{prefix:"html5"},canPlayType:function(e){var t=a.default.createElement("video");return d.IS_ANDROID&&/\/mp(3|4)$/i.test(e)||~["application/x-mpegurl","vnd.apple.mpegurl","audio/mpegurl","audio/hls","video/hls"].indexOf(e.toLowerCase())&&d.SUPPORTS_NATIVE_HLS?"yes":t.canPlayType?t.canPlayType(e.toLowerCase()).replace(/no/,""):""},create:function(e,t,n){var i=e.id+"_"+t.prefix,o=null;void 0===e.originalNode||null===e.originalNode?(o=a.default.createElement("audio"),e.appendChild(o)):o=e.originalNode,o.setAttribute("id",i);for(var d=r.default.html5media.properties,u=0,c=d.length;u<c;u++)!function(e){var t=""+e.substring(0,1).toUpperCase()+e.substring(1);o["get"+t]=function(){return o[e]},o["set"+t]=function(t){-1===r.default.html5media.readOnlyProperties.indexOf(e)&&(o[e]=t)}}(d[u]);for(var f=r.default.html5media.events.concat(["click","mouseover","mouseout"]),p=0,m=f.length;p<m;p++)!function(t){o.addEventListener(t,function(t){var n=(0,l.createEvent)(t.type,e);e.dispatchEvent(n)})}(f[p]);if(o.setSize=function(e,t){return o.style.width=e+"px",o.style.height=t+"px",o},o.hide=function(){return o.style.display="none",o},o.show=function(){return o.style.display="",o},n&&n.length>0)for(var h=0,v=n.length;h<v;h++)if(s.renderer.renderers[t.prefix].canPlayType(n[h].type)){o.setAttribute("src",n[h].src);break}var y=(0,l.createEvent)("rendererready",o);return e.dispatchEvent(y),o}};o.default.HtmlMediaElement=r.default.HtmlMediaElement=u,s.renderer.add(u)},{2:2,23:23,25:25,3:3,6:6,7:7}],22:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=i(e(3)),r=i(e(2)),s=i(e(6)),l=e(7),d=e(25),u=e(26),c=e(24),f={isIframeStarted:!1,isIframeLoaded:!1,iframeQueue:[],enqueueIframe:function(e){f.isLoaded="undefined"!=typeof YT&&YT.loaded,f.isLoaded?f.createIframe(e):(f.loadIframeApi(),f.iframeQueue.push(e))},loadIframeApi:function(){f.isIframeStarted||((0,c.loadScript)("https://www.youtube.com/player_api"),f.isIframeStarted=!0)},iFrameReady:function(){for(f.isLoaded=!0,f.isIframeLoaded=!0;f.iframeQueue.length>0;){var e=f.iframeQueue.pop();f.createIframe(e)}},createIframe:function(e){return new YT.Player(e.containerId,e)},getYouTubeId:function(e){var t="";return e.indexOf("?")>0?""===(t=f.getYouTubeIdFromParam(e))&&(t=f.getYouTubeIdFromUrl(e)):t=f.getYouTubeIdFromUrl(e),t},getYouTubeIdFromParam:function(e){if(void 0===e||null===e||!e.trim().length)return null;for(var t=e.split("?")[1].split("&"),n="",i=0,o=t.length;i<o;i++){var a=t[i].split("=");if("v"===a[0]){n=a[1];break}}return n},getYouTubeIdFromUrl:function(e){return void 0!==e&&null!==e&&e.trim().length?(e=e.split("?")[0]).substring(e.lastIndexOf("/")+1):null},getYouTubeNoCookieUrl:function(e){if(void 0===e||null===e||!e.trim().length||-1===e.indexOf("//www.youtube"))return e;var t=e.split("/");return t[2]=t[2].replace(".com","-nocookie.com"),t.join("/")}},p={name:"youtube_iframe",options:{prefix:"youtube_iframe",youtube:{autoplay:0,controls:0,disablekb:1,end:0,loop:0,modestbranding:0,playsinline:0,rel:0,showinfo:0,start:0,iv_load_policy:3,nocookie:!1}},canPlayType:function(e){return~["video/youtube","video/x-youtube"].indexOf(e.toLowerCase())},create:function(e,t,n){var i={},o=[],l=null,u=!0,c=!1,p=null,m=1;i.options=t,i.id=e.id+"_"+t.prefix,i.mediaElement=e;for(var h=s.default.html5media.properties,v=0,y=h.length;v<y;v++)!function(t){var n=""+t.substring(0,1).toUpperCase()+t.substring(1);i["get"+n]=function(){if(null!==l){switch(t){case"currentTime":return l.getCurrentTime();case"duration":return l.getDuration();case"volume":return m=l.getVolume()/100;case"paused":return u;case"ended":return c;case"muted":return l.isMuted();case"buffered":var e=l.getVideoLoadedFraction(),n=l.getDuration();return{start:function(){return 0},end:function(){return e*n},length:1};case"src":return l.getVideoUrl();case"readyState":return 4}return null}return null},i["set"+n]=function(n){if(null!==l)switch(t){case"src":var a="string"==typeof n?n:n[0].src,r=f.getYouTubeId(a);e.originalNode.autoplay?l.loadVideoById(r):l.cueVideoById(r);break;case"currentTime":l.seekTo(n);break;case"muted":n?l.mute():l.unMute(),setTimeout(function(){var t=(0,d.createEvent)("volumechange",i);e.dispatchEvent(t)},50);break;case"volume":m=n,l.setVolume(100*n),setTimeout(function(){var t=(0,d.createEvent)("volumechange",i);e.dispatchEvent(t)},50);break;case"readyState":var s=(0,d.createEvent)("canplay",i);e.dispatchEvent(s)}else o.push({type:"set",propName:t,value:n})}}(h[v]);for(var g=s.default.html5media.methods,b=0,E=g.length;b<E;b++)!function(e){i[e]=function(){if(null!==l)switch(e){case"play":return u=!1,l.playVideo();case"pause":return u=!0,l.pauseVideo();case"load":return null}else o.push({type:"call",methodName:e})}}(g[b]);var S=r.default.createElement("div");S.id=i.id,i.options.youtube.nocookie&&e.originalNode.setAttribute("src",f.getYouTubeNoCookieUrl(n[0].src)),e.originalNode.parentNode.insertBefore(S,e.originalNode),e.originalNode.style.display="none";var x="audio"===e.originalNode.tagName.toLowerCase(),w=x?"1":e.originalNode.height,P=x?"1":e.originalNode.width,T=f.getYouTubeId(n[0].src),C={id:i.id,containerId:S.id,videoId:T,height:w,width:P,playerVars:Object.assign({controls:0,rel:0,disablekb:1,showinfo:0,modestbranding:0,html5:1,playsinline:0,start:0,end:0,iv_load_policy:3},i.options.youtube),origin:a.default.location.host,events:{onReady:function(t){if(e.youTubeApi=l=t.target,e.youTubeState={paused:!0,ended:!1},o.length)for(var n=0,a=o.length;n<a;n++){var r=o[n];if("set"===r.type){var s=r.propName,u=""+s.substring(0,1).toUpperCase()+s.substring(1);i["set"+u](r.value)}else"call"===r.type&&i[r.methodName]()}p=l.getIframe();for(var c=["mouseover","mouseout"],f=0,m=c.length;f<m;f++)p.addEventListener(c[f],function(t){var n=(0,d.createEvent)(t.type,i);e.dispatchEvent(n)},!1);for(var h=["rendererready","loadedmetadata","loadeddata","canplay"],v=0,y=h.length;v<y;v++){var g=(0,d.createEvent)(h[v],i);e.dispatchEvent(g)}},onStateChange:function(t){var n=[];switch(t.data){case-1:n=["loadedmetadata"],u=!0,c=!1;break;case 0:n=["ended"],u=!1,c=!0,i.stopInterval();break;case 1:n=["play","playing"],u=!1,c=!1,i.startInterval();break;case 2:n=["pause"],u=!0,c=!1,i.stopInterval();break;case 3:n=["progress"],c=!1;break;case 5:n=["loadeddata","loadedmetadata","canplay"],u=!0,c=!1}for(var o=0,a=n.length;o<a;o++){var r=(0,d.createEvent)(n[o],i);e.dispatchEvent(r)}},onError:function(t){var n=(0,d.createEvent)("error",i);n.data=t.data,e.dispatchEvent(n)}}};return x&&(C.playerVars.playsinline=1),f.enqueueIframe(C),i.onEvent=function(t,n,i){null!==i&&void 0!==i&&(e.youTubeState=i)},i.setSize=function(e,t){null!==l&&l.setSize(e,t)},i.hide=function(){i.stopInterval(),i.pause(),p&&(p.style.display="none")},i.show=function(){p&&(p.style.display="")},i.destroy=function(){l.destroy()},i.interval=null,i.startInterval=function(){i.interval=setInterval(function(){var t=(0,d.createEvent)("timeupdate",i);e.dispatchEvent(t)},250)},i.stopInterval=function(){i.interval&&clearInterval(i.interval)},i}};a.default.postMessage&&o(a.default.addEventListener)&&(a.default.onYouTubePlayerAPIReady=function(){f.iFrameReady()},u.typeChecks.push(function(e){return/\/\/(www\.youtube|youtu\.be)/i.test(e)?"video/x-youtube":null}),l.renderer.add(p))},{2:2,24:24,25:25,26:26,3:3,6:6,7:7}],23:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(n,"__esModule",{value:!0}),n.cancelFullScreen=n.requestFullScreen=n.isFullScreen=n.FULLSCREEN_EVENT_NAME=n.HAS_NATIVE_FULLSCREEN_ENABLED=n.HAS_TRUE_NATIVE_FULLSCREEN=n.HAS_IOS_FULLSCREEN=n.HAS_MS_NATIVE_FULLSCREEN=n.HAS_MOZ_NATIVE_FULLSCREEN=n.HAS_WEBKIT_NATIVE_FULLSCREEN=n.HAS_NATIVE_FULLSCREEN=n.SUPPORTS_NATIVE_HLS=n.SUPPORT_POINTER_EVENTS=n.HAS_MSE=n.IS_STOCK_ANDROID=n.IS_SAFARI=n.IS_FIREFOX=n.IS_CHROME=n.IS_EDGE=n.IS_IE=n.IS_ANDROID=n.IS_IOS=n.IS_IPHONE=n.IS_IPAD=n.UA=n.NAV=void 0;for(var o=i(e(3)),a=i(e(2)),r=i(e(6)),s=n.NAV=o.default.navigator,l=n.UA=s.userAgent.toLowerCase(),d=n.IS_IPAD=/ipad/i.test(l),u=n.IS_IPHONE=/iphone/i.test(l),c=(n.IS_IOS=u||d,n.IS_ANDROID=/android/i.test(l)),f=n.IS_IE=/(trident|microsoft)/i.test(s.appName),p=(n.IS_EDGE="msLaunchUri"in s&&!("documentMode"in a.default)),m=n.IS_CHROME=/chrome/i.test(l),h=n.IS_FIREFOX=/firefox/i.test(l),v=n.IS_SAFARI=/safari/i.test(l)&&!m,y=n.IS_STOCK_ANDROID=/^mozilla\/\d+\.\d+\s\(linux;\su;/i.test(l),g=(n.HAS_MSE="MediaSource"in o.default),b=(n.SUPPORT_POINTER_EVENTS=function(){var e=a.default.createElement("x"),t=a.default.documentElement,n=o.default.getComputedStyle;if(!("pointerEvents"in e.style))return!1;e.style.pointerEvents="auto",e.style.pointerEvents="x",t.appendChild(e);var i=n&&"auto"===n(e,"").pointerEvents;return e.remove(),!!i}()),E=["source","track","audio","video"],S=void 0,x=0,w=E.length;x<w;x++)S=a.default.createElement(E[x]);var P=n.SUPPORTS_NATIVE_HLS=v||c&&(m||y)||f&&/edge/i.test(l),T=void 0!==S.webkitEnterFullscreen,C=void 0!==S.requestFullscreen;T&&/mac os x 10_5/i.test(l)&&(C=!1,T=!1);var k=void 0!==S.webkitRequestFullScreen,_=void 0!==S.mozRequestFullScreen,N=void 0!==S.msRequestFullscreen,A=k||_||N,L=A,F="",j=void 0,I=void 0,M=void 0;_?L=a.default.mozFullScreenEnabled:N&&(L=a.default.msFullscreenEnabled),m&&(T=!1),A&&(k?F="webkitfullscreenchange":_?F="mozfullscreenchange":N&&(F="MSFullscreenChange"),n.isFullScreen=j=function(){return _?a.default.mozFullScreen:k?a.default.webkitIsFullScreen:N?null!==a.default.msFullscreenElement:void 0},n.requestFullScreen=I=function(e){k?e.webkitRequestFullScreen():_?e.mozRequestFullScreen():N&&e.msRequestFullscreen()},n.cancelFullScreen=M=function(){k?a.default.webkitCancelFullScreen():_?a.default.mozCancelFullScreen():N&&a.default.msExitFullscreen()});var O=n.HAS_NATIVE_FULLSCREEN=C,H=n.HAS_WEBKIT_NATIVE_FULLSCREEN=k,D=n.HAS_MOZ_NATIVE_FULLSCREEN=_,q=n.HAS_MS_NATIVE_FULLSCREEN=N,R=n.HAS_IOS_FULLSCREEN=T,U=n.HAS_TRUE_NATIVE_FULLSCREEN=A,V=n.HAS_NATIVE_FULLSCREEN_ENABLED=L,B=n.FULLSCREEN_EVENT_NAME=F;n.isFullScreen=j,n.requestFullScreen=I,n.cancelFullScreen=M,r.default.Features=r.default.Features||{},r.default.Features.isiPad=d,r.default.Features.isiPhone=u,r.default.Features.isiOS=r.default.Features.isiPhone||r.default.Features.isiPad,r.default.Features.isAndroid=c,r.default.Features.isIE=f,r.default.Features.isEdge=p,r.default.Features.isChrome=m,r.default.Features.isFirefox=h,r.default.Features.isSafari=v,r.default.Features.isStockAndroid=y,r.default.Features.hasMSE=g,r.default.Features.supportsNativeHLS=P,r.default.Features.supportsPointerEvents=b,r.default.Features.hasiOSFullScreen=R,r.default.Features.hasNativeFullscreen=O,r.default.Features.hasWebkitNativeFullScreen=H,r.default.Features.hasMozNativeFullScreen=D,r.default.Features.hasMsNativeFullScreen=q,r.default.Features.hasTrueNativeFullScreen=U,r.default.Features.nativeFullScreenEnabled=V,r.default.Features.fullScreenEventName=B,r.default.Features.isFullScreen=j,r.default.Features.requestFullScreen=I,r.default.Features.cancelFullScreen=M},{2:2,3:3,6:6}],24:[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function o(e){function t(e){for(o=e;a=n.shift();)a[i]&&a[i](o)}var n=[],i=-1,o=void 0,a=void 0;return e(function(e){return t(e,i=0)},function(e){return t(e,i=1)}),{then:function(){for(var e=arguments.length,t=Array(e),a=0;a<e;a++)t[a]=arguments[a];~i?t[i]&&t[i](o):n.push(t)}}}function a(e){return o(function(t,n){var i=m.default.createElement("script");i.src=e,i.async=!0,i.onload=function(){i.remove(),t()},i.onerror=function(){i.remove(),n()},m.default.head.appendChild(i)})}function r(e){var t=e.getBoundingClientRect(),n=p.default.pageXOffset||m.default.documentElement.scrollLeft,i=p.default.pageYOffset||m.default.documentElement.scrollTop;return{top:t.top+i,left:t.left+n}}function s(e,t){b(e,t)?S(e,t):E(e,t)}function l(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:400,n=arguments[2];e.style.opacity||(e.style.opacity=1);var i=null;p.default.requestAnimationFrame(function o(a){var r=a-(i=i||a),s=parseFloat(1-r/t,2);e.style.opacity=s<0?0:s,r>t?n&&"function"==typeof n&&n():p.default.requestAnimationFrame(o)})}function d(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:400,n=arguments[2];e.style.opacity||(e.style.opacity=0);var i=null;p.default.requestAnimationFrame(function o(a){var r=a-(i=i||a),s=parseFloat(r/t,2);e.style.opacity=s>1?1:s,r>t?n&&"function"==typeof n&&n():p.default.requestAnimationFrame(o)})}function u(e,t){var n=[];e=e.parentNode.firstChild;do{t&&!t(e)||n.push(e)}while(e=e.nextSibling);return n}function c(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}function f(e,t,n,i){var o=p.default.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP"),a="application/x-www-form-urlencoded; charset=UTF-8",r=!1,s="*/".concat("*");switch(t){case"text":a="text/plain";break;case"json":a="application/json, text/javascript";break;case"html":a="text/html";break;case"xml":a="application/xml, text/xml"}"application/x-www-form-urlencoded"!==a&&(s=a+", */*; q=0.01"),o&&(o.open("GET",e,!0),o.setRequestHeader("Accept",s),o.onreadystatechange=function(){if(!r&&4===o.readyState)if(200===o.status){r=!0;var e=void 0;switch(t){case"json":e=JSON.parse(o.responseText);break;case"xml":e=o.responseXML;break;default:e=o.responseText}n(e)}else"function"==typeof i&&i(o.status)},o.send())}Object.defineProperty(n,"__esModule",{value:!0}),n.removeClass=n.addClass=n.hasClass=void 0,n.loadScript=a,n.offset=r,n.toggleClass=s,n.fadeOut=l,n.fadeIn=d,n.siblings=u,n.visible=c,n.ajax=f;var p=i(e(3)),m=i(e(2)),h=i(e(6)),v=void 0,y=void 0,g=void 0;"classList"in m.default.documentElement?(v=function(e,t){return void 0!==e.classList&&e.classList.contains(t)},y=function(e,t){return e.classList.add(t)},g=function(e,t){return e.classList.remove(t)}):(v=function(e,t){return new RegExp("\\b"+t+"\\b").test(e.className)},y=function(e,t){b(e,t)||(e.className+=" "+t)},g=function(e,t){e.className=e.className.replace(new RegExp("\\b"+t+"\\b","g"),"")});var b=n.hasClass=v,E=n.addClass=y,S=n.removeClass=g;h.default.Utils=h.default.Utils||{},h.default.Utils.offset=r,h.default.Utils.hasClass=b,h.default.Utils.addClass=E,h.default.Utils.removeClass=S,h.default.Utils.toggleClass=s,h.default.Utils.fadeIn=d,h.default.Utils.fadeOut=l,h.default.Utils.siblings=u,h.default.Utils.visible=c,h.default.Utils.ajax=f,h.default.Utils.loadScript=a},{2:2,3:3,6:6}],25:[function(e,t,n){"use strict";function i(e){if("string"!=typeof e)throw new Error("Argument passed must be a string");var t={"&":"&","<":"<",">":">",'"':"""};return e.replace(/[&<>"]/g,function(e){return t[e]})}function o(e,t){var n=this,i=arguments,o=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if("function"!=typeof e)throw new Error("First argument must be a function");if("number"!=typeof t)throw new Error("Second argument must be a numeric value");var a=void 0;return function(){var r=n,s=i,l=o&&!a;clearTimeout(a),a=setTimeout(function(){a=null,o||e.apply(r,s)},t),l&&e.apply(r,s)}}function a(e){return Object.getOwnPropertyNames(e).length<=0}function r(e,t){var n=/^((after|before)print|(before)?unload|hashchange|message|o(ff|n)line|page(hide|show)|popstate|resize|storage)\b/,i={d:[],w:[]};return(e||"").split(" ").forEach(function(e){var o=e+(t?"."+t:"");o.startsWith(".")?(i.d.push(o),i.w.push(o)):i[n.test(e)?"w":"d"].push(o)}),i.d=i.d.join(" "),i.w=i.w.join(" "),i}function s(e,t){if("string"!=typeof e)throw new Error("Event name must be a string");var n=e.match(/([a-z]+\.([a-z]+))/i),i={target:t};return null!==n&&(e=n[1],i.namespace=n[2]),new window.CustomEvent(e,{detail:i})}function l(e,t){return!!(e&&t&&2&e.compareDocumentPosition(t))}function d(e){return"string"==typeof e}Object.defineProperty(n,"__esModule",{value:!0}),n.escapeHTML=i,n.debounce=o,n.isObjectEmpty=a,n.splitEvents=r,n.createEvent=s,n.isNodeAfter=l,n.isString=d;var u=function(e){return e&&e.__esModule?e:{default:e}}(e(6));u.default.Utils=u.default.Utils||{},u.default.Utils.escapeHTML=i,u.default.Utils.debounce=o,u.default.Utils.isObjectEmpty=a,u.default.Utils.splitEvents=r,u.default.Utils.createEvent=s,u.default.Utils.isNodeAfter=l,u.default.Utils.isString=d},{6:6}],26:[function(e,t,n){"use strict";function i(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");var t=document.createElement("div");return t.innerHTML='<a href="'+(0,u.escapeHTML)(e)+'">x</a>',t.firstChild.href}function o(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e&&!t?r(e):a(t)}function a(e){if("string"!=typeof e)throw new Error("`type` argument must be a string");return e&&e.indexOf(";")>-1?e.substr(0,e.indexOf(";")):e}function r(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");for(var t=0,n=c.length;t<n;t++){var i=c[t](e);if(i)return i}var o=l(s(e)),a="video/mp4";return o&&(~["mp4","m4v","ogg","ogv","webm","flv","mpeg","mov"].indexOf(o)?a="video/"+o:~["mp3","oga","wav","mid","midi"].indexOf(o)&&(a="audio/"+o)),a}function s(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");var t=e.split("?")[0].split("\\").pop().split("/").pop();return~t.indexOf(".")?t.substring(t.lastIndexOf(".")+1):""}function l(e){if("string"!=typeof e)throw new Error("`extension` argument must be a string");switch(e){case"mp4":case"m4v":return"mp4";case"webm":case"webma":case"webmv":return"webm";case"ogg":case"oga":case"ogv":return"ogg";default:return e}}Object.defineProperty(n,"__esModule",{value:!0}),n.typeChecks=void 0,n.absolutizeUrl=i,n.formatType=o,n.getMimeFromType=a,n.getTypeFromFile=r,n.getExtension=s,n.normalizeExtension=l;var d=function(e){return e&&e.__esModule?e:{default:e}}(e(6)),u=e(25),c=n.typeChecks=[];d.default.Utils=d.default.Utils||{},d.default.Utils.typeChecks=c,d.default.Utils.absolutizeUrl=i,d.default.Utils.formatType=o,d.default.Utils.getMimeFromType=a,d.default.Utils.getTypeFromFile=r,d.default.Utils.getExtension=s,d.default.Utils.normalizeExtension=l},{25:25,6:6}],27:[function(e,t,n){"use strict";var i=function(e){return e&&e.__esModule?e:{default:e}}(e(2));[Element.prototype,CharacterData.prototype,DocumentType.prototype].forEach(function(e){e.hasOwnProperty("remove")||Object.defineProperty(e,"remove",{configurable:!0,enumerable:!0,writable:!0,value:function(){this.parentNode.removeChild(this)}})}),function(){function e(e,t){t=t||{bubbles:!1,cancelable:!1,detail:void 0};var n=i.default.createEvent("CustomEvent");return n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),n}if("function"==typeof window.CustomEvent)return!1;e.prototype=window.Event.prototype,window.CustomEvent=e}(),"function"!=typeof Object.assign&&(Object.assign=function(e){if(null===e||void 0===e)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(e),n=1,i=arguments.length;n<i;n++){var o=arguments[n];if(null!==o)for(var a in o)Object.prototype.hasOwnProperty.call(o,a)&&(t[a]=o[a])}return t}),String.prototype.startsWith||(String.prototype.startsWith=function(e,t){return t=t||0,this.substr(t,e.length)===e}),Element.prototype.matches||(Element.prototype.matches=Element.prototype.matchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||Element.prototype.webkitMatchesSelector||function(e){for(var t=(this.document||this.ownerDocument).querySelectorAll(e),n=t.length-1;--n>=0&&t.item(n)!==this;);return n>-1}),window.Element&&!Element.prototype.closest&&(Element.prototype.closest=function(e){var t=(this.document||this.ownerDocument).querySelectorAll(e),n=void 0,i=this;do{for(n=t.length;--n>=0&&t.item(n)!==i;);}while(n<0&&(i=i.parentElement));return i}),function(){for(var e=0,t=["ms","moz","webkit","o"],n=0;n<t.length&&!window.requestAnimationFrame;++n)window.requestAnimationFrame=window[t[n]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[t[n]+"CancelAnimationFrame"]||window[t[n]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(t){var n=(new Date).getTime(),i=Math.max(0,16-(n-e)),o=window.setTimeout(function(){t(n+i)},i);return e=n+i,o}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(e){clearTimeout(e)})}(),/firefox/i.test(navigator.userAgent)&&(window.mediaElementJsOldGetComputedStyle=window.getComputedStyle,window.getComputedStyle=function(e,t){var n=window.mediaElementJsOldGetComputedStyle(e,t);return null===n?{getPropertyValue:function(){}}:n})},{2:2}],28:[function(e,t,n){"use strict";function i(){return!((arguments.length>0&&void 0!==arguments[0]?arguments[0]:25)%1==0)}function o(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:25,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0;e=!e||"number"!=typeof e||e<0?0:e;var r=Math.round(.066666*o),s=Math.round(o),l=24*Math.round(3600*o),d=Math.round(600*o),u=i(o)?";":":",c=void 0,f=void 0,p=void 0,m=void 0,h=Math.round(e*o);if(i(o)){h<0&&(h=l+h);var v=(h%=l)%d;h+=9*r*Math.floor(h/d),v>r&&(h+=r*Math.floor((v-r)/Math.round(60*s-r)));var y=Math.floor(h/s);c=Math.floor(Math.floor(y/60)/60),f=Math.floor(y/60)%60,p=n?y%60:(h/s%60).toFixed(a)}else c=Math.floor(e/3600)%24,f=Math.floor(e/60)%60,p=n?Math.floor(e%60):(e%60).toFixed(a);c=c<=0?0:c,f=f<=0?0:f,p=p<=0?0:p;var g=t||c>0?(c<10?"0"+c:c)+":":"";return g+=(f<10?"0"+f:f)+":",g+=""+(p<10?"0"+p:p),n&&(g+=(m=(m=(h%s).toFixed(0))<=0?0:m)<10?u+"0"+m:""+u+m),g}function a(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25;if("string"!=typeof e)throw new TypeError("Time must be a string");if(e.indexOf(";")>0&&(e=e.replace(";",":")),!/\d{2}(\:\d{2}){0,3}/i.test(e))throw new TypeError("Time code must have the format `00:00:00`");var n=e.split(":"),o=void 0,a=0,r=0,s=0,l=0,d=0,u=Math.round(.066666*t),c=Math.round(t),f=3600*c,p=60*c;switch(n.length){default:case 1:s=parseInt(n[0],10);break;case 2:r=parseInt(n[0],10),s=parseInt(n[1],10);break;case 3:a=parseInt(n[0],10),r=parseInt(n[1],10),s=parseInt(n[2],10);break;case 4:a=parseInt(n[0],10),r=parseInt(n[1],10),s=parseInt(n[2],10),l=parseInt(n[3],10)}return o=i(t)?f*a+p*r+c*s+l-u*((d=60*a+r)-Math.floor(d/10)):(f*a+p*r+t*s+l)/t,parseFloat(o.toFixed(3))}function r(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:25;e=!e||"number"!=typeof e||e<0?0:e;for(var i=Math.floor(e/3600)%24,o=Math.floor(e/60)%60,a=Math.floor(e%60),r=[[Math.floor((e%1*n).toFixed(3)),"f"],[a,"s"],[o,"m"],[i,"h"]],s=t.timeFormat,l=s[1]===s[0],d=l?2:1,u=s.length<d?s[d]:":",c=s[0],f=!1,p=0,m=r.length;p<m;p++)if(~s.indexOf(r[p][1]))f=!0;else if(f){for(var h=!1,v=p;v<m;v++)if(r[v][0]>0){h=!0;break}if(!h)break;l||(s=c+s),s=r[p][1]+u+s,l&&(s=r[p][1]+s),c=r[p][1]}t.currentTimeFormat=s}function s(e){if("string"!=typeof e)throw new TypeError("Argument must be a string value");for(var t=~(e=e.replace(",",".")).indexOf(".")?e.split(".")[1].length:0,n=0,i=1,o=0,a=(e=e.split(":").reverse()).length;o<a;o++)i=1,o>0&&(i=Math.pow(60,o)),n+=Number(e[o])*i;return Number(n.toFixed(t))}Object.defineProperty(n,"__esModule",{value:!0}),n.isDropFrame=i,n.secondsToTimeCode=o,n.timeCodeToSeconds=a,n.calculateTimeFormat=r,n.convertSMPTEtoSeconds=s;var l=function(e){return e&&e.__esModule?e:{default:e}}(e(6));l.default.Utils=l.default.Utils||{},l.default.Utils.secondsToTimeCode=o,l.default.Utils.timeCodeToSeconds=a,l.default.Utils.calculateTimeFormat=r,l.default.Utils.convertSMPTEtoSeconds=s},{6:6}]},{},[27,5,4,14,21,18,17,19,20,22,15,16,8,9,10,11,12,13]); \ No newline at end of file diff --git a/src/main/webapp/static/movie/player.js b/src/main/webapp/static/movie/player.js index 7e9f6334e44ff9fc5d55762a045570ce8a62b694..fd55d91eb7e4d1250e51344d4ac23f9d84a275f5 100644 --- a/src/main/webapp/static/movie/player.js +++ b/src/main/webapp/static/movie/player.js @@ -152,7 +152,8 @@ var BPlayer = { path: mediaElementBaseUrl + 'hls/hls.min.js' }, flv : { - path: mediaElementBaseUrl + 'flv/flv.min.js' + path: mediaElementBaseUrl + 'flv/flv.min.js', + withCredentials: true }, success: function(mediaElement, originalNode, player) { if(config.autostart) { @@ -206,12 +207,14 @@ var BPlayer = { config.enablePseudoStreaming = true; if(extension == 'flv') { mimeType = "video/flv"; + meConfig.renderers = ['flash_video','native_flv']; } else { mimeType = "video/mp4"; } } else { if(extension == 'flv') { mimeType = "video/flv"; + meConfig.renderers = ['flash_video','native_flv']; } else if(extension == 'f4v') { mimeType = "video/flv"; } else if(extension == 'mp4') { diff --git a/src/main/webapp/static/movie/player.min.js b/src/main/webapp/static/movie/player.min.js index 8767757a414647b61db17a6181a4f77921ebc468..89475ba7ee7c22e6bcbcacb6c9cc2a5596005dc5 100644 --- a/src/main/webapp/static/movie/player.min.js +++ b/src/main/webapp/static/movie/player.min.js @@ -1 +1 @@ -var BPlayer={insertPlayer:function(j,d,c,k,b,e,h,g,l,a,f,i){BPlayer.insertHTML5Player(j,d,c,k,b,e,h,g,l,a,f,i)},insertHTML5Player:function(c,g,l,k,e,a,n,r,p,i,m,j){var f=c;if(c.indexOf("://")<0&&(c.indexOf("/raw/static/")==0||c.indexOf("/secstatic/qtieditor/")>=0||c.indexOf("/secstatic/qti/")>=0)){f=c}else{if(c.indexOf("://")<0&&((n!="rtmp"&&n!="http")||((n=="rtmp"||n=="http")&&(r==undefined||r.length==0)))){var d=document.location.href;f=d.substring(0,d.lastIndexOf("/"));if(c.indexOf("/")!=0){f+="/"}f+=c}}var b={file:f,width:l,height:k,controlbar:{position:"bottom"}};if(typeof n!="undefined"){b.provider=n}if(n=="rtmp"||n=="http"){b.streamer=r}if(typeof e!="undefined"){var h=BPlayer._convertInSeconds(e);if(h>0){b.start=h}}if(typeof a!="undefined"){var q=BPlayer._convertInSeconds(a);if(q>0){b.duration=q}}if(typeof p!="undefined"&&p){b.autostart=true}if(typeof i!="undefined"&&i){b.repeat="single"}if(typeof m!="undefined"&&!m){b.controlbar="none"}if(typeof j!="undefined"){b.image=j}if(BPlayer._needJWPlayerFallback(b)){b.flashplayer=BPlayer._jwPlayerBaseUrl()+"movieViewer.swf";var o=function(){jwplayer(g).setup(b)};BPlayer._loadJWPlayer(o)}else{var o=function(){BPlayer._insertHTML5MediaElementPlayerWorker(g,b)};BPlayer.loadMediaelementJsPlayer(o)}},loadMediaelementJsPlayer:function(d){var a=BPlayer._mediaElementBaseUrl();var c=a+(BPlayer.debugEnabled?"mediaelementplayer.css":"mediaelementplayer.min.css");var b=a+(BPlayer.debugEnabled?"mediaelement-and-player.js":"mediaelement-and-player.min.js");if(jQuery("#mediaelementplayercss").length==0){jQuery("<link>").appendTo("head").attr({id:"mediaelementplayercss",type:"text/css",rel:"stylesheet"}).attr("href",c)}if(typeof jQuery("body").mediaelementplayer!="undefined"){if(d){d()}}else{jQuery.ajax({dataType:"script",cache:true,async:false,url:b}).done(function(){if(d){d()}})}},_loadJWPlayer:function(a){if(BPlayer._isIE8()&&domId!="prev_container"&&jQuery("#"+domId).is("span")){alert("This is video is not supported on Internet Explorer 8. Sorry for the inconvenience")}else{jQuery.getScript(BPlayer._jwPlayerBaseUrl()+"player.jw.js",function(){if(a){a()}})}},_needJWPlayerFallback:function(a){if(a.provider=="rtmp"){if(a.file.match(/(.*)\/((flv|mp4|mp3):.*)/)){return false}else{return true}}return false},_insertHTML5MediaElementPlayerWorker:function(e,d){var j=BPlayer._mediaElementBaseUrl();var k={loop:d.repeat,pluginPath:j,stretching:"responsive",hls:{path:j+"hls/hls.min.js"},flv:{path:j+"flv/flv.min.js"},success:function(n,p,o){if(d.autostart){try{o.load();o.play()}catch(q){if(window.console){console.log(q)}}}if(d.start){var r=true;if(!d.autostart){o.play()}n.addEventListener("loadedmetadata",function(){try{o.setCurrentTime(d.start);if(!d.autostart&&r){r=true;o.pause()}}catch(s){if(window.console){console.log(s)}}})}}};var a=null;var m=d.file.split(".").pop().toLowerCase().split("&").shift();if(d.provider=="sound"){if(m=="mp3"){a="audio/mp3"}else{if(m=="aac"){a="audio/aac"}else{if(m=="m4a"){a="audio/mp4"}}}}else{if(d.provider=="youtube"){a="video/youtube"}else{if(d.provider=="vimeo"){a="video/vimeo"}else{if(d.provider=="rtmp"){k.flashStreamer=d.streamer;a="video/rtmp"}else{if(d.provider=="http"){d.enablePseudoStreaming=true;if(m=="flv"){a="video/flv"}else{a="video/mp4"}}else{if(m=="flv"){a="video/flv"}else{if(m=="f4v"){a="video/flv"}else{if(m=="mp4"){a="video/mp4"}else{if(m=="m4v"){a="video/m4v"}else{if(m=="m3u8"){a="application/x-mpegURL"}else{if(m=="aac"){a="audio/mp4";d.provider="sound"}else{if(m=="mp3"){a="audio/mp3";d.provider="sound"}else{if(m=="m4a"){a="audio/mp4";d.provider="sound"}else{if(d.file.indexOf("vimeo.com")>-1){a="video/vimeo"}else{if(d.file.indexOf("youtube.com")>-1||d.file.indexOf("youtu.be")>-1||d.file.indexOf("youtube.be")>-1){a="video/youtube"}else{if(m.indexOf("mp4?")==0){a="video/mp4"}else{alert("Something go badly wrong!"+d.provider+" "+m)}}}}}}}}}}}}}}}}var i;var c=e+"_oo"+Math.floor(Math.random()*1000000)+"vid";var f=e+"_oo"+Math.floor(Math.random()*1000000)+"obj";if(d.provider=="sound"){if(d.height){k.audioHeight=d.height}if(d.width){k.audioWidth=d.width}i="<audio id='"+c+"' controls='controls' oncontextmenu='return false;'";if(typeof d.repeat!="undefined"&&d.repeat){i+=" loop='loop'"}var b="<object id='"+f+"' type='application/x-shockwave-flash'";if(typeof d.height!="undefined"){i+=" height='"+d.height+"'";b+=" height='"+d.height+"'";k.videoHeight=d.height}if(typeof d.width!="undefined"){i+=" width='"+d.width+"'";b+=" width='"+d.width+"'";k.videoWidth=d.width}if(typeof d.image!="undefined"){i+=" poster='"+d.image+"'"}i+="><source type='"+a+"' src='"+d.file+"'>";var g="mediaelement-flash-video.swf";if(a=="audio/mp3"){g="mediaelement-flash-audio.swf"}else{if(a=="audio/ogg"){g="mediaelement-flash-audio-ogg.swf"}}i+=b+" data='"+j+g+"'>";i+="<param name='movie' value='"+j+g+"' />";i+="<param name='flashvars' value='controls=true&";if(typeof d.streamer!="undefined"){i+="&streamer="+d.streamer}i+="&file="+d.file+"' /></object>";i+="</audio>"}else{i="<video id='"+c+"' controls='controls' preload='none' oncontextmenu='return false;'";if(typeof d.repeat!="undefined"&&d.repeat){i+=" loop='loop'"}var b="<object id='"+f+"' type='application/x-shockwave-flash'";if(typeof d.height!="undefined"){i+=" height='"+d.height+"'";b+=" height='"+d.height+"'";k.videoHeight=d.height}if(typeof d.width!="undefined"){i+=" width='"+d.width+"'";b+=" width='"+d.width+"'";k.videoWidth=d.width}if(typeof d.image!="undefined"){i+=" poster='"+d.image+"'"}i+="><source type='"+a+"' src='"+d.file+"' />";i+=b+" data='"+j+"mediaelement-flash-video.swf'>";i+="<param name='movie' value='"+j+"mediaelement-flash-video.swf' />";i+="<param name='flashvars' value='controls=true";if(typeof d.streamer!="undefined"){i+="&streamer="+d.streamer}i+="&file="+d.file+"' /></object></video>"}var h=jQuery("#"+e);h.css({height:"auto"});if(jQuery(window).width()<=d.width){h.css({width:"auto"})}h.html(i);if(a=="video/vimeo"){var j=BPlayer._mediaElementBaseUrl();var l=j+(BPlayer.debugEnabled?"renderers/vimeo.js":"renderers/vimeo.min.js");jQuery.ajax({dataType:"script",cache:true,async:false,url:l}).done(function(){jQuery("#"+c).mediaelementplayer(k)})}else{jQuery("#"+c).mediaelementplayer(k)}},_mediaElementBaseUrl:function(){var a=BPlayer._findBaseUrl(window);if(a==null){a="/olat/raw/_noversion_/"}a+="movie/mediaelementjs/";return a},_isIE8:function(){return(jQuery.support.opacity==false)},_jwPlayerBaseUrl:function(){var a=BPlayer._findBaseUrl(window);if(a==null){a="/olat/raw/_noversion_/"}a+="movie/jw/";return a},_findBaseUrl:function(a){if(a.o_info){return a.o_info.o_baseURI}else{if(a.opener){return BPlayer._findBaseUrl(a.opener)}else{if(a.parent){return BPlayer._findBaseUrl(a.parent)}else{return null}}}},_convertInSeconds:function(d){if(typeof d=="undefined"||d==null){return 0}if(!d.length){return d}if(d.length==0){return 0}if(d.indexOf(".")>0){d=d.substring(0,d.indexOf("."))}var e=d.lastIndexOf(":");if(e>0){var c=d.substring(e+1,d.length);var a=parseInt(c);d=d.substring(0,e);e=d.lastIndexOf(":");if(e>0){var b=d.substring(e+1,d.length);a+=60*parseInt(b)}d=d.substring(0,e);if(d.length>0){a+=60*60*parseInt(d)}return a}else{return d}},_isOODebug:function(a){if(a.o_info){return a.o_info.debug}else{if(a.opener){return BPlayer._isOODebug(a.opener)}else{if(a.parent){return BPlayer._isOODebug(a.parent)}else{return false}}}}};BPlayer.debugEnabled=BPlayer._isOODebug(window); \ No newline at end of file +var BPlayer={insertPlayer:function(j,d,c,k,b,e,h,g,l,a,f,i){BPlayer.insertHTML5Player(j,d,c,k,b,e,h,g,l,a,f,i)},insertHTML5Player:function(c,g,l,k,e,a,n,r,p,i,m,j){var f=c;if(c.indexOf("://")<0&&(c.indexOf("/raw/static/")==0||c.indexOf("/secstatic/qtieditor/")>=0||c.indexOf("/secstatic/qti/")>=0)){f=c}else{if(c.indexOf("://")<0&&((n!="rtmp"&&n!="http")||((n=="rtmp"||n=="http")&&(r==undefined||r.length==0)))){var d=document.location.href;f=d.substring(0,d.lastIndexOf("/"));if(c.indexOf("/")!=0){f+="/"}f+=c}}var b={file:f,width:l,height:k,controlbar:{position:"bottom"}};if(typeof n!="undefined"){b.provider=n}if(n=="rtmp"||n=="http"){b.streamer=r}if(typeof e!="undefined"){var h=BPlayer._convertInSeconds(e);if(h>0){b.start=h}}if(typeof a!="undefined"){var q=BPlayer._convertInSeconds(a);if(q>0){b.duration=q}}if(typeof p!="undefined"&&p){b.autostart=true}if(typeof i!="undefined"&&i){b.repeat="single"}if(typeof m!="undefined"&&!m){b.controlbar="none"}if(typeof j!="undefined"){b.image=j}if(BPlayer._needJWPlayerFallback(b)){b.flashplayer=BPlayer._jwPlayerBaseUrl()+"movieViewer.swf";var o=function(){jwplayer(g).setup(b)};BPlayer._loadJWPlayer(o)}else{var o=function(){BPlayer._insertHTML5MediaElementPlayerWorker(g,b)};BPlayer.loadMediaelementJsPlayer(o)}},loadMediaelementJsPlayer:function(d){var a=BPlayer._mediaElementBaseUrl();var c=a+(BPlayer.debugEnabled?"mediaelementplayer.css":"mediaelementplayer.min.css");var b=a+(BPlayer.debugEnabled?"mediaelement-and-player.js":"mediaelement-and-player.min.js");if(jQuery("#mediaelementplayercss").length==0){jQuery("<link>").appendTo("head").attr({id:"mediaelementplayercss",type:"text/css",rel:"stylesheet"}).attr("href",c)}if(typeof jQuery("body").mediaelementplayer!="undefined"){if(d){d()}}else{jQuery.ajax({dataType:"script",cache:true,async:false,url:b}).done(function(){if(d){d()}})}},_loadJWPlayer:function(a){if(BPlayer._isIE8()&&domId!="prev_container"&&jQuery("#"+domId).is("span")){alert("This is video is not supported on Internet Explorer 8. Sorry for the inconvenience")}else{jQuery.getScript(BPlayer._jwPlayerBaseUrl()+"player.jw.js",function(){if(a){a()}})}},_needJWPlayerFallback:function(a){if(a.provider=="rtmp"){if(a.file.match(/(.*)\/((flv|mp4|mp3):.*)/)){return false}else{return true}}return false},_insertHTML5MediaElementPlayerWorker:function(e,d){var j=BPlayer._mediaElementBaseUrl();var k={loop:d.repeat,pluginPath:j,stretching:"responsive",hls:{path:j+"hls/hls.min.js"},flv:{path:j+"flv/flv.min.js",withCredentials:true},success:function(n,p,o){if(d.autostart){try{o.load();o.play()}catch(q){if(window.console){console.log(q)}}}if(d.start){var r=true;if(!d.autostart){o.play()}n.addEventListener("loadedmetadata",function(){try{o.setCurrentTime(d.start);if(!d.autostart&&r){r=true;o.pause()}}catch(s){if(window.console){console.log(s)}}})}}};var a=null;var m=d.file.split(".").pop().toLowerCase().split("&").shift();if(d.provider=="sound"){if(m=="mp3"){a="audio/mp3"}else{if(m=="aac"){a="audio/aac"}else{if(m=="m4a"){a="audio/mp4"}}}}else{if(d.provider=="youtube"){a="video/youtube"}else{if(d.provider=="vimeo"){a="video/vimeo"}else{if(d.provider=="rtmp"){k.flashStreamer=d.streamer;a="video/rtmp"}else{if(d.provider=="http"){d.enablePseudoStreaming=true;if(m=="flv"){a="video/flv";k.renderers=["flash_video","native_flv"]}else{a="video/mp4"}}else{if(m=="flv"){a="video/flv";k.renderers=["flash_video","native_flv"]}else{if(m=="f4v"){a="video/flv"}else{if(m=="mp4"){a="video/mp4"}else{if(m=="m4v"){a="video/m4v"}else{if(m=="m3u8"){a="application/x-mpegURL"}else{if(m=="aac"){a="audio/mp4";d.provider="sound"}else{if(m=="mp3"){a="audio/mp3";d.provider="sound"}else{if(m=="m4a"){a="audio/mp4";d.provider="sound"}else{if(d.file.indexOf("vimeo.com")>-1){a="video/vimeo"}else{if(d.file.indexOf("youtube.com")>-1||d.file.indexOf("youtu.be")>-1||d.file.indexOf("youtube.be")>-1){a="video/youtube"}else{if(m.indexOf("mp4?")==0){a="video/mp4"}else{alert("Something go badly wrong!"+d.provider+" "+m)}}}}}}}}}}}}}}}}var i;var c=e+"_oo"+Math.floor(Math.random()*1000000)+"vid";var f=e+"_oo"+Math.floor(Math.random()*1000000)+"obj";if(d.provider=="sound"){if(d.height){k.audioHeight=d.height}if(d.width){k.audioWidth=d.width}i="<audio id='"+c+"' controls='controls' oncontextmenu='return false;'";if(typeof d.repeat!="undefined"&&d.repeat){i+=" loop='loop'"}var b="<object id='"+f+"' type='application/x-shockwave-flash'";if(typeof d.height!="undefined"){i+=" height='"+d.height+"'";b+=" height='"+d.height+"'";k.videoHeight=d.height}if(typeof d.width!="undefined"){i+=" width='"+d.width+"'";b+=" width='"+d.width+"'";k.videoWidth=d.width}if(typeof d.image!="undefined"){i+=" poster='"+d.image+"'"}i+="><source type='"+a+"' src='"+d.file+"'>";var g="mediaelement-flash-video.swf";if(a=="audio/mp3"){g="mediaelement-flash-audio.swf"}else{if(a=="audio/ogg"){g="mediaelement-flash-audio-ogg.swf"}}i+=b+" data='"+j+g+"'>";i+="<param name='movie' value='"+j+g+"' />";i+="<param name='flashvars' value='controls=true&";if(typeof d.streamer!="undefined"){i+="&streamer="+d.streamer}i+="&file="+d.file+"' /></object>";i+="</audio>"}else{i="<video id='"+c+"' controls='controls' preload='none' oncontextmenu='return false;'";if(typeof d.repeat!="undefined"&&d.repeat){i+=" loop='loop'"}var b="<object id='"+f+"' type='application/x-shockwave-flash'";if(typeof d.height!="undefined"){i+=" height='"+d.height+"'";b+=" height='"+d.height+"'";k.videoHeight=d.height}if(typeof d.width!="undefined"){i+=" width='"+d.width+"'";b+=" width='"+d.width+"'";k.videoWidth=d.width}if(typeof d.image!="undefined"){i+=" poster='"+d.image+"'"}i+="><source type='"+a+"' src='"+d.file+"' />";i+=b+" data='"+j+"mediaelement-flash-video.swf'>";i+="<param name='movie' value='"+j+"mediaelement-flash-video.swf' />";i+="<param name='flashvars' value='controls=true";if(typeof d.streamer!="undefined"){i+="&streamer="+d.streamer}i+="&file="+d.file+"' /></object></video>"}var h=jQuery("#"+e);h.css({height:"auto"});if(jQuery(window).width()<=d.width){h.css({width:"auto"})}h.html(i);if(a=="video/vimeo"){var j=BPlayer._mediaElementBaseUrl();var l=j+(BPlayer.debugEnabled?"renderers/vimeo.js":"renderers/vimeo.min.js");jQuery.ajax({dataType:"script",cache:true,async:false,url:l}).done(function(){jQuery("#"+c).mediaelementplayer(k)})}else{jQuery("#"+c).mediaelementplayer(k)}},_mediaElementBaseUrl:function(){var a=BPlayer._findBaseUrl(window);if(a==null){a="/olat/raw/_noversion_/"}a+="movie/mediaelementjs/";return a},_isIE8:function(){return(jQuery.support.opacity==false)},_jwPlayerBaseUrl:function(){var a=BPlayer._findBaseUrl(window);if(a==null){a="/olat/raw/_noversion_/"}a+="movie/jw/";return a},_findBaseUrl:function(a){if(a.o_info){return a.o_info.o_baseURI}else{if(a.opener){return BPlayer._findBaseUrl(a.opener)}else{if(a.parent){return BPlayer._findBaseUrl(a.parent)}else{return null}}}},_convertInSeconds:function(d){if(typeof d=="undefined"||d==null){return 0}if(!d.length){return d}if(d.length==0){return 0}if(d.indexOf(".")>0){d=d.substring(0,d.indexOf("."))}var e=d.lastIndexOf(":");if(e>0){var c=d.substring(e+1,d.length);var a=parseInt(c);d=d.substring(0,e);e=d.lastIndexOf(":");if(e>0){var b=d.substring(e+1,d.length);a+=60*parseInt(b)}d=d.substring(0,e);if(d.length>0){a+=60*60*parseInt(d)}return a}else{return d}},_isOODebug:function(a){if(a.o_info){return a.o_info.debug}else{if(a.opener){return BPlayer._isOODebug(a.opener)}else{if(a.parent){return BPlayer._isOODebug(a.parent)}else{return false}}}}};BPlayer.debugEnabled=BPlayer._isOODebug(window); \ No newline at end of file diff --git a/src/main/webapp/static/themes/light/_config.scss b/src/main/webapp/static/themes/light/_config.scss index b5137adbf1fc7d09ceadf5c911d1b507731c6939..e1d06c374f6e79086711643440b2a9b5806e1af3 100644 --- a/src/main/webapp/static/themes/light/_config.scss +++ b/src/main/webapp/static/themes/light/_config.scss @@ -357,6 +357,8 @@ $o-portfolio-lead-space-sm : $padding-large-vertical !default; $o-portfolio-lead-background-color : lighten($gray-base, 95%) !default; $o-portfolio-lead-border-color : darken($o-portfolio-lead-background-color,10%) !default; $o-portfolio-lead-border-radius : $border-radius-small !default; +$o-portfolio-lead-ended-background-color : lighten($brand-danger, 30%) !default; +$o-portfolio-lead-ended-border-color : darken($o-portfolio-lead-ended-background-color ,10%) !default; $o-portfolio-page-summary-font-size : $font-size-large !default; /* QTI2 eAssessment */ @@ -402,9 +404,9 @@ $o-qti-error : $brand-danger !default; $o-qti-box-bg : #eee !default; $o-qti-box-color : #666 !default; $o-qti-choice-tablelayout-bg : #e7e7e7 !default; -$o-qti-userselection-color : #fff !default; -$o-qti-userselection-bg : $o-qti-status-review-color !default; -$o-qti-userselection-border-color : darken($o-qti-userselection-bg,10%) !default; +$o-qti-userselection-color : $text-color !default; +$o-qti-userselection-bg : $state-info-bg !default; +$o-qti-userselection-border-color : $state-info-border !default; $o-qti-gap-border-color : #999 !default; $o-qti-gap-drag-border-color : $brand-primary !default; $o-qti-gap-selected-border-color : $brand-primary !default; @@ -428,6 +430,13 @@ $o-qti-match-drop-accept-border-color : darken($brand-info, 25%) !default; $o-qti-match-target-border-color : $brand-info !default; $o-qti-match-target-bg : $state-info-bg !default; $o-qti-match-border-radius : $panel-border-radius !default; +$o-qti-order-source-border-style : dashed !default; +$o-qti-order-sources-border-color : $o-qti-run-infos-border-color !default; +$o-qti-order-border-radius : $panel-border-radius !default; +$o-qti-order-source-bg : $state-warning-bg !default; +$o-qti-order-sources-bg : $o-qti-run-infos-bg !default; +$o-qti-order-drop-accept-border-color : darken($brand-info, 25%) !default; +$o-qti-order-target-bg : $state-info-bg !default; $o-qti-textEntryInteraction-color : $text-color !default; $o-qti-textEntryInteraction-bg : #fff !default; $o-qti-textEntryInteraction-border-color : $o-qti-gap-border-color !default; @@ -435,6 +444,11 @@ $o-qti-textEntryInteraction-filled-color : $o-qti-userselection-color !default $o-qti-textEntryInteraction-filled-bg : $o-qti-userselection-bg !default; $o-qti-textEntryInteraction-filled-border-color : $o-qti-userselection-border-color !default; +/* Lecture module */ +$o-lm-current-bg : $o-toolbar-bg-color !default; +$o-lm-current-border-color : transparent !default; +$o-lm-current-border-radius : $border-radius-base !default; + /* Chat and other floating window */ $o-dialog-window-bg : #fefefe !default; $o-dialog-window-bar-bg : #eee !default; @@ -475,9 +489,15 @@ $o-forum-quote-font-size : $font-size-small !default; $o-forum-attachment-font-size : $font-size-small !default; /* Evaluation forms */ -$o-evaluation-slider-margin-bottom : 8px; -$o-evaluation-step-labels-margin-bottom : 8px; -$o-evaluation-slider-hover-background-color : $table-bg-hover; +$o-evaluation-block-margin-top : 2em !default; +$o-evaluation-block-margin-bottom : 2em !default; +$o-evaluation-side-labels-font-weight : normal !default; +$o-evaluation-step-labels-margin-bottom : 1em !default; +$o-evaluation-step-labels-font-weight : bold !default; +$o-evaluation-step-background-color : $table-bg-accent !default; +$o-evaluation-slider-margin-bottom : 1em !default; +$o-evaluation-slider-hover-background-color : $table-bg-hover !default; + /* Portlets site */ $o-portlet-border : $panel-default-border !default; @@ -631,7 +651,8 @@ $o-cit-quote-font-size : $font-size-large !default; $o-cit-quote-color : $o-forum-quote-color !default; /* Sliders */ -$o-slider-border : #999; +$o-slider-border : #aaa !default; +$o-slider-background : #f9f9f9 !default; $o-slider-handler-border-color : $brand-primary !default; $o-slider-handler-background-color : $brand-primary !default; @@ -641,3 +662,4 @@ $o-portrait-border : none !default; $o-bookmark-color : #bc2d0c !default; $o-imagebg-text-background : rgba(255, 255, 255, 0.8) !default; $o-progress-marker-color : rgb(255, 0, 0) !default; /* danger color */ +$o-cal-desc-background-color : $o-toolbar-bg-color !default; diff --git a/src/main/webapp/static/themes/light/content.css b/src/main/webapp/static/themes/light/content.css index 23c1b7266aae7e00f4469ff534feb128ad1a0f21..7e451118685094cf8bb1c43f6ea739b1c241c488 100644 --- a/src/main/webapp/static/themes/light/content.css +++ b/src/main/webapp/static/themes/light/content.css @@ -22,5 +22,5 @@ * @author gnaegi, www.frentix.com * @date April. 2014 * ======================================================== -**//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h1 .small,h2 small,h2 .small,h3 small,h3 .small,h4 small,h4 .small,h5 small,h5 .small,h6 small,h6 .small,.h1 small,.h1 .small,.h2 small,.h2 .small,.h3 small,.h3 .small,.h4 small,.h4 .small,.h5 small,.h5 .small,.h6 small,.h6 .small{font-weight:normal;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,h1 .small,.h1 small,.h1 .small,h2 small,h2 .small,.h2 small,.h2 .small,h3 small,h3 .small,.h3 small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,h4 .small,.h4 small,.h4 .small,h5 small,h5 .small,.h5 small,.h5 .small,h6 small,h6 .small,.h6 small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width: 768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff}.bg-primary{background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ul ol,ol ul,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857}dt{font-weight:bold}dd{margin-left:0}.dl-horizontal dd:before,.dl-horizontal dd:after{content:" ";display:table}.dl-horizontal dd:after{clear:both}@media (min-width: 768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,.blockquote-reverse small:before,.blockquote-reverse .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,.blockquote-reverse small:after,.blockquote-reverse .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857}@font-face{font-family:'FontAwesome';src:url("../../font-awesome/fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../../font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../../font-awesome/fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../../font-awesome/fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_block_bottom,.o_block,.o_button_group,.o_header_with_buttons{margin-bottom:1em}.o_block_top,.o_block,.o_button_group{margin-top:1em}.o_block_large_bottom,.o_block_large{margin-bottom:2em}.o_block_large_top,.o_block_large{margin-top:2em}.o_block_inline,.o_block_inline_left,.o_block_inline_both,.o_block_inline_right{display:inline-block}.o_block_inline_left,.o_block_inline_both{margin-left:0.5em}.o_block_inline_right,.o_block_inline_both{margin-right:0.5em}.o_block_centered_wrapper{display:table;width:100%;height:100%}.o_block_centered_content{display:table-cell;vertical-align:middle;text-align:center}.o_block_imagebg{background-repeat:no-repeat;background-position:center;background-size:cover}.o_block_imagebg span{padding:2px;background-color:rgba(255,255,255,0.8)}.o_block_imagebg h1,.o_block_imagebg h2,.o_block_imagebg h3,.o_block_imagebg h4,.o_block_imagebg h5,.o_block_imagebg p{padding:2px;background-color:rgba(255,255,255,0.8);display:inline-block}.o_block_imagebg h1:after,.o_block_imagebg h2:after,.o_block_imagebg h3:after,.o_block_imagebg h4:after,.o_block_imagebg h5:after,.o_block_imagebg p:after{content:' ';display:block}.o_scrollblock,div.b_scrollblock{overflow-x:auto;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.o_button_group{text-align:center}.o_button_group a,.o_button_group input,.o_button_group button,.o_button_group .btn-group{margin-right:5px;margin-bottom:0.5em}.o_button_group a:last-child,.o_button_group input:last-child,.o_button_group button:last-child,.o_button_group .btn-group:last-child{margin-right:0}.o_button_group .btn-group a,.o_button_group .btn-group input,.o_button_group .btn-group button{margin-right:0;margin-bottom:0}.o_button_group .dropdown-menu{text-align:left}.o_button_group_left{text-align:left}.o_button_group_right{text-align:right}.o_button_group_top{margin-top:0}.o_header_with_buttons:before,.o_header_with_buttons:after{content:" ";display:table}.o_header_with_buttons:after{clear:both}.o_header_with_buttons h1,.o_header_with_buttons h2,.o_header_with_buttons h3,.o_header_with_buttons h4,.o_header_with_buttons h5,.o_header_with_buttons h6{display:inline-block}.o_header_with_buttons .o_button_group{margin-bottom:0;float:right}.o_header_with_buttons h1+.o_button_group{margin-top:28px}.o_header_with_buttons h2+.o_button_group{margin-top:24px}.o_header_with_buttons h3+.o_button_group{margin-top:20px}.o_header_with_buttons h4+.o_button_group{margin-top:10px}.o_header_with_buttons h5+.o_button_group{margin-top:6.66667px}.o_header_with_buttons h6+.o_button_group{margin-top:5px}#o_main_center .o_header_with_buttons h2+.o_button_group{margin-top:0}.panel-heading.o_header_with_buttons{margin-bottom:0}.panel-imagebg{background-repeat:no-repeat;background-position:center;background-size:cover}.panel-imagebg.panel-default>.panel-heading{background-color:rgba(255,255,255,0.8);border-bottom:transparent}.panel-imagebg .panel-body span{padding:2px;background-color:rgba(255,255,255,0.8)}.panel-placeholder{border-width:2px;border-style:dashed;border-color:#78acd9;border-radius:10px}.panel-placeholder .panel-body{padding:10px}.panel-placeholder .panel-body:nth-child(n+2){border-top:none}.panel-placeholder .panel-body h3:nth-child(1),.panel-placeholder .panel-body h4:nth-child(1),.panel-placeholder .panel-body h5:nth-child(1){margin-top:0}.panel-placeholder .panel-body .o_button_group{margin-bottom:0}.panel-placeholder .panel-heading{border-top-right-radius:8px;border-top-left-radius:8px;border-width:2px;border-style:dashed;border-color:#78acd9;border-top:none;border-left:none;border-right:none;color:#337ab7;font-weight:bold}.panel-placeholder .panel-footer{border-bottom-right-radius:8px;border-bottom-left-radius:8px;border-width:2px;border-style:dashed;border-color:#78acd9;border-bottom:none;border-left:none;border-right:none}.o_xsmall,.b_xsmall,p.b_xsmall,div.b_xsmall{font-size:12px}.o_small,.b_small,p.b_small,div.b_small{font-size:12px}.o_large,.b_large,p.b_large,div.b_large{font-size:18px}.o_xlarge,.b_xlarge,p.b_xlarge,div.b_xlarge{font-size:18px}.o_disabled,.b_disabled,p.b_disabled,div.b_disabled{color:#777 !important;cursor:default}.o_disabled:hover,.b_disabled:hover{color:#777 !important}.o_dimmed,.b_dimmed,p.b_dimmed,div.b_dimmed{opacity:0.4;filter:alpha(opacity=40)}.o_selected,.b_selected,p.b_selected,div.b_selected{font-weight:bold}.o_deleted,.b_deleted,p.b_deleted,div.b_deleted{text-decoration:line-through}.o_clickable{cursor:pointer}.o_ochre{color:#c8a959}.o_blue{color:#12223F}.o_undecorated:hover,.o_undecorated:focus,.o_disabled:hover,.b_disabled:hover,.o_disabled:focus,.b_disabled:focus{text-decoration:none}.o_copy_code,.b_copy_code,p.b_copy_code,div.b_copy_code,code,pre{overflow-x:auto;overflow-y:auto;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}.o_nowrap,.b_copy_code,p.b_copy_code,div.b_copy_code,code{white-space:nowrap}.o_titled_wrapper .o_content{margin-top:20px}.o_video,.o_video video,.b_video,.o_video_wrapper{display:inline-block;max-width:100%;height:auto;max-width:100%}.o_image,.o_image img,img,.b_image{display:inline-block;max-width:100%;height:auto;max-width:100%}.o_image_vertical_center_helper{display:inline-block;height:100%;vertical-align:middle}.o_image_vertical_center_helper+.o_image img{vertical-align:middle}.o_with_hyphens{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.o_info,.b_info,p.b_info,div.b_info{margin:20px 0;padding:20px;border-left:3px solid #777;background-color:#eee}.o_info h2,.o_info h3,.o_info h4,.o_info h5,.b_info h2,.b_info h3,.b_info h4,.b_info h5{color:#777}.o_note,.b_note,p.b_note,div.b_note{margin:20px 0;padding:20px;border-left:3px solid #31708f;background-color:#d9edf7}.o_note h2,.o_note h3,.o_note h4,.o_note h5,.b_note h2,.b_note h3,.b_note h4,.b_note h5{color:#31708f}.o_important,.b_important,p.b_important,div.b_important{margin:20px 0;padding:20px;border-left:3px solid #F4D000;background-color:#FFF1A4}.o_important h2,.o_important h3,.o_important h4,.o_important h5,.b_important h2,.b_important h3,.b_important h4,.b_important h5{color:#F4D000}.o_success,.b_success,p.b_success,div.b_success{margin:20px 0;padding:20px;border-left:3px solid #3c763d;background-color:#dff0d8}.o_success h2,.o_success h3,.o_success h4,.o_success h5,.b_success h2,.b_success h3,.b_success h4,.b_success h5{color:#3c763d}.o_warning,.b_warning,p.b_warning,div.b_warning{margin:20px 0;padding:20px;border-left:3px solid #8a6d3b;background-color:#fcf8e3}.o_warning h2,.o_warning h3,.o_warning h4,.o_warning h5,.b_warning h2,.b_warning h3,.b_warning h4,.b_warning h5{color:#8a6d3b}.o_error,.b_error,p.b_error,div.b_error{margin:20px 0;padding:20px;border-left:3px solid #a94442;background-color:#f2dede}.o_error h2,.o_error h3,.o_error h4,.o_error h5,.b_error h2,.b_error h3,.b_error h4,.b_error h5{color:#a94442}div.o_callout_overlay{position:fixed;top:0;left:0;width:100%;height:100%;zoom:1;background:#000;opacity:0;filter:alpha(opacity=0)}.o_alert_info{position:fixed;top:-100%;left:0;display:none;z-index:2000;width:100%;text-align:center}.o_alert_info .alert{position:relative;width:auto;margin:0 auto;text-align:left;-webkit-box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15);box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15)}.o_alert_info .alert .o_alert_close{float:right;color:#777}.o_alert_info .alert .o_alert_close:hover{color:#555}@media (min-width: 768px){.o_alert_info .alert{width:600px}}#o_msg_sticky,#o_msg_sticky_preview{position:relative;color:#a94442;background-color:#f2dede;border:1px solid #ebccd1;padding:10px 16px 10px 60px;min-height:40px;margin:-20px 0 20px 0}#o_msg_sticky .o_icon_info_msg,#o_msg_sticky_preview .o_icon_info_msg{position:absolute;left:10px;top:5px;font-size:40px}#o_msg_sticky.o_msg_sticky_fullscreen,#o_msg_sticky_preview.o_msg_sticky_fullscreen{margin-top:0}@media (min-width: 768px){.modal .o_modal_fullwidth{width:90%}}@media (min-width: 992px){.modal .o_modal_fullwidth{width:80%}}.modal .modal-header h4{color:#337ab7;font-weight:500;font-family:inherit;line-height:1.1}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857;color:#333;background-color:#fff}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}h1{color:#337ab7}h2{color:#337ab7}h3{color:#337ab7}h4{color:#337ab7}h5{color:#337ab7}h5{color:#337ab7}hr{border-top:1px solid #eee}.o_user_content_block a{color:#337ab7;text-decoration:none}.o_user_content_block a:hover,.o_user_content_block a:focus{color:#23527c;text-decoration:underline}.b_border_box,p.b_border_box,div.b_border_box{border:1px solid #777;padding:1em;border-top-right-radius:3px;border-top-left-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}table td{vertical-align:top}table.b_grid{width:99.5%;background:transparent;border-collapse:separate}table.b_grid td,table.b_grid th{padding:1px 5px;border:1px solid #777}table.b_grid thead td,table.b_grid th{background:#eee;font-weight:bold}table.b_border{width:99.5%;background:transparent;border-collapse:collapse}table.b_border td,table.b_border th{padding:1px 5px;border:1px solid #777}table.b_border thead td,table.b_border th{background:#eee;font-weight:bold}table.b_borderless{width:99.5%;background:transparent;border-collapse:separate}table.b_borderless td,table.b_borderless th{padding:1px 5px;border:0;font-weight:bold}table.b_full{width:99.5%}table.b_middle{background:transparent}table.b_middle td{vertical-align:middle}table.b_gray{border-collapse:collapse}table.b_gray td,table.b_gray th{padding:1px 5px;background:#eee;border:1px solid #fff}table.b_gray thead td,table.b_gray th{background:#d5d5d5;font-weight:bold}table.b_blue{border-collapse:collapse}table.b_blue td,table.b_blue th{padding:1px 5px;background:#d9edf7;border:1px solid #fff}table.b_blue thead td,table.b_blue th{background:#afd9ee;font-weight:bold}table.b_green{border-collapse:collapse}table.b_green td,table.b_green th{padding:1px 5px;background:#dff0d8;border:1px solid #fff}table.b_green thead td,table.b_green th{background:#c1e2b3;font-weight:bold}table.b_yellow{border-collapse:collapse}table.b_yellow td,table.b_yellow th{padding:1px 5px;background:#fcf8e3;border:1px solid #fff}table.b_yellow thead td,table.b_yellow th{background:#f7ecb5;font-weight:bold}table.b_red{border-collapse:collapse}table.b_red td,table.b_red th{padding:1px 5px;background:#f2dede;border:1px solid #fff}table.b_red thead td,table.b_red th{background:#e4b9b9;font-weight:bold}.b_align_normal{text-align:left}.b_align_center{text-align:center}.b_align_inverse{text-align:right}.b_align_justified{text-align:justify}a.b_link_extern{color:#337ab7}a.b_link_extern:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:""}a.b_link_mailto{color:#337ab7}a.b_link_mailto:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:""}a.b_link_forward{color:#337ab7}a.b_link_forward:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"ï¤"}img.b_float_left{float:left;margin:0 2em 2em 0}img.b_float_left_clear{clear:both;margin:0 2em 2em 0;display:block}img.b_float_right{float:right;margin:0 0 2em 2em}img.b_float_right_clear{clear:both;display:block;margin:0 0 2em auto}img.b_float_left_clear_nomargin{float:left;display:block;margin:0 0 0 0}img.b_centered{clear:both;display:block;margin:0 auto 2em auto}img.b_circle{border-radius:50%}img.b_with_border{border:1px solid #ddd;padding:3px;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}p.b_figure_title{margin:20px 0 5px 0;font-size:85%;font-family:inherit}p.b_figure_caption{clear:both;margin:5px 0 20px 0;font-size:85%;font-family:inherit}span.olatFlashMovieViewer{max-width:100% !important;border:none !important}.mejs__container,.mejs__mediaelement video,.mejs__layers div,.me_cannotplay{max-width:100%}.b_clear_float,p.b_clear_float,div.b_clear_float{clear:both}@media print{a[href]:after{content:""}#o_header_wrapper,#o_offcanvas_right,#o_navbar_wrapper,#o_footer_wrapper,#o_toplink,#o_main_left,#o_main_right,#o_main_toolbar,#jsMath_PrintWarning,.o_noti,.o_opener,.o_hide,.o_noprint{display:none !important}.o_print_break_avoid{page-break-inside:avoid}.o_print_break_before{page-break-before:always}.btn{display:none}.o_form textarea,.o_form .form-control.textarea_disabled{-webkit-print-color-adjust:exact;color-adjust:exact;background:#fff !important;height:auto !important;color:#000 !important;resize:none}#o_comment_form_link,.o_comments form{display:none !important}.o_avatar{display:none}body.o_dmz{background:white !important;-webkit-print-color-adjust:exact;color-adjust:exact}.modal-dialog{margin:0 !important;width:100% !important;height:100% !important;background:#fff !important;-webkit-print-color-adjust:exact;color-adjust:exact}.progress{page-break-inside:avoid;-webkit-print-color-adjust:exact;color-adjust:exact;background-color:rgba(0,0,0,0.1) !important;border:1px solid rgba(0,0,0,0.5)}.progress-bar{-webkit-print-color-adjust:exact;background-color:#000 !important;border:10px solid #000}.radial-progress{page-break-inside:avoid;-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#eee !important}.radial-progress .circle .mask .fill{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#000 !important}.radial-progress .inset{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#fff !important}body{margin:0}} +**//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h1 .small,h2 small,h2 .small,h3 small,h3 .small,h4 small,h4 .small,h5 small,h5 .small,h6 small,h6 .small,.h1 small,.h1 .small,.h2 small,.h2 .small,.h3 small,.h3 .small,.h4 small,.h4 .small,.h5 small,.h5 .small,.h6 small,.h6 .small{font-weight:normal;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,h1 .small,.h1 small,.h1 .small,h2 small,h2 .small,.h2 small,.h2 .small,h3 small,h3 .small,.h3 small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,h4 .small,.h4 small,.h4 .small,h5 small,h5 .small,.h5 small,.h5 .small,h6 small,h6 .small,.h6 small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width: 768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff}.bg-primary{background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ul ol,ol ul,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857}dt{font-weight:bold}dd{margin-left:0}.dl-horizontal dd:before,.dl-horizontal dd:after{content:" ";display:table}.dl-horizontal dd:after{clear:both}@media (min-width: 768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,.blockquote-reverse small:before,.blockquote-reverse .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,.blockquote-reverse small:after,.blockquote-reverse .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857}@font-face{font-family:'FontAwesome';src:url("../../font-awesome/fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../../font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../../font-awesome/fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../../font-awesome/fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_block_bottom,.o_block,.o_button_group,.o_header_with_buttons{margin-bottom:1em}.o_block_top,.o_block,.o_button_group{margin-top:1em}.o_block_small_bottom,.o_block_small{margin-bottom:0.5em}.o_block_small_top,.o_block_small{margin-top:0.5em}.o_block_large_bottom,.o_block_large{margin-bottom:2em}.o_block_large_top,.o_block_large{margin-top:2em}.o_block_inline,.o_block_inline_left,.o_block_inline_both,.o_block_inline_right{display:inline-block}.o_block_inline_left,.o_block_inline_both{margin-left:0.5em}.o_block_inline_right,.o_block_inline_both{margin-right:0.5em}.o_block_centered_wrapper{display:table;width:100%;height:100%}.o_block_centered_content{display:table-cell;vertical-align:middle;text-align:center}.o_block_imagebg{background-repeat:no-repeat;background-position:center;background-size:cover}.o_block_imagebg span{padding:2px;background-color:rgba(255,255,255,0.8)}.o_block_imagebg h1,.o_block_imagebg h2,.o_block_imagebg h3,.o_block_imagebg h4,.o_block_imagebg h5,.o_block_imagebg p{padding:2px;background-color:rgba(255,255,255,0.8);display:inline-block}.o_block_imagebg h1:after,.o_block_imagebg h2:after,.o_block_imagebg h3:after,.o_block_imagebg h4:after,.o_block_imagebg h5:after,.o_block_imagebg p:after{content:' ';display:block}.o_scrollblock,div.b_scrollblock{overflow-x:auto;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.o_button_group{text-align:center}.o_button_group a,.o_button_group input,.o_button_group button,.o_button_group .btn-group{margin-right:5px;margin-bottom:0.5em}.o_button_group a:last-child,.o_button_group input:last-child,.o_button_group button:last-child,.o_button_group .btn-group:last-child{margin-right:0}.o_button_group .btn-group a,.o_button_group .btn-group input,.o_button_group .btn-group button{margin-right:0;margin-bottom:0}.o_button_group .dropdown-menu{text-align:left}.o_button_group_left{text-align:left}.o_button_group_right{text-align:right}.o_button_group_top{margin-top:0}.o_header_with_buttons:before,.o_header_with_buttons:after{content:" ";display:table}.o_header_with_buttons:after{clear:both}.o_header_with_buttons h1,.o_header_with_buttons h2,.o_header_with_buttons h3,.o_header_with_buttons h4,.o_header_with_buttons h5,.o_header_with_buttons h6{display:inline-block}.o_header_with_buttons .o_button_group{margin-bottom:0;float:right}.o_header_with_buttons h1+.o_button_group{margin-top:28px}.o_header_with_buttons h2+.o_button_group{margin-top:24px}.o_header_with_buttons h3+.o_button_group{margin-top:20px}.o_header_with_buttons h4+.o_button_group{margin-top:10px}.o_header_with_buttons h5+.o_button_group{margin-top:6.66667px}.o_header_with_buttons h6+.o_button_group{margin-top:5px}#o_main_center .o_header_with_buttons h2+.o_button_group{margin-top:0}.panel-heading.o_header_with_buttons{margin-bottom:0}.o_button_textstyle:before{content:'['}.o_button_textstyle:after{content:']'}.panel-imagebg{background-repeat:no-repeat;background-position:center;background-size:cover}.panel-imagebg.panel-default>.panel-heading{background-color:rgba(255,255,255,0.8);border-bottom:transparent}.panel-imagebg .panel-body span{padding:2px;background-color:rgba(255,255,255,0.8)}.panel-placeholder{border-width:2px;border-style:dashed;border-color:#78acd9;border-radius:10px}.panel-placeholder .panel-body{padding:10px}.panel-placeholder .panel-body:nth-child(n+2){border-top:none}.panel-placeholder .panel-body h3:nth-child(1),.panel-placeholder .panel-body h4:nth-child(1),.panel-placeholder .panel-body h5:nth-child(1){margin-top:0}.panel-placeholder .panel-body .o_button_group{margin-bottom:0}.panel-placeholder .panel-heading{border-top-right-radius:8px;border-top-left-radius:8px;border-width:2px;border-style:dashed;border-color:#78acd9;border-top:none;border-left:none;border-right:none;color:#337ab7;font-weight:bold}.panel-placeholder .panel-footer{border-bottom-right-radius:8px;border-bottom-left-radius:8px;border-width:2px;border-style:dashed;border-color:#78acd9;border-bottom:none;border-left:none;border-right:none}.o_xsmall,.b_xsmall,p.b_xsmall,div.b_xsmall{font-size:12px}.o_small,.b_small,p.b_small,div.b_small{font-size:12px}.o_large,.b_large,p.b_large,div.b_large{font-size:18px}.o_xlarge,.b_xlarge,p.b_xlarge,div.b_xlarge{font-size:18px}.o_disabled,.b_disabled,p.b_disabled,div.b_disabled{color:#777 !important;cursor:default}.o_disabled:hover,.b_disabled:hover{color:#777 !important}.o_dimmed,.b_dimmed,p.b_dimmed,div.b_dimmed{opacity:.4;filter:alpha(opacity=40)}.o_selected,.b_selected,p.b_selected,div.b_selected{font-weight:bold}.o_deleted,.b_deleted,p.b_deleted,div.b_deleted{text-decoration:line-through}.o_highlight_on_hover:hover{background-color:#f5f5f5}.o_clickable{cursor:pointer}.o_ochre{color:#c8a959}.o_blue{color:#12223F}.o_undecorated:hover,.o_undecorated:focus,.o_disabled:hover,.b_disabled:hover,.o_disabled:focus,.b_disabled:focus{text-decoration:none}.o_copy_code,.b_copy_code,p.b_copy_code,div.b_copy_code,code,pre{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}.o_copy_code input,.o_copy_code textarea,.b_copy_code input,code input,pre input,.b_copy_code textarea,code textarea,pre textarea{border:0;width:95%;background:transparent}.o_nowrap,.b_copy_code,p.b_copy_code,div.b_copy_code,code{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.o_titled_wrapper .o_content{margin-top:20px}.o_video,.o_video video,.b_video,.o_video_wrapper{display:inline-block;max-width:100%;height:auto;max-width:100%}.o_image,.o_image img,img,.b_image{display:inline-block;max-width:100%;height:auto;max-width:100%}.o_figure_caption_bottom{display:inline-block;min-width:50%}.o_figure_caption_bottom figure{display:table}.o_figure_caption_bottom figcaption{display:table-caption;caption-side:bottom;font-size:90%;font-style:italic;text-align:center}.o_image_vertical_center_helper{display:inline-block;height:100%;vertical-align:middle}.o_image_vertical_center_helper+.o_image img{vertical-align:middle}.o_with_hyphens{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.o_info,.b_info,p.b_info,div.b_info{margin:20px 0;padding:20px;border-left:3px solid #777;background-color:#eee}.o_info h2,.o_info h3,.o_info h4,.o_info h5,.b_info h2,.b_info h3,.b_info h4,.b_info h5{color:#777}.o_note,.b_note,p.b_note,div.b_note{margin:20px 0;padding:20px;border-left:3px solid #31708f;background-color:#d9edf7}.o_note h2,.o_note h3,.o_note h4,.o_note h5,.b_note h2,.b_note h3,.b_note h4,.b_note h5{color:#31708f}.o_important,.b_important,p.b_important,div.b_important{margin:20px 0;padding:20px;border-left:3px solid #F4D000;background-color:#FFF1A4}.o_important h2,.o_important h3,.o_important h4,.o_important h5,.b_important h2,.b_important h3,.b_important h4,.b_important h5{color:#F4D000}.o_success,.b_success,p.b_success,div.b_success{margin:20px 0;padding:20px;border-left:3px solid #3c763d;background-color:#dff0d8}.o_success h2,.o_success h3,.o_success h4,.o_success h5,.b_success h2,.b_success h3,.b_success h4,.b_success h5{color:#3c763d}.o_warning,.b_warning,p.b_warning,div.b_warning{margin:20px 0;padding:20px;border-left:3px solid #8a6d3b;background-color:#fcf8e3}.o_warning h2,.o_warning h3,.o_warning h4,.o_warning h5,.b_warning h2,.b_warning h3,.b_warning h4,.b_warning h5{color:#8a6d3b}.o_error,.b_error,p.b_error,div.b_error{margin:20px 0;padding:20px;border-left:3px solid #a94442;background-color:#f2dede}.o_error h2,.o_error h3,.o_error h4,.o_error h5,.b_error h2,.b_error h3,.b_error h4,.b_error h5{color:#a94442}div.o_callout_overlay{position:fixed;top:0;left:0;width:100%;height:100%;zoom:1;background:#000;opacity:0;filter:alpha(opacity=0)}.o_alert_info{position:fixed;top:-100%;left:0;display:none;z-index:2000;width:100%;text-align:center}.o_alert_info .alert{position:relative;width:auto;margin:0 auto;text-align:left;-webkit-box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15);box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15)}.o_alert_info .alert .o_alert_close{float:right;color:#777}.o_alert_info .alert .o_alert_close:hover{color:#555}@media (min-width: 768px){.o_alert_info .alert{width:600px}}#o_msg_sticky,#o_msg_sticky_preview{position:relative;color:#a94442;background-color:#f2dede;border:1px solid #ebccd1;padding:10px 16px 10px 60px;min-height:40px;margin:-20px 0 20px 0}#o_msg_sticky .o_icon_info_msg,#o_msg_sticky_preview .o_icon_info_msg{position:absolute;left:10px;top:5px;font-size:40px}#o_msg_sticky.o_msg_sticky_fullscreen,#o_msg_sticky_preview.o_msg_sticky_fullscreen{margin-top:0}@media (min-width: 768px){.modal .o_modal_fullwidth{width:90%}}@media (min-width: 992px){.modal .o_modal_fullwidth{width:80%}}.modal .modal-header h4{color:#337ab7;font-weight:500;font-family:inherit;line-height:1.1}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857;color:#333;background-color:#fff}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}h1{color:#337ab7}h2{color:#337ab7}h3{color:#337ab7}h4{color:#337ab7}h5{color:#337ab7}h5{color:#337ab7}hr{border-top:1px solid #eee}.o_user_content_block a{color:#337ab7;text-decoration:none}.o_user_content_block a:hover,.o_user_content_block a:focus{color:#23527c;text-decoration:underline}.b_border_box,p.b_border_box,div.b_border_box{border:1px solid #777;padding:1em;border-top-right-radius:3px;border-top-left-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}table td{vertical-align:top}table.b_grid{width:99.5%;background:transparent;border-collapse:separate}table.b_grid td,table.b_grid th{padding:1px 5px;border:1px solid #777}table.b_grid thead td,table.b_grid th{background:#eee;font-weight:bold}table.b_border{width:99.5%;background:transparent;border-collapse:collapse}table.b_border td,table.b_border th{padding:1px 5px;border:1px solid #777}table.b_border thead td,table.b_border th{background:#eee;font-weight:bold}table.b_borderless{width:99.5%;background:transparent;border-collapse:separate}table.b_borderless td,table.b_borderless th{padding:1px 5px;border:0}table.b_borderless thead td,table.b_borderless th{font-weight:bold}table.b_full{width:99.5%}table.b_middle{background:transparent}table.b_middle td{vertical-align:middle}table.b_gray{border-collapse:collapse}table.b_gray td,table.b_gray th{padding:1px 5px;background:#eee;border:1px solid #fff}table.b_gray thead td,table.b_gray th{background:#d5d5d5;font-weight:bold}table.b_blue{border-collapse:collapse}table.b_blue td,table.b_blue th{padding:1px 5px;background:#d9edf7;border:1px solid #fff}table.b_blue thead td,table.b_blue th{background:#afd9ee;font-weight:bold}table.b_green{border-collapse:collapse}table.b_green td,table.b_green th{padding:1px 5px;background:#dff0d8;border:1px solid #fff}table.b_green thead td,table.b_green th{background:#c1e2b3;font-weight:bold}table.b_yellow{border-collapse:collapse}table.b_yellow td,table.b_yellow th{padding:1px 5px;background:#fcf8e3;border:1px solid #fff}table.b_yellow thead td,table.b_yellow th{background:#f7ecb5;font-weight:bold}table.b_red{border-collapse:collapse}table.b_red td,table.b_red th{padding:1px 5px;background:#f2dede;border:1px solid #fff}table.b_red thead td,table.b_red th{background:#e4b9b9;font-weight:bold}.b_align_normal{text-align:left}.b_align_center{text-align:center}.b_align_inverse{text-align:right}.b_align_justified{text-align:justify}a.b_link_extern{color:#337ab7}a.b_link_extern:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:""}a.b_link_mailto{color:#337ab7}a.b_link_mailto:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:""}a.b_link_forward{color:#337ab7}a.b_link_forward:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"ï¤"}img.b_float_left{float:left;margin:0 2em 2em 0}img.b_float_left_clear{clear:both;margin:0 2em 2em 0;display:block}img.b_float_right{float:right;margin:0 0 2em 2em}img.b_float_right_clear{clear:both;display:block;margin:0 0 2em auto}img.b_float_left_clear_nomargin{float:left;display:block;margin:0 0 0 0}img.b_centered{clear:both;display:block;margin:0 auto 2em auto}img.b_circle{border-radius:50%}img.b_with_border{border:1px solid #ddd;padding:3px;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}p.b_figure_title{margin:20px 0 5px 0;font-size:85%;font-family:inherit}p.b_figure_caption{clear:both;margin:5px 0 20px 0;font-size:85%;font-family:inherit}.b_clear_float,p.b_clear_float,div.b_clear_float{clear:both}figure.align-left{float:left}figure.align-right{float:right}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}img.align-left{float:left}img.align-right{float:right}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}figure.image.align-center{display:block;text-align:center}figure.image.align-left{float:none;display:block;text-align:left}figure.image.align-left figcaption{text-align:left}figure.image.align-right{float:none;display:block;text-align:right}figure.image.align-right figcaption{text-align:right}figure.image{margin:2em 0 2em 0;border:0;background:none}figure.image img.b_float_left,figure.image img.b_float_left_clear,figure.image img.b_float_right,figure.image img.b_float_right_clear,figure.image img.b_float_left_clear_nomargin,figure.image img.b_centered{float:none;display:inline-block;margin:0}figure.image figcaption{font-size:90%;font-style:italic}@media print{a[href]:after{content:""}#o_header_wrapper,#o_offcanvas_right,#o_navbar_wrapper,#o_footer_wrapper,#o_toplink,#o_main_left,#o_main_right,#o_main_toolbar,#jsMath_PrintWarning,.o_noti,.o_opener,.o_hide,.o_noprint{display:none !important}.o_print_break_avoid{page-break-inside:avoid}.o_print_break_before{page-break-before:always}.o_print_break_after{clear:both;page-break-after:always}.btn{display:none}.o_form textarea,.o_form .form-control.textarea_disabled{-webkit-print-color-adjust:exact;color-adjust:exact;background:#fff !important;height:auto !important;color:#000 !important;resize:none}#o_comment_form_link,.o_comments form{display:none !important}.o_avatar{display:none}body.o_dmz{background:white !important;-webkit-print-color-adjust:exact;color-adjust:exact}.modal-dialog{margin:0 !important;width:100% !important;height:100% !important;background:#fff !important;-webkit-print-color-adjust:exact;color-adjust:exact}.progress{page-break-inside:avoid;-webkit-print-color-adjust:exact;color-adjust:exact;background-color:rgba(0,0,0,0.1) !important;border:1px solid rgba(0,0,0,0.5)}.progress-bar{-webkit-print-color-adjust:exact;background-color:#000 !important;border:10px solid #000}.ui-slider.ui-slider-horizontal.ui-widget-content{-webkit-print-color-adjust:exact;color-adjust:exact;background:#f9f9f9 !important}.ui-slider.ui-slider-horizontal.ui-widget-content .ui-slider-handle{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#337ab7 !important}.radial-progress{page-break-inside:avoid;-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#eee !important}.radial-progress .circle .mask .fill{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#000 !important}.radial-progress .inset{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#fff !important}body{margin:0}table,figure,figure{page-break-inside:avoid}h1,h2,h3,h4,h5,h6{page-break-after:avoid}} /*# sourceMappingURL=content.css.map */ diff --git a/src/main/webapp/static/themes/light/content.css.map b/src/main/webapp/static/themes/light/content.css.map index 34ecd8bbdbca0f641ca855652f5daa121880d6dd..d2071e65979c73cb58eac138c37e4fdf4af74357 100644 --- a/src/main/webapp/static/themes/light/content.css.map +++ b/src/main/webapp/static/themes/light/content.css.map @@ -1,7 +1,7 @@ { "version": 3, -"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;+DAQA,IAAK,CACH,WAAW,CAAE,UAAU,CACvB,oBAAoB,CAAE,IAAI,CAC1B,wBAAwB,CAAE,IAAI,CAOhC,IAAK,CACH,MAAM,CAAE,CAAC,CAaX,0FAYQ,CACN,OAAO,CAAE,KAAK,CAQhB,2BAGM,CACJ,OAAO,CAAE,YAAY,CACrB,cAAc,CAAE,QAAQ,CAQ1B,qBAAsB,CACpB,OAAO,CAAE,IAAI,CACb,MAAM,CAAE,CAAC,CAQX,iBACS,CACP,OAAO,CAAE,IAAI,CAUf,CAAE,CACA,gBAAgB,CAAE,WAAW,CAO/B,gBACQ,CACN,OAAO,CAAE,CAAC,CAUZ,WAAY,CACV,aAAa,CAAE,UAAU,CAO3B,QACO,CACL,WAAW,CAAE,IAAI,CAOnB,GAAI,CACF,UAAU,CAAE,MAAM,CAQpB,EAAG,CACD,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,QAAQ,CAOlB,IAAK,CACH,UAAU,CAAE,IAAI,CAChB,KAAK,CAAE,IAAI,CAOb,KAAM,CACJ,SAAS,CAAE,GAAG,CAOhB,OACI,CACF,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,CAAC,CACd,QAAQ,CAAE,QAAQ,CAClB,cAAc,CAAE,QAAQ,CAG1B,GAAI,CACF,GAAG,CAAE,MAAM,CAGb,GAAI,CACF,MAAM,CAAE,OAAO,CAUjB,GAAI,CACF,MAAM,CAAE,CAAC,CAOX,cAAe,CACb,QAAQ,CAAE,MAAM,CAUlB,MAAO,CACL,MAAM,CAAE,QAAQ,CAOlB,EAAG,CACD,eAAe,CAAE,WAAW,CAC5B,UAAU,CAAE,WAAW,CACvB,MAAM,CAAE,CAAC,CAOX,GAAI,CACF,QAAQ,CAAE,IAAI,CAOhB,iBAGK,CACH,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAkBhB,qCAIS,CACP,KAAK,CAAE,OAAO,CACd,IAAI,CAAE,OAAO,CACb,MAAM,CAAE,CAAC,CAOX,MAAO,CACL,QAAQ,CAAE,OAAO,CAUnB,aACO,CACL,cAAc,CAAE,IAAI,CAWtB,yEAGqB,CACnB,kBAAkB,CAAE,MAAM,CAC1B,MAAM,CAAE,OAAO,CAOjB,qCACqB,CACnB,MAAM,CAAE,OAAO,CAOjB,gDACwB,CACtB,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CAQZ,KAAM,CACJ,WAAW,CAAE,MAAM,CAWrB,0CACoB,CAClB,UAAU,CAAE,UAAU,CACtB,OAAO,CAAE,CAAC,CASZ,+FACgD,CAC9C,MAAM,CAAE,IAAI,CASd,oBAAqB,CACnB,kBAAkB,CAAE,SAAS,CAC7B,eAAe,CAAE,WAAW,CAC5B,kBAAkB,CAAE,WAAW,CAC/B,UAAU,CAAE,WAAW,CASzB,kGACgD,CAC9C,kBAAkB,CAAE,IAAI,CAO1B,QAAS,CACP,MAAM,CAAE,iBAAiB,CACzB,MAAM,CAAE,KAAK,CACb,OAAO,CAAE,qBAAqB,CAQhC,MAAO,CACL,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CAOZ,QAAS,CACP,QAAQ,CAAE,IAAI,CAQhB,QAAS,CACP,WAAW,CAAE,IAAI,CAUnB,KAAM,CACJ,eAAe,CAAE,QAAQ,CACzB,cAAc,CAAE,CAAC,CAGnB,KACG,CACD,OAAO,CAAE,CAAC,sFClaZ,YAAa,CACT,kBAEQ,CACJ,UAAU,CAAE,sBAAsB,CAClC,KAAK,CAAE,eAAe,CACtB,UAAU,CAAE,eAAe,CAC3B,WAAW,CAAE,eAAe,CAGhC,WACU,CACN,eAAe,CAAE,SAAS,CAG9B,aAAc,CACV,OAAO,CAAE,mBAAmB,CAGhC,iBAAkB,CACd,OAAO,CAAE,oBAAoB,CAKjC,+CAC6B,CACzB,OAAO,CAAE,EAAE,CAGf,cACW,CACP,MAAM,CAAE,cAAc,CACtB,iBAAiB,CAAE,KAAK,CAG5B,KAAM,CACF,OAAO,CAAE,kBAAkB,CAG/B,MACI,CACA,iBAAiB,CAAE,KAAK,CAG5B,GAAI,CACA,SAAS,CAAE,eAAe,CAG9B,OAEG,CACC,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CAGb,KACG,CACC,gBAAgB,CAAE,KAAK,CAO3B,MAAO,CACH,UAAU,CAAE,eAAe,CAI/B,OAAQ,CACJ,OAAO,CAAE,IAAI,CAIb,+BAAS,CACL,gBAAgB,CAAE,eAAe,CAGzC,MAAO,CACH,MAAM,CAAE,cAAc,CAG1B,MAAO,CACH,eAAe,CAAE,mBAAmB,CAEpC,mBACG,CACC,gBAAgB,CAAE,eAAe,CAIrC,qCACG,CACC,MAAM,CAAE,yBAAyB,EC3F7C,CAAE,CCgEA,kBAAkB,CD/DE,UAAU,CCgE3B,eAAe,CDhEE,UAAU,CCiEtB,UAAU,CDjEE,UAAU,CAEhC,gBACQ,CC4DN,kBAAkB,CD3DE,UAAU,CC4D3B,eAAe,CD5DE,UAAU,CC6DtB,UAAU,CD7DE,UAAU,CAMhC,IAAK,CACH,SAAS,CAAE,IAAI,CACf,2BAA2B,CAAE,WAAa,CAG5C,IAAK,CACH,WAAW,CESkB,2CAAiB,CFR9C,SAAS,CG2Be,IAAI,CH1B5B,WAAW,CGsCa,OAAW,CHrCnC,KAAK,CEofmB,IAAW,CFnfnC,gBAAgB,CEkfM,IAAQ,CF9ehC,4BAGS,CACP,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,OAAO,CAClB,WAAW,CAAE,OAAO,CAMtB,CAAE,CACA,KAAK,CE2kB8B,OAAc,CF1kBjD,eAAe,CAAE,IAAI,CAErB,eACQ,CACN,KAAK,CEuZwB,OAAiB,CFtZ9C,eAAe,CGZK,SAAS,CHe/B,OAAQ,CIrDR,OAAO,CAAE,WAAW,CAEpB,OAAO,CAAE,iCAAiC,CAC1C,cAAc,CAAE,IAAI,CJ6DtB,MAAO,CACL,MAAM,CAAE,CAAC,CAMX,GAAI,CACF,cAAc,CAAE,MAAM,CAIxB,eAAgB,CKvEd,OAAO,CADuB,KAAK,CAEnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CL0Ed,YAAa,CACX,aAAa,CG2Ba,GAAG,CHrB/B,cAAe,CACb,OAAO,CGwoBqB,GAAG,CHvoB/B,WAAW,CG3Ba,OAAW,CH4BnC,gBAAgB,CEkbM,IAAQ,CFjb9B,MAAM,CAAE,cAA2B,CACnC,aAAa,CEnCgB,GAAwB,CD2HrD,kBAAkB,CAAE,oBAAW,CAC1B,aAAa,CAAE,oBAAW,CACvB,UAAU,CAAE,oBAAW,CIlL/B,OAAO,CL4FiB,YAAY,CK3FpC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CL8Fd,WAAY,CACV,aAAa,CAAE,GAAG,CAMpB,EAAG,CACD,UAAU,CEqFgB,IAAqB,CFpF/C,aAAa,CEoFa,IAAqB,CFnF/C,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,cAAoB,CAQlC,QAAS,CACP,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,GAAG,CACV,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,CAAC,CACV,QAAQ,CAAE,MAAM,CAChB,IAAI,CAAE,gBAAa,CACnB,MAAM,CAAE,CAAC,CAQT,kDACQ,CACN,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CACjB,IAAI,CAAE,IAAI,CM3Id,yCAC6B,CAC3B,WAAW,CH8Da,OAAO,CG7D/B,WAAW,CH8Da,GAAG,CG7D3B,WAAW,CH8Da,GAAG,CG7D3B,KAAK,CH8DmB,OAAO,CG5D/B,+OACO,CACL,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,KAAK,CJ0kB0B,IAAW,CItkB9C,oBAEQ,CACN,UAAU,CJ4KgB,IAAqB,CI3K/C,aAAa,CAAE,IAA2B,CAE1C,uHACO,CACL,SAAS,CAAE,GAAG,CAGlB,oBAEQ,CACN,UAAU,CAAE,IAA2B,CACvC,aAAa,CAAE,IAA2B,CAE1C,uHACO,CACL,SAAS,CAAE,GAAG,CAIlB,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGZxD,MAAQ,CAAE,SAAS,CHaO,IAA+B,CGZzD,MAAQ,CAAE,SAAS,CHaO,IAA6B,CGZvD,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGZxD,MAAQ,CAAE,SAAS,CHaO,IAAe,CGZzC,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGPxD,CAAE,CACA,MAAM,CAAE,QAA+B,CAGzC,KAAM,CACJ,aAAa,CJwIa,IAAqB,CIvI/C,SAAS,CAAE,IAA+B,CAC1C,WAAW,CAAE,GAAG,CAChB,WAAW,CAAE,GAAG,CAEhB,yBAAmC,CANrC,KAAM,CAOF,SAAS,CAAE,IAAuB,EAStC,YACO,CACL,SAAS,CAAE,GAAkD,CAG/D,UACM,CACJ,gBAAgB,CJ0aK,OAAiB,CIzatC,OAAO,CAAE,IAAI,CAIf,UAAqB,CAAE,UAAU,CAAE,IAAI,CACvC,WAAqB,CAAE,UAAU,CAAE,KAAK,CACxC,YAAqB,CAAE,UAAU,CAAE,MAAM,CACzC,aAAqB,CAAE,UAAU,CAAE,OAAO,CAC1C,YAAqB,CAAE,WAAW,CAAE,MAAM,CAG1C,eAAqB,CAAE,cAAc,CAAE,SAAS,CAChD,eAAqB,CAAE,cAAc,CAAE,SAAS,CAChD,gBAAqB,CAAE,cAAc,CAAE,UAAU,CAGjD,WAAY,CACV,KAAK,CJuf4B,IAAW,CKzlB5C,aAAW,CACT,KAAK,CLsnB4B,OAAc,CKpnBjD,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,aAAW,CACT,KAAK,CLwfgB,OAAmB,CKtf1C,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,UAAW,CACT,KAAK,CLofc,OAAgB,CKlfrC,iBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,aAAW,CACT,KAAK,CL0fgB,OAAmB,CKxf1C,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,YAAW,CACT,KAAK,CL4fe,OAAkB,CK1fxC,mBAAkB,CAChB,KAAK,CAAE,OAAmB,CD8G9B,WAAY,CAGV,KAAK,CAAE,IAAI,CErHX,WAAW,CACT,gBAAgB,CNsnBiB,OAAc,CMpnBjD,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,WAAW,CACT,gBAAgB,CNufG,OAAiB,CMrftC,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,QAAW,CACT,gBAAgB,CNmfC,OAAc,CMjfjC,eAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,WAAW,CACT,gBAAgB,CNyfG,OAAiB,CMvftC,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,UAAW,CACT,gBAAgB,CN2fE,OAAgB,CMzfpC,iBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CFiIzC,YAAa,CACX,cAAc,CAAE,GAAiC,CACjD,MAAM,CAAE,WAAmD,CAC3D,aAAa,CAAE,cAAmC,CAQpD,KACG,CACD,UAAU,CAAE,CAAC,CACb,aAAa,CAAE,IAA2B,CAC1C,uBACG,CACD,aAAa,CAAE,CAAC,CAYpB,cAAe,CAJb,YAAY,CAAE,CAAC,CACf,UAAU,CAAE,IAAI,CASlB,YAAa,CAVX,YAAY,CAAE,CAAC,CACf,UAAU,CAAE,IAAI,CAWhB,WAAW,CAAE,IAAI,CAEjB,eAAK,CACH,OAAO,CAAE,YAAY,CACrB,YAAY,CAAE,GAAG,CACjB,aAAa,CAAE,GAAG,CAKtB,EAAG,CACD,UAAU,CAAE,CAAC,CACb,aAAa,CJYa,IAAqB,CIVjD,KACG,CACD,WAAW,CH3Ha,OAAW,CG6HrC,EAAG,CACD,WAAW,CAAE,IAAI,CAEnB,EAAG,CACD,WAAW,CAAE,CAAC,CGvLd,gDACQ,CACN,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAEhB,uBAAQ,CACN,KAAK,CAAE,IAAI,CH8Lb,yBAA2C,CACzC,iBAAG,CACD,KAAK,CAAE,IAAI,CACX,KAAK,CAAE,KAA4B,CACnC,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,KAAK,CIlNrB,QAAQ,CAAE,MAAM,CAChB,aAAa,CAAE,QAAQ,CACvB,WAAW,CAAE,MAAM,CJmNjB,iBAAG,CACD,WAAW,CHmoBa,KAA4B,EGznB1D,qCAE0B,CACxB,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,eAA6B,CAE9C,WAAY,CACV,SAAS,CAAE,GAAG,CACd,cAAc,CAAE,SAAS,CAI3B,UAAW,CACT,OAAO,CAAE,SAAiD,CAC1D,MAAM,CAAE,QAAyB,CACjC,SAAS,CHomBoB,MAAsB,CGnmBnD,WAAW,CAAE,cAAkC,CAK7C,yEAAa,CACX,aAAa,CAAE,CAAC,CAMpB,oDAEO,CACL,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,GAAG,CACd,WAAW,CHlMW,OAAW,CGmMjC,KAAK,CJuV0B,IAAW,CIrV1C,yEAAS,CACP,OAAO,CAAE,aAAa,CAQ5B,yCACsB,CACpB,aAAa,CAAE,IAAI,CACnB,YAAY,CAAE,CAAC,CACf,YAAY,CAAE,cAAkC,CAChD,WAAW,CAAE,CAAC,CACd,UAAU,CAAE,KAAK,CAMf,+MAAS,CAAE,OAAO,CAAE,EAAE,CACtB,yMAAQ,CACN,OAAO,CAAE,aAAa,CAM5B,OAAQ,CACN,aAAa,CJhGa,IAAqB,CIiG/C,UAAU,CAAE,MAAM,CAClB,WAAW,CHrOa,OAAW,CQhErC,UAWC,CAVC,WAAW,CAAE,aAAa,CAC1B,GAAG,CAAE,+DAAgE,CACrE,GAAG,CAAE,wbAI8F,CAEnG,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CCVpB,OAAmB,CACjB,OAAO,CAAE,YAAY,CACrB,IAAI,CAAE,uCAA8E,CACpF,SAAS,CAAE,OAAO,CAClB,cAAc,CAAE,IAAI,CACpB,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CCJpC,+DAAiC,CAChC,aAAa,CAAE,GAAG,CAEnB,qCAA2B,CAC1B,UAAU,CAAE,GAAG,CAMhB,oCAA6C,CAC5C,aAAa,CAAE,GAAG,CAEnB,iCAAuC,CACtC,UAAU,CAAE,GAAG,CAMhB,+EAAiC,CAChC,OAAO,CAAE,YAAY,CAEtB,yCAA2C,CAE1C,WAAW,CAAE,KAAK,CAGnB,0CAA6C,CAE5C,YAAY,CAAE,KAAK,CAQpB,yBAA0B,CACzB,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CAEb,yBAA0B,CACzB,OAAO,CAAE,UAAU,CACnB,cAAc,CAAE,MAAM,CACtB,UAAU,CAAE,MAAM,CAInB,gBAAiB,CAChB,iBAAiB,CAAC,SAAS,CAC3B,mBAAmB,CAAE,MAAM,CAC3B,eAAe,CAAE,KAAK,CACtB,qBAAK,CACJ,OAAO,CAAE,GAAG,CACZ,gBAAgB,CXokBY,qBAAwB,CWjkBrD,sHACE,CACD,OAAO,CAAE,GAAG,CACZ,gBAAgB,CX8jBY,qBAAwB,CW7jBpD,OAAO,CAAE,YAAY,CACrB,0JAAQ,CACP,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAOjB,gCAA+B,CAE9B,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,MAAM,CAEf,kBAAkB,CAAE,wBAAwB,CAC5C,0BAA0B,CAAE,KAAK,CAIrC,eAAgB,CAEf,UAAU,CAAE,MAAM,CAClB,yFAA6B,CAC5B,YAAY,CAAE,GAAG,CACjB,aAAa,CAAE,KAAK,CACpB,qIAAa,CACZ,YAAY,CAAE,CAAC,CAIhB,+FAAiB,CAChB,YAAY,CAAE,CAAC,CACf,aAAa,CAAE,CAAC,CAGlB,8BAAe,CACd,UAAU,CAAE,IAAI,CAIlB,oBAAqB,CACpB,UAAU,CAAE,IAAI,CAEjB,qBAAsB,CACrB,UAAU,CAAE,KAAK,CAElB,mBAAoB,CACnB,UAAU,CAAE,CAAC,CJvGZ,0DACQ,CACN,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAEhB,4BAAQ,CACN,KAAK,CAAE,IAAI,CIuGd,2JAAuB,CACtB,OAAO,CAAE,YAAY,CAEtB,sCAAgB,CACf,aAAa,CAAE,CAAC,CAChB,KAAK,CAAE,KAAK,CAGb,yCAAoB,CAClB,UAAU,CAAE,IAA6B,CAE3C,yCAAoB,CAClB,UAAU,CAAE,IAA6B,CAE3C,yCAAoB,CAClB,UAAU,CX6De,IAAqB,CW3DhD,yCAAoB,CAClB,UAAU,CAAE,IAA2B,CAEzC,yCAAoB,CAClB,UAAU,CAAE,SAA2B,CAEzC,yCAAoB,CAClB,UAAU,CAAE,GAA2B,CAI1C,wDAA0D,CACzD,UAAU,CAAE,CAAC,CAGd,oCAAqC,CACpC,aAAa,CAAE,CAAC,CAGjB,cAAe,CACd,iBAAiB,CAAC,SAAS,CAC3B,mBAAmB,CAAE,MAAM,CAC3B,eAAe,CAAE,KAAK,CAEtB,2CAA+B,CAC9B,gBAAgB,CX6dY,qBAAwB,CW5dpD,aAAa,CAAE,WAAW,CAE3B,+BAAiB,CAChB,OAAO,CAAE,GAAG,CACZ,gBAAgB,CXwdY,qBAAwB,CWndtD,kBAAmB,CAClB,YAAY,CX8buB,GAAG,CW7btC,YAAY,CAAE,MAAM,CACpB,YAAY,CXgcuB,OAAwC,CW/b3E,aAAa,CX4buB,IAAI,CW1bxC,8BAAY,CACX,OAAO,CX6buB,IAAI,CW5blC,6CAAiB,CAChB,UAAU,CAAE,IAAI,CAEjB,4IAEgB,CACf,UAAU,CAAE,CAAC,CAGd,8CAAgB,CACf,aAAa,CAAE,CAAC,CAGlB,iCAAe,CACd,uBAAuB,CAAE,GAAwE,CACjG,sBAAsB,CAAE,GAAwE,CAChG,YAAY,CXuasB,GAAG,CWtarC,YAAY,CAAE,MAAM,CACpB,YAAY,CXyasB,OAAwC,CWxa1E,UAAU,CAAE,IAAI,CAChB,WAAW,CAAE,IAAI,CACjB,YAAY,CAAE,IAAI,CAClB,KAAK,CX+a8B,OAAc,CW9ajD,WAAW,CXmasB,IAAI,CWjatC,gCAAc,CACb,0BAA0B,CAAE,GAAwE,CACpG,yBAAyB,CAAE,GAAwE,CACnG,YAAY,CX2ZsB,GAAG,CW1ZrC,YAAY,CAAE,MAAM,CACpB,YAAY,CX6ZsB,OAAwC,CW5Z1E,aAAa,CAAE,IAAI,CACnB,WAAW,CAAE,IAAI,CACjB,YAAY,CAAE,IAAI,CASpB,2CAAqB,CACpB,SAAS,CX2WY,IAAgB,CWzWtC,uCAAmB,CAClB,SAAS,CXwWY,IAAgB,CWtWtC,uCAAmB,CAClB,SAAS,CX8YiB,IAAgB,CW5Y3C,2CAAqB,CACpB,SAAS,CX2YiB,IAAgB,CWvY3C,mDAAyB,CACxB,KAAK,CAAE,eAAoC,CAK3C,MAAM,CAAE,OAAO,CAJf,mCAAO,CACN,KAAK,CAAE,eAAoC,CAM7C,2CAAqB,CCpPnB,OAAO,CDqPS,GAAE,CClPlB,MAAM,CAAE,iBAA6B,CDqPvC,mDAAyB,CACxB,WAAW,CAAE,IAAI,CAGlB,+CAAuB,CACtB,eAAe,CAAE,YAAY,CAG9B,YAA2B,CAC1B,MAAM,CAAE,OAAO,CAIhB,QAAS,CAAE,KAAK,CAAE,OAAO,CACzB,OAAQ,CAAE,KAAK,CAAE,OAAO,CAKvB,iHAAgB,CACf,eAAe,CAAE,IAAI,CAKvB,gEAA2B,CAC1B,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,IAAI,CACd,WAAW,CVnOY,6CAAiD,CUoOxE,OAAO,CAAE,OAAO,CAChB,SAAS,CAAE,GAAG,CACd,KAAK,CVkiBsB,OAAO,CUjiBnC,gBAAgB,CVkiBY,OAAO,CUjiBlC,aAAa,CV5KY,GAAG,CUgL/B,yDAAqB,CACpB,WAAW,CAAE,MAAM,CAKnB,4BAAW,CACV,UAAU,CAAE,IAA2B,CAKzC,iDAAqD,CRnSnD,OAAO,CQoSgB,YAAY,CRnSnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CQmSb,SAAS,CAAE,IAAI,CAEhB,kCAAiC,CRvS/B,OAAO,CQwSgB,YAAY,CRvSnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CQuSb,SAAS,CAAE,IAAI,CAIhB,+BAAgC,CAC/B,OAAO,CAAE,YAAY,CAClB,MAAM,CAAE,IAAI,CACZ,cAAc,CAAE,MAAM,CACtB,4CAAgB,CACf,cAAc,CAAE,MAAM,CAK3B,eAAiC,CAChC,eAAe,CAAE,IAAI,CACrB,YAAY,CAAE,IAAI,CAClB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,IAAI,CEnUd,mCAAiB,CCChB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,cAAyC,CACtD,gBAAgB,CdifI,IAAa,CchfjC,uFAAe,CAAE,KAAK,CdulBY,IAAW,CazlB9C,mCAAiB,CCFhB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdmfI,OAAc,CclflC,uFAAe,CAAE,KAAK,CdmfA,OAAgB,CalfvC,uDAA2B,CCL1B,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdqfQ,OAAO,Ccpf/B,+HAAe,CAAE,KAAK,CdqfI,OAAO,CajflC,+CAAuB,CCRtB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdufM,OAAiB,CctfvC,+GAAe,CAAE,KAAK,CdufE,OAAmB,Cahf5C,+CAAuB,CCXtB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdyfM,OAAiB,CcxfvC,+GAAe,CAAE,KAAK,CdyfE,OAAmB,Ca/e5C,uCAAmB,CCdlB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,Cd2fK,OAAgB,Cc1frC,+FAAe,CAAE,KAAK,Cd2fC,OAAkB,Ca3e1C,qBAAsB,CACrB,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CAAE,IAAI,CAAE,CAAC,CACf,KAAK,CAAC,IAAI,CAAE,MAAM,CAAC,IAAI,CACvB,IAAI,CAAC,CAAC,CACN,UAAU,CAAE,IAAI,CDxBf,OAAO,CCyBS,CAAC,CDtBjB,MAAM,CAAE,gBAA6B,CC0BvC,aAAc,CACb,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,KAAK,CACV,IAAI,CAAE,CAAC,CACP,OAAO,CAAE,IAAI,CACZ,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,MAAM,CAElB,oBAAO,CACP,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAC,MAAM,CACb,UAAU,CAAE,IAAI,CduBhB,kBAAkB,CAAE,iCAAO,CACnB,UAAU,CAAE,iCAAO,CcrB3B,mCAAe,CACd,KAAK,CAAE,KAAK,CACZ,KAAK,Cb2iB2B,IAAW,Ca1iB3C,yCAAQ,CACP,KAAK,CbkkBe,IAAoB,Ca/jB1C,yBAAmC,CAdnC,oBAAO,CAgBH,KAAK,CZ0iBmB,KAAK,EYpiBnC,mCAAqC,CACpC,QAAQ,CAAE,QAAQ,CAClB,KAAK,CbgckB,OAAkB,Ca/bzC,gBAAgB,Cb8bK,OAAgB,Ca7brC,MAAM,CAAE,iBAA8B,CACtC,OAAO,CAAE,mBAAmG,CAC5G,UAAU,CAAE,IAAyB,CAErC,MAAM,CAAE,cAAgD,CAExD,qEAAiB,CAChB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,IAAgC,CACtC,GAAG,CAAE,GAAgC,CACrC,SAAS,CAAE,IAAyB,CAGrC,mFAA0B,CACzB,UAAU,CAAE,CAAC,CAOb,yBAAmC,CADpC,yBAAmB,CAEjB,KAAK,CAAE,GAAG,EAEX,yBAAmC,CAJpC,yBAAmB,CAKjB,KAAK,CAAE,GAAG,EAGZ,uBAAiB,CAChB,KAAK,Cb2hB8B,OAAc,Ca1hB/C,WAAW,CbwVgB,GAAqB,CavVlD,WAAW,CZ1Ba,OAAO,CY2B7B,WAAW,CZzBW,GAAG,CczE7B,qBAA0B,CAAC,UAAU,CAAG,+CAAgD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACnH,qBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,wBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,wBAA0B,CAAC,UAAU,CAAG,iDAAkD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACrH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,mBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,qBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,mBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,oBAA0B,CAAC,UAAU,CAAG,kDAAmD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACtH,qBAA0B,CAAC,UAAU,CAAG,yCAA0C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAC7G,sBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,+CAAgD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACnH,qBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,uBAA0B,CAAC,UAAU,CAAG,mDAAoD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACvH,kBAAwB,CAAC,UAAU,CAAG,2CAA4C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAC7G,oBAA0B,CAAC,UAAU,CAAG,wCAAyC,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CCA5G,IAAK,CACH,WAAW,ChBekB,2CAAiB,CgBd9C,SAAS,ChBekB,IAAe,CgBd1C,WAAW,ChBekB,OAAiB,CgBd9C,KAAK,ChB0fmB,IAAW,CgBzfnC,gBAAgB,ChBwfM,IAAQ,CgBrfhC,CAAE,CACA,KAAK,ChB8lB8B,OAAc,CgB7lBjD,eAAe,CAAE,IAAI,CAErB,eACQ,CACN,KAAK,ChB0awB,OAAiB,CgBza9C,eAAe,ChBSW,SAAS,CgBNrC,OAAQ,CdlCR,OAAO,CAAE,WAAW,CAEpB,OAAO,CAAE,iCAAiC,CAC1C,cAAc,CAAE,IAAI,CcoCtB,EAAG,CACF,KAAK,ChB+kB+B,OAAc,CgB7kBnD,EAAG,CACF,KAAK,ChB4kB+B,OAAc,CgB1kBnD,EAAG,CACF,KAAK,ChBykB+B,OAAc,CgBvkBnD,EAAG,CACF,KAAK,ChBskB+B,OAAc,CgBpkBnD,EAAG,CACF,KAAK,ChBmkB+B,OAAc,CgBjkBnD,EAAG,CACF,KAAK,ChBgkB+B,OAAc,CgB9jBnD,EAAG,CACF,UAAU,CAAE,cAA4C,CCtDxD,uBAAE,CACD,KAAK,CjBknB8B,OAAc,CiBjnBjD,eAAe,CAAE,IAAI,CACrB,2DACQ,CACP,KAAK,CjB+byB,OAAiB,CiB9b/C,eAAe,CjB8BY,SAAS,CiBAvC,6CAAgD,CAC/C,MAAM,CAAE,cAAsC,CAC9C,OAAO,CjBcwB,GAAG,CkBzDjC,uBAAuB,ClBwDM,GAAoB,CkBvDhD,sBAAsB,ClBuDM,GAAoB,CkBhDjD,0BAA0B,ClBgDG,GAAoB,CkB/ChD,yBAAyB,ClB+CG,GAAoB,CiBoBlD,QAAG,CACF,cAAc,CAAE,GAAG,CAGpB,YAAS,CACR,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,cAAiC,CAE1C,qCAAa,CACZ,UAAU,CjB0ZQ,IAAa,CiBzZ/B,WAAW,CAAE,IAAI,CAGnB,cAAW,CACV,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,mCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,cAAiC,CAE1C,yCAAa,CACZ,UAAU,CjB6YQ,IAAa,CiB5Y/B,WAAW,CAAE,IAAI,CAGnB,kBAAe,CACd,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,2CAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,CAAC,CACT,WAAW,CAAE,IAAI,CAGnB,YAAS,CACR,KAAK,CAAE,KAAK,CAEb,cAAW,CACV,UAAU,CAAE,WAAW,CACvB,iBAAG,CACF,cAAc,CAAE,MAAM,CAGxB,YAAS,CAhET,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBmbS,IAAa,CiBlbhC,MAAM,CAAE,cAA+B,CAExC,qCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CA2DlB,YAAS,CAnET,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBqbS,OAAc,CiBpbjC,MAAM,CAAE,cAA+B,CAExC,qCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CA8DlB,aAAU,CAtEV,eAAe,CAAE,QAAQ,CACzB,iCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBybW,OAAiB,CiBxbtC,MAAM,CAAE,cAA+B,CAExC,uCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAiElB,cAAW,CAzEX,eAAe,CAAE,QAAQ,CACzB,mCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjB2bW,OAAiB,CiB1btC,MAAM,CAAE,cAA+B,CAExC,yCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAoElB,WAAQ,CA5ER,eAAe,CAAE,QAAQ,CACzB,6BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjB6bU,OAAgB,CiB5bpC,MAAM,CAAE,cAA+B,CAExC,mCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAsGnB,eAAgB,CACf,UAAU,CAAE,IAAI,CAEjB,eAAgB,CACf,UAAU,CAAE,MAAM,CAEnB,gBAAiB,CAChB,UAAU,CAAE,KAAK,CAElB,kBAAmB,CAClB,UAAU,CAAC,OAAO,CAInB,eAAgB,CACf,KAAK,CjB8b+B,OAAc,CiB7blD,sBAAS,CHlLR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CG8KlC,aAAa,CAAE,KAAK,CACpB,OAAO,CE0Dc,GAAO,CFvD9B,eAAgB,CACf,KAAK,CjBsb+B,OAAc,CiBrblD,sBAAS,CH1LR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CGsLlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEmCW,GAAO,CF/B3B,gBAAiB,CAChB,KAAK,CjB6a+B,OAAc,CiB5alD,uBAAS,CHnMR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CG+LlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEoXM,GAAO,CF1WtB,gBAAiB,CAChB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,WAAW,CAEpB,sBAAuB,CACtB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,WAAW,CACnB,OAAO,CAAE,KAAK,CAEf,iBAAkB,CACjB,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,WAAW,CAEpB,uBAAwB,CACvB,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,YAAY,CAErB,+BAAgC,CAC/B,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,OAAO,CAEhB,cAAe,CACd,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,eAAe,CAExB,YAAa,CACZ,aAAa,CAAE,GAAG,CAEnB,iBAAkB,CACjB,MAAM,CAAE,cAAsC,CAC9C,OAAO,CjB9LwB,GAAG,CkB5DjC,uBAAuB,ClB2DM,GAAwB,CkB1DpD,sBAAsB,ClB0DM,GAAwB,CkBnDrD,0BAA0B,ClBmDG,GAAwB,CkBlDpD,yBAAyB,ClBkDG,GAAwB,CiB6MvD,gBAAiB,CAChB,MAAM,CAAE,YAAqD,CAC7D,SAAS,CAAE,GAAkD,CAC7D,WAAW,ChBtMc,OAAO,CgBwMjC,kBAAmB,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,YAAqD,CAC7D,SAAS,CAAE,GAAkD,CAC7D,WAAW,ChB5Mc,OAAO,CgBgNjC,yBAA0B,CACzB,SAAS,CAAE,eAAe,CAC1B,MAAM,CAAE,eAAe,CAExB,2EAA+E,CAC9E,SAAS,CAAE,IAAI,CAIhB,gDAAmD,CAClD,KAAK,CAAE,IAAI,CGrRZ,YAAa,CAGZ,aAAc,CACV,OAAO,CAAE,EAAE,CAIf,wLAYW,CACV,OAAO,CAAE,eAAe,CAIzB,oBAAqB,CACpB,iBAAiB,CAAG,KAAK,CAE1B,qBAAsB,CACrB,iBAAiB,CAAE,MAAM,CAI1B,IAAK,CACJ,OAAO,CAAE,IAAI,CAIb,wDACgC,CAC/B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,UAAU,CAAE,eAAe,CAC3B,MAAM,CAAE,eAAe,CACvB,KAAK,CAAE,eAAe,CACtB,MAAM,CAAE,IAAI,CAKd,qCACiB,CACf,OAAO,CAAE,eAAe,CAI1B,SAAU,CACT,OAAO,CAAE,IAAI,CAId,UAAW,CACV,UAAU,CAAE,gBAAgB,CAC5B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CAIpB,aAAc,CACb,MAAM,CAAE,YAAY,CACpB,KAAK,CAAE,eAAe,CACtB,MAAM,CAAE,eAAe,CACvB,UAAU,CAAE,eAAe,CAC3B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CAIpB,SAAU,CACT,iBAAiB,CAAG,KAAK,CACzB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACjB,gBAAgB,CAAE,0BAAyB,CAC3C,MAAM,CAAE,yBAAwB,CAEnC,aAAc,CACb,0BAA0B,CAAE,KAAK,CACjC,gBAAgB,CAAE,eAAe,CAEjC,MAAM,CAAE,eAAe,CAIxB,gBAAiB,CAChB,iBAAiB,CAAG,KAAK,CACzB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CACjC,oCAAoB,CACnB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CAElC,uBAAO,CACN,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CAInC,IAAK,CACJ,MAAM,CAAE,CAAC", -"sources": ["../../bootstrap/stylesheets/bootstrap/_normalize.scss","../../bootstrap/stylesheets/bootstrap/_print.scss","../../bootstrap/stylesheets/bootstrap/_scaffolding.scss","../../bootstrap/stylesheets/bootstrap/mixins/_vendor-prefixes.scss","_config.scss","../../bootstrap/stylesheets/bootstrap/_variables.scss","../../bootstrap/stylesheets/bootstrap/mixins/_tab-focus.scss","../../bootstrap/stylesheets/bootstrap/mixins/_image.scss","../../bootstrap/stylesheets/bootstrap/_type.scss","../../bootstrap/stylesheets/bootstrap/mixins/_text-emphasis.scss","../../bootstrap/stylesheets/bootstrap/mixins/_background-variant.scss","../../bootstrap/stylesheets/bootstrap/mixins/_clearfix.scss","../../bootstrap/stylesheets/bootstrap/mixins/_text-overflow.scss","../../font-awesome/scss/_path.scss","../../font-awesome/scss/_core.scss","modules/_helpers.scss","../../bootstrap/stylesheets/bootstrap/mixins/_opacity.scss","modules/_dialog.scss","modules/_mixins.scss","modules/_emoticons.scss","modules/_content.scss","modules/_content_embedded.scss","../../bootstrap/stylesheets/bootstrap/mixins/_border-radius.scss","../../font-awesome/scss/_variables.scss","modules/_print.scss"], +"mappings": "CAEA;;;;;;;;;;;;;;;;;;;;;;;;IAwBG,DC1BH,4DAA4D,AAQ5D,IAAK,CACH,WAAW,CAAE,UAAU,CACvB,oBAAoB,CAAE,IAAI,CAC1B,wBAAwB,CAAE,IAAI,CAOhC,IAAK,CACH,MAAM,CAAE,CAAC,CAaX,0FAYQ,CACN,OAAO,CAAE,KAAK,CAQhB,2BAGM,CACJ,OAAO,CAAE,YAAY,CACrB,cAAc,CAAE,QAAQ,CAQ1B,qBAAsB,CACpB,OAAO,CAAE,IAAI,CACb,MAAM,CAAE,CAAC,CAQX,iBACS,CACP,OAAO,CAAE,IAAI,CAUf,CAAE,CACA,gBAAgB,CAAE,WAAW,CAO/B,gBACQ,CACN,OAAO,CAAE,CAAC,CAUZ,WAAY,CACV,aAAa,CAAE,UAAU,CAO3B,QACO,CACL,WAAW,CAAE,IAAI,CAOnB,GAAI,CACF,UAAU,CAAE,MAAM,CAQpB,EAAG,CACD,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,QAAQ,CAOlB,IAAK,CACH,UAAU,CAAE,IAAI,CAChB,KAAK,CAAE,IAAI,CAOb,KAAM,CACJ,SAAS,CAAE,GAAG,CAOhB,OACI,CACF,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,CAAC,CACd,QAAQ,CAAE,QAAQ,CAClB,cAAc,CAAE,QAAQ,CAG1B,GAAI,CACF,GAAG,CAAE,MAAM,CAGb,GAAI,CACF,MAAM,CAAE,OAAO,CAUjB,GAAI,CACF,MAAM,CAAE,CAAC,CAOX,cAAe,CACb,QAAQ,CAAE,MAAM,CAUlB,MAAO,CACL,MAAM,CAAE,QAAQ,CAOlB,EAAG,CACD,eAAe,CAAE,WAAW,CAC5B,UAAU,CAAE,WAAW,CACvB,MAAM,CAAE,CAAC,CAOX,GAAI,CACF,QAAQ,CAAE,IAAI,CAOhB,iBAGK,CACH,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAkBhB,qCAIS,CACP,KAAK,CAAE,OAAO,CACd,IAAI,CAAE,OAAO,CACb,MAAM,CAAE,CAAC,CAOX,MAAO,CACL,QAAQ,CAAE,OAAO,CAUnB,aACO,CACL,cAAc,CAAE,IAAI,CAWtB,yEAGqB,CACnB,kBAAkB,CAAE,MAAM,CAC1B,MAAM,CAAE,OAAO,CAOjB,qCACqB,CACnB,MAAM,CAAE,OAAO,CAOjB,gDACwB,CACtB,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CAQZ,KAAM,CACJ,WAAW,CAAE,MAAM,CAWrB,0CACoB,CAClB,UAAU,CAAE,UAAU,CACtB,OAAO,CAAE,CAAC,CASZ,+FACgD,CAC9C,MAAM,CAAE,IAAI,CASd,oBAAqB,CACnB,kBAAkB,CAAE,SAAS,CAC7B,eAAe,CAAE,WAAW,CAC5B,kBAAkB,CAAE,WAAW,CAC/B,UAAU,CAAE,WAAW,CASzB,kGACgD,CAC9C,kBAAkB,CAAE,IAAI,CAO1B,QAAS,CACP,MAAM,CAAE,iBAAiB,CACzB,MAAM,CAAE,KAAK,CACb,OAAO,CAAE,qBAAqB,CAQhC,MAAO,CACL,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CAOZ,QAAS,CACP,QAAQ,CAAE,IAAI,CAQhB,QAAS,CACP,WAAW,CAAE,IAAI,CAUnB,KAAM,CACJ,eAAe,CAAE,QAAQ,CACzB,cAAc,CAAE,CAAC,CAGnB,KACG,CACD,OAAO,CAAE,CAAC,CCzaZ,qFAAqF,AAOrF,YAAa,CACT,kBAEQ,CACJ,UAAU,CAAE,sBAAsB,CAClC,KAAK,CAAE,eAAe,CACtB,UAAU,CAAE,eAAe,CAC3B,WAAW,CAAE,eAAe,CAGhC,WACU,CACN,eAAe,CAAE,SAAS,CAG9B,aAAc,CACV,OAAO,CAAE,mBAAmB,CAGhC,iBAAkB,CACd,OAAO,CAAE,oBAAoB,CAKjC,+CAC6B,CACzB,OAAO,CAAE,EAAE,CAGf,cACW,CACP,MAAM,CAAE,cAAc,CACtB,iBAAiB,CAAE,KAAK,CAG5B,KAAM,CACF,OAAO,CAAE,kBAAkB,CAG/B,MACI,CACA,iBAAiB,CAAE,KAAK,CAG5B,GAAI,CACA,SAAS,CAAE,eAAe,CAG9B,OAEG,CACC,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CAGb,KACG,CACC,gBAAgB,CAAE,KAAK,CAO3B,MAAO,CACH,UAAU,CAAE,eAAe,CAI/B,OAAQ,CACJ,OAAO,CAAE,IAAI,CAIb,+BAAS,CACL,gBAAgB,CAAE,eAAe,CAGzC,MAAO,CACH,MAAM,CAAE,cAAc,CAG1B,MAAO,CACH,eAAe,CAAE,mBAAmB,CAEpC,mBACG,CACC,gBAAgB,CAAE,eAAe,CAIrC,qCACG,CACC,MAAM,CAAE,yBAAyB,EC3F7C,CAAE,CCgEA,kBAAkB,CD/DE,UAAU,CCgE3B,eAAe,CDhEE,UAAU,CCiEtB,UAAU,CDjEE,UAAU,CAEhC,gBACQ,CC4DN,kBAAkB,CD3DE,UAAU,CC4D3B,eAAe,CD5DE,UAAU,CC6DtB,UAAU,CD7DE,UAAU,CAMhC,IAAK,CACH,SAAS,CAAE,IAAI,CACf,2BAA2B,CAAE,WAAa,CAG5C,IAAK,CACH,WAAW,CESkB,2CAAiB,CFR9C,SAAS,CG2Be,IAAI,CH1B5B,WAAW,CGsCa,OAAW,CHrCnC,KAAK,CEwgBmB,IAAW,CFvgBnC,gBAAgB,CEsgBM,IAAQ,CFlgBhC,4BAGS,CACP,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,OAAO,CAClB,WAAW,CAAE,OAAO,CAMtB,CAAE,CACA,KAAK,CEgmB8B,OAAc,CF/lBjD,eAAe,CAAE,IAAI,CAErB,eACQ,CACN,KAAK,CEqawB,OAAiB,CFpa9C,eAAe,CGZK,SAAS,CHe/B,OAAQ,CIrDR,OAAO,CAAE,WAAW,CAEpB,OAAO,CAAE,iCAAiC,CAC1C,cAAc,CAAE,IAAI,CJ6DtB,MAAO,CACL,MAAM,CAAE,CAAC,CAMX,GAAI,CACF,cAAc,CAAE,MAAM,CAIxB,eAAgB,CKvEd,OAAO,CADuB,KAAK,CAEnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CL0Ed,YAAa,CACX,aAAa,CG2Ba,GAAG,CHrB/B,cAAe,CACb,OAAO,CGwoBqB,GAAG,CHvoB/B,WAAW,CG3Ba,OAAW,CH4BnC,gBAAgB,CEscM,IAAQ,CFrc9B,MAAM,CAAE,cAA2B,CACnC,aAAa,CEnCgB,GAAwB,CD2HrD,kBAAkB,CAAE,oBAAW,CAC1B,aAAa,CAAE,oBAAW,CACvB,UAAU,CAAE,oBAAW,CIlL/B,OAAO,CL4FiB,YAAY,CK3FpC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CL8Fd,WAAY,CACV,aAAa,CAAE,GAAG,CAMpB,EAAG,CACD,UAAU,CEqFgB,IAAqB,CFpF/C,aAAa,CEoFa,IAAqB,CFnF/C,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,cAAoB,CAQlC,QAAS,CACP,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,GAAG,CACV,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,CAAC,CACV,QAAQ,CAAE,MAAM,CAChB,IAAI,CAAE,gBAAa,CACnB,MAAM,CAAE,CAAC,CAQT,kDACQ,CACN,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CACjB,IAAI,CAAE,IAAI,CM3Id,yCAC6B,CAC3B,WAAW,CH8Da,OAAO,CG7D/B,WAAW,CH8Da,GAAG,CG7D3B,WAAW,CH8Da,GAAG,CG7D3B,KAAK,CH8DmB,OAAO,CG5D/B,+OACO,CACL,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,KAAK,CJ8lB0B,IAAW,CI1lB9C,oBAEQ,CACN,UAAU,CJ4KgB,IAAqB,CI3K/C,aAAa,CAAE,IAA2B,CAE1C,uHACO,CACL,SAAS,CAAE,GAAG,CAGlB,oBAEQ,CACN,UAAU,CAAE,IAA2B,CACvC,aAAa,CAAE,IAA2B,CAE1C,uHACO,CACL,SAAS,CAAE,GAAG,CAIlB,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGZxD,MAAQ,CAAE,SAAS,CHaO,IAA+B,CGZzD,MAAQ,CAAE,SAAS,CHaO,IAA6B,CGZvD,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGZxD,MAAQ,CAAE,SAAS,CHaO,IAAe,CGZzC,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGPxD,CAAE,CACA,MAAM,CAAE,QAA+B,CAGzC,KAAM,CACJ,aAAa,CJwIa,IAAqB,CIvI/C,SAAS,CAAE,IAA+B,CAC1C,WAAW,CAAE,GAAG,CAChB,WAAW,CAAE,GAAG,CAEhB,yBAAmC,CANrC,KAAM,CAOF,SAAS,CAAE,IAAuB,EAStC,YACO,CACL,SAAS,CAAE,GAAkD,CAG/D,UACM,CACJ,gBAAgB,CJ8bK,OAAiB,CI7btC,OAAO,CAAE,IAAI,CAIf,UAAqB,CAAE,UAAU,CAAE,IAAI,CACvC,WAAqB,CAAE,UAAU,CAAE,KAAK,CACxC,YAAqB,CAAE,UAAU,CAAE,MAAM,CACzC,aAAqB,CAAE,UAAU,CAAE,OAAO,CAC1C,YAAqB,CAAE,WAAW,CAAE,MAAM,CAG1C,eAAqB,CAAE,cAAc,CAAE,SAAS,CAChD,eAAqB,CAAE,cAAc,CAAE,SAAS,CAChD,gBAAqB,CAAE,cAAc,CAAE,UAAU,CAGjD,WAAY,CACV,KAAK,CJ2gB4B,IAAW,CK7mB5C,aAAW,CACT,KAAK,CL2oB4B,OAAc,CKzoBjD,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,aAAW,CACT,KAAK,CL4gBgB,OAAmB,CK1gB1C,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,UAAW,CACT,KAAK,CLwgBc,OAAgB,CKtgBrC,iBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,aAAW,CACT,KAAK,CL8gBgB,OAAmB,CK5gB1C,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,YAAW,CACT,KAAK,CLghBe,OAAkB,CK9gBxC,mBAAkB,CAChB,KAAK,CAAE,OAAmB,CD8G9B,WAAY,CAGV,KAAK,CAAE,IAAI,CErHX,WAAW,CACT,gBAAgB,CN2oBiB,OAAc,CMzoBjD,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,WAAW,CACT,gBAAgB,CN2gBG,OAAiB,CMzgBtC,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,QAAW,CACT,gBAAgB,CNugBC,OAAc,CMrgBjC,eAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,WAAW,CACT,gBAAgB,CN6gBG,OAAiB,CM3gBtC,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,UAAW,CACT,gBAAgB,CN+gBE,OAAgB,CM7gBpC,iBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CFiIzC,YAAa,CACX,cAAc,CAAE,GAAiC,CACjD,MAAM,CAAE,WAAmD,CAC3D,aAAa,CAAE,cAAmC,CAQpD,KACG,CACD,UAAU,CAAE,CAAC,CACb,aAAa,CAAE,IAA2B,CAC1C,uBACG,CACD,aAAa,CAAE,CAAC,CAYpB,cAAe,CAJb,YAAY,CAAE,CAAC,CACf,UAAU,CAAE,IAAI,CASlB,YAAa,CAVX,YAAY,CAAE,CAAC,CACf,UAAU,CAAE,IAAI,CAWhB,WAAW,CAAE,IAAI,CAEjB,eAAK,CACH,OAAO,CAAE,YAAY,CACrB,YAAY,CAAE,GAAG,CACjB,aAAa,CAAE,GAAG,CAKtB,EAAG,CACD,UAAU,CAAE,CAAC,CACb,aAAa,CJYa,IAAqB,CIVjD,KACG,CACD,WAAW,CH3Ha,OAAW,CG6HrC,EAAG,CACD,WAAW,CAAE,IAAI,CAEnB,EAAG,CACD,WAAW,CAAE,CAAC,CGvLd,gDACQ,CACN,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAEhB,uBAAQ,CACN,KAAK,CAAE,IAAI,CH8Lb,yBAA2C,CACzC,iBAAG,CACD,KAAK,CAAE,IAAI,CACX,KAAK,CAAE,KAA4B,CACnC,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,KAAK,CIlNrB,QAAQ,CAAE,MAAM,CAChB,aAAa,CAAE,QAAQ,CACvB,WAAW,CAAE,MAAM,CJmNjB,iBAAG,CACD,WAAW,CHmoBa,KAA4B,EGznB1D,qCAE0B,CACxB,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,eAA6B,CAE9C,WAAY,CACV,SAAS,CAAE,GAAG,CACd,cAAc,CAAE,SAAS,CAI3B,UAAW,CACT,OAAO,CAAE,SAAiD,CAC1D,MAAM,CAAE,QAAyB,CACjC,SAAS,CHomBoB,MAAsB,CGnmBnD,WAAW,CAAE,cAAkC,CAK7C,yEAAa,CACX,aAAa,CAAE,CAAC,CAMpB,oDAEO,CACL,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,GAAG,CACd,WAAW,CHlMW,OAAW,CGmMjC,KAAK,CJ2W0B,IAAW,CIzW1C,yEAAS,CACP,OAAO,CAAE,aAAa,CAQ5B,yCACsB,CACpB,aAAa,CAAE,IAAI,CACnB,YAAY,CAAE,CAAC,CACf,YAAY,CAAE,cAAkC,CAChD,WAAW,CAAE,CAAC,CACd,UAAU,CAAE,KAAK,CAMf,+MAAS,CAAE,OAAO,CAAE,EAAE,CACtB,yMAAQ,CACN,OAAO,CAAE,aAAa,CAM5B,OAAQ,CACN,aAAa,CJhGa,IAAqB,CIiG/C,UAAU,CAAE,MAAM,CAClB,WAAW,CHrOa,OAAW,CQhErC,UAWC,CAVC,WAAW,CAAE,aAAa,CAC1B,GAAG,CAAE,+DAAgE,CACrE,GAAG,CAAE,wbAI8F,CAEnG,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CCVpB,OAAmB,CACjB,OAAO,CAAE,YAAY,CACrB,IAAI,CAAE,uCAA8E,CACpF,SAAS,CAAE,OAAO,CAClB,cAAc,CAAE,IAAI,CACpB,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CCJpC,+DAAiC,CAChC,aAAa,CAAE,GAAG,CAEnB,qCAA2B,CAC1B,UAAU,CAAE,GAAG,CAMhB,oCAA6C,CAC5C,aAAa,CAAE,KAAK,CAErB,iCAAuC,CACtC,UAAU,CAAE,KAAK,CAMlB,oCAA6C,CAC5C,aAAa,CAAE,GAAG,CAEnB,iCAAuC,CACtC,UAAU,CAAE,GAAG,CAMhB,+EAAiC,CAChC,OAAO,CAAE,YAAY,CAEtB,yCAA2C,CAE1C,WAAW,CAAE,KAAK,CAGnB,0CAA6C,CAE5C,YAAY,CAAE,KAAK,CAQpB,yBAA0B,CACzB,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CAEb,yBAA0B,CACzB,OAAO,CAAE,UAAU,CACnB,cAAc,CAAE,MAAM,CACtB,UAAU,CAAE,MAAM,CAInB,gBAAiB,CAChB,iBAAiB,CAAC,SAAS,CAC3B,mBAAmB,CAAE,MAAM,CAC3B,eAAe,CAAE,KAAK,CACtB,qBAAK,CACJ,OAAO,CAAE,GAAG,CACZ,gBAAgB,CX+kBY,qBAAwB,CW5kBrD,sHACE,CACD,OAAO,CAAE,GAAG,CACZ,gBAAgB,CXykBY,qBAAwB,CWxkBpD,OAAO,CAAE,YAAY,CACrB,0JAAQ,CACP,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAOjB,gCAA+B,CAE9B,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,MAAM,CAEf,kBAAkB,CAAE,wBAAwB,CAC5C,0BAA0B,CAAE,KAAK,CAIrC,eAAgB,CAEf,UAAU,CAAE,MAAM,CAClB,yFAA6B,CAC5B,YAAY,CAAE,GAAG,CACjB,aAAa,CAAE,KAAK,CACpB,qIAAa,CACZ,YAAY,CAAE,CAAC,CAIhB,+FAAiB,CAChB,YAAY,CAAE,CAAC,CACf,aAAa,CAAE,CAAC,CAGlB,8BAAe,CACd,UAAU,CAAE,IAAI,CAIlB,oBAAqB,CACpB,UAAU,CAAE,IAAI,CAEjB,qBAAsB,CACrB,UAAU,CAAE,KAAK,CAElB,mBAAoB,CACnB,UAAU,CAAE,CAAC,CJjHZ,0DACQ,CACN,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAEhB,4BAAQ,CACN,KAAK,CAAE,IAAI,CIiHd,2JAAuB,CACtB,OAAO,CAAE,YAAY,CAEtB,sCAAgB,CACf,aAAa,CAAE,CAAC,CAChB,KAAK,CAAE,KAAK,CAGb,yCAAoB,CAClB,UAAU,CAAE,IAA6B,CAE3C,yCAAoB,CAClB,UAAU,CAAE,IAA6B,CAE3C,yCAAoB,CAClB,UAAU,CXmDe,IAAqB,CWjDhD,yCAAoB,CAClB,UAAU,CAAE,IAA2B,CAEzC,yCAAoB,CAClB,UAAU,CAAE,SAA2B,CAEzC,yCAAoB,CAClB,UAAU,CAAE,GAA2B,CAI1C,wDAA0D,CACzD,UAAU,CAAE,CAAC,CAGd,oCAAqC,CACpC,aAAa,CAAE,CAAC,CAKhB,0BAAS,CAAC,OAAO,CAAC,GAAG,CACrB,yBAAQ,CAAC,OAAO,CAAC,GAAG,CAKrB,cAAe,CACd,iBAAiB,CAAC,SAAS,CAC3B,mBAAmB,CAAE,MAAM,CAC3B,eAAe,CAAE,KAAK,CAEtB,2CAA+B,CAC9B,gBAAgB,CXgeY,qBAAwB,CW/dpD,aAAa,CAAE,WAAW,CAE3B,+BAAiB,CAChB,OAAO,CAAE,GAAG,CACZ,gBAAgB,CX2dY,qBAAwB,CWtdtD,kBAAmB,CAClB,YAAY,CXgcuB,GAAG,CW/btC,YAAY,CAAE,MAAM,CACpB,YAAY,CXkcuB,OAAwC,CWjc3E,aAAa,CX8buB,IAAI,CW5bxC,8BAAY,CACX,OAAO,CX+buB,IAAI,CW9blC,6CAAiB,CAChB,UAAU,CAAE,IAAI,CAEjB,4IAEgB,CACf,UAAU,CAAE,CAAC,CAGd,8CAAgB,CACf,aAAa,CAAE,CAAC,CAGlB,iCAAe,CACd,uBAAuB,CAAE,GAAwE,CACjG,sBAAsB,CAAE,GAAwE,CAChG,YAAY,CXyasB,GAAG,CWxarC,YAAY,CAAE,MAAM,CACpB,YAAY,CX2asB,OAAwC,CW1a1E,UAAU,CAAE,IAAI,CAChB,WAAW,CAAE,IAAI,CACjB,YAAY,CAAE,IAAI,CAClB,KAAK,CXkb8B,OAAc,CWjbjD,WAAW,CXqasB,IAAI,CWnatC,gCAAc,CACb,0BAA0B,CAAE,GAAwE,CACpG,yBAAyB,CAAE,GAAwE,CACnG,YAAY,CX6ZsB,GAAG,CW5ZrC,YAAY,CAAE,MAAM,CACpB,YAAY,CX+ZsB,OAAwC,CW9Z1E,aAAa,CAAE,IAAI,CACnB,WAAW,CAAE,IAAI,CACjB,YAAY,CAAE,IAAI,CASpB,2CAAqB,CACpB,SAAS,CX6WY,IAAgB,CW3WtC,uCAAmB,CAClB,SAAS,CX0WY,IAAgB,CWxWtC,uCAAmB,CAClB,SAAS,CXgZiB,IAAgB,CW9Y3C,2CAAqB,CACpB,SAAS,CX6YiB,IAAgB,CWzY3C,mDAAyB,CACxB,KAAK,CAAE,eAAoC,CAK3C,MAAM,CAAE,OAAO,CAJf,mCAAO,CACN,KAAK,CAAE,eAAoC,CAM7C,2CAAqB,CCtQnB,OAAO,CDuQS,EAAE,CCpQlB,MAAM,CAAE,iBAA6B,CDuQvC,mDAAyB,CACxB,WAAW,CAAE,IAAI,CAGlB,+CAAuB,CACtB,eAAe,CAAE,YAAY,CAG9B,2BAA4B,CAC3B,gBAAgB,CX4N6B,OAAe,CWxN7D,YAA2B,CAC1B,MAAM,CAAE,OAAO,CAIhB,QAAS,CAAE,KAAK,CAAE,OAAO,CACzB,OAAQ,CAAE,KAAK,CAAE,OAAO,CAKvB,iHAAgB,CACf,eAAe,CAAE,IAAI,CAKvB,gEAA2B,CACxB,WAAW,CVxPY,6CAAiD,CUyPxE,OAAO,CAAE,OAAO,CAChB,SAAS,CAAE,GAAG,CACd,KAAK,CV6gBsB,OAAO,CU5gBnC,gBAAgB,CV6gBY,OAAO,CU5gBlC,aAAa,CVjMY,GAAG,CUmM5B,iIAAe,CACd,MAAM,CAAE,CAAC,CACT,KAAK,CAAE,GAAG,CACV,UAAU,CAAE,WAAW,CAK3B,yDAAqB,CACpB,WAAW,CAAE,MAAM,CACnB,QAAQ,CAAE,MAAM,CAChB,aAAa,CAAE,QAAQ,CAKvB,4BAAW,CACV,UAAU,CAAE,IAA2B,CAKzC,iDAAqD,CRhUnD,OAAO,CQiUgB,YAAY,CRhUnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CQgUb,SAAS,CAAE,IAAI,CAEhB,kCAAiC,CRpU/B,OAAO,CQqUgB,YAAY,CRpUnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CQoUb,SAAS,CAAE,IAAI,CAIhB,wBAAyB,CACxB,OAAO,CAAE,YAAY,CACrB,SAAS,CAAE,GAAG,CACd,+BAAO,CACN,OAAO,CAAE,KAAK,CAEf,mCAAW,CACV,OAAO,CAAE,aAAa,CACtB,YAAY,CAAE,MAAM,CACpB,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,MAAM,CAMpB,+BAAgC,CAC/B,OAAO,CAAE,YAAY,CAClB,MAAM,CAAE,IAAI,CACZ,cAAc,CAAE,MAAM,CACtB,4CAAgB,CACf,cAAc,CAAE,MAAM,CAK3B,eAAiC,CAChC,eAAe,CAAE,IAAI,CACrB,YAAY,CAAE,IAAI,CAClB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,IAAI,CEjXd,mCAAiB,CCChB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,cAAyC,CACtD,gBAAgB,CdqgBI,IAAa,CcpgBjC,uFAAe,CAAE,KAAK,Cd2mBY,IAAW,Ca7mB9C,mCAAiB,CCFhB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdugBI,OAAc,CctgBlC,uFAAe,CAAE,KAAK,CdugBA,OAAgB,CatgBvC,uDAA2B,CCL1B,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdygBQ,OAAO,CcxgB/B,+HAAe,CAAE,KAAK,CdygBI,OAAO,CargBlC,+CAAuB,CCRtB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,Cd2gBM,OAAiB,Cc1gBvC,+GAAe,CAAE,KAAK,Cd2gBE,OAAmB,CapgB5C,+CAAuB,CCXtB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,Cd6gBM,OAAiB,Cc5gBvC,+GAAe,CAAE,KAAK,Cd6gBE,OAAmB,CangB5C,uCAAmB,CCdlB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,Cd+gBK,OAAgB,Cc9gBrC,+FAAe,CAAE,KAAK,Cd+gBC,OAAkB,Ca/f1C,qBAAsB,CACrB,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CAAE,IAAI,CAAE,CAAC,CACf,KAAK,CAAC,IAAI,CAAE,MAAM,CAAC,IAAI,CACvB,IAAI,CAAC,CAAC,CACN,UAAU,CAAE,IAAI,CDxBf,OAAO,CCyBS,CAAC,CDtBjB,MAAM,CAAE,gBAA6B,CC0BvC,aAAc,CACb,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,KAAK,CACV,IAAI,CAAE,CAAC,CACP,OAAO,CAAE,IAAI,CACZ,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,MAAM,CAElB,oBAAO,CACP,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAC,MAAM,CACb,UAAU,CAAE,IAAI,CduBhB,kBAAkB,CAAE,iCAAO,CACnB,UAAU,CAAE,iCAAO,CcrB3B,mCAAe,CACd,KAAK,CAAE,KAAK,CACZ,KAAK,Cb+jB2B,IAAW,Ca9jB3C,yCAAQ,CACP,KAAK,CbslBe,IAAoB,CanlB1C,yBAAmC,CAdnC,oBAAO,CAgBH,KAAK,CZ0iBmB,KAAK,EYpiBnC,mCAAqC,CACpC,QAAQ,CAAE,QAAQ,CAClB,KAAK,CbodkB,OAAkB,CandzC,gBAAgB,CbkdK,OAAgB,CajdrC,MAAM,CAAE,iBAA8B,CACtC,OAAO,CAAE,mBAAmG,CAC5G,UAAU,CAAE,IAAyB,CAErC,MAAM,CAAE,cAAgD,CAExD,qEAAiB,CAChB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,IAAgC,CACtC,GAAG,CAAE,GAAgC,CACrC,SAAS,CAAE,IAAyB,CAGrC,mFAA0B,CACzB,UAAU,CAAE,CAAC,CAOb,yBAAmC,CADpC,yBAAmB,CAEjB,KAAK,CAAE,GAAG,EAEX,yBAAmC,CAJpC,yBAAmB,CAKjB,KAAK,CAAE,GAAG,EAGZ,uBAAiB,CAChB,KAAK,CbgjB8B,OAAc,Ca/iB/C,WAAW,CbsWgB,GAAqB,CarWlD,WAAW,CZ1Ba,OAAO,CY2B7B,WAAW,CZzBW,GAAG,CczE7B,qBAA0B,CAAC,UAAU,CAAG,+CAAgD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACnH,qBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,wBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,wBAA0B,CAAC,UAAU,CAAG,iDAAkD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACrH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,mBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,qBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,mBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,oBAA0B,CAAC,UAAU,CAAG,kDAAmD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACtH,qBAA0B,CAAC,UAAU,CAAG,yCAA0C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAC7G,sBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,+CAAgD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACnH,qBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,uBAA0B,CAAC,UAAU,CAAG,mDAAoD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACvH,kBAAwB,CAAC,UAAU,CAAG,2CAA4C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAC7G,oBAA0B,CAAC,UAAU,CAAG,wCAAyC,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CCA5G,IAAK,CACH,WAAW,ChBekB,2CAAiB,CgBd9C,SAAS,ChBekB,IAAe,CgBd1C,WAAW,ChBekB,OAAiB,CgBd9C,KAAK,ChB8gBmB,IAAW,CgB7gBnC,gBAAgB,ChB4gBM,IAAQ,CgBzgBhC,CAAE,CACA,KAAK,ChBmnB8B,OAAc,CgBlnBjD,eAAe,CAAE,IAAI,CAErB,eACQ,CACN,KAAK,ChBwbwB,OAAiB,CgBvb9C,eAAe,ChBSW,SAAS,CgBNrC,OAAQ,CdlCR,OAAO,CAAE,WAAW,CAEpB,OAAO,CAAE,iCAAiC,CAC1C,cAAc,CAAE,IAAI,CcoCtB,EAAG,CACF,KAAK,ChBomB+B,OAAc,CgBlmBnD,EAAG,CACF,KAAK,ChBimB+B,OAAc,CgB/lBnD,EAAG,CACF,KAAK,ChB8lB+B,OAAc,CgB5lBnD,EAAG,CACF,KAAK,ChB2lB+B,OAAc,CgBzlBnD,EAAG,CACF,KAAK,ChBwlB+B,OAAc,CgBtlBnD,EAAG,CACF,KAAK,ChBqlB+B,OAAc,CgBnlBnD,EAAG,CACF,UAAU,CAAE,cAA4C,CCtDxD,uBAAE,CACD,KAAK,CjBuoB8B,OAAc,CiBtoBjD,eAAe,CAAE,IAAI,CACrB,2DACQ,CACP,KAAK,CjB6cyB,OAAiB,CiB5c/C,eAAe,CjB8BY,SAAS,CiBAvC,6CAAgD,CAC/C,MAAM,CAAE,cAAsC,CAC9C,OAAO,CjBcwB,GAAG,CkBzDjC,uBAAuB,ClBwDM,GAAoB,CkBvDhD,sBAAsB,ClBuDM,GAAoB,CkBhDjD,0BAA0B,ClBgDG,GAAoB,CkB/ChD,yBAAyB,ClB+CG,GAAoB,CiBoBlD,QAAG,CACF,cAAc,CAAE,GAAG,CAGpB,YAAS,CACR,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,cAAiC,CAE1C,qCAAa,CACZ,UAAU,CjB8aQ,IAAa,CiB7a/B,WAAW,CAAE,IAAI,CAGnB,cAAW,CACV,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,mCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,cAAiC,CAE1C,yCAAa,CACZ,UAAU,CjBiaQ,IAAa,CiBha/B,WAAW,CAAE,IAAI,CAGnB,kBAAe,CACd,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,2CAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,CAAC,CAEV,iDAAa,CACZ,WAAW,CAAE,IAAI,CAGnB,YAAS,CACR,KAAK,CAAE,KAAK,CAEb,cAAW,CACV,UAAU,CAAE,WAAW,CACvB,iBAAG,CACF,cAAc,CAAE,MAAM,CAGxB,YAAS,CAlET,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBucS,IAAa,CiBtchC,MAAM,CAAE,cAA+B,CAExC,qCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CA6DlB,YAAS,CArET,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBycS,OAAc,CiBxcjC,MAAM,CAAE,cAA+B,CAExC,qCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAgElB,aAAU,CAxEV,eAAe,CAAE,QAAQ,CACzB,iCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjB6cW,OAAiB,CiB5ctC,MAAM,CAAE,cAA+B,CAExC,uCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAmElB,cAAW,CA3EX,eAAe,CAAE,QAAQ,CACzB,mCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjB+cW,OAAiB,CiB9ctC,MAAM,CAAE,cAA+B,CAExC,yCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAsElB,WAAQ,CA9ER,eAAe,CAAE,QAAQ,CACzB,6BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBidU,OAAgB,CiBhdpC,MAAM,CAAE,cAA+B,CAExC,mCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAwGnB,eAAgB,CACf,UAAU,CAAE,IAAI,CAEjB,eAAgB,CACf,UAAU,CAAE,MAAM,CAEnB,gBAAiB,CAChB,UAAU,CAAE,KAAK,CAElB,kBAAmB,CAClB,UAAU,CAAC,OAAO,CAInB,eAAgB,CACf,KAAK,CjBid+B,OAAc,CiBhdlD,sBAAS,CHpLR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CGgLlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEwDc,GAAO,CFrD9B,eAAgB,CACf,KAAK,CjByc+B,OAAc,CiBxclD,sBAAS,CH5LR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CGwLlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEiCW,GAAO,CF7B3B,gBAAiB,CAChB,KAAK,CjBgc+B,OAAc,CiB/blD,uBAAS,CHrMR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CGiMlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEkXM,GAAO,CFxWtB,gBAAiB,CAChB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,WAAW,CAEpB,sBAAuB,CACtB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,WAAW,CACnB,OAAO,CAAE,KAAK,CAEf,iBAAkB,CACjB,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,WAAW,CAEpB,uBAAwB,CACvB,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,YAAY,CAErB,+BAAgC,CAC/B,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,OAAO,CAEhB,cAAe,CACd,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,eAAe,CAExB,YAAa,CACZ,aAAa,CAAE,GAAG,CAEnB,iBAAkB,CACjB,MAAM,CAAE,cAAsC,CAC9C,OAAO,CjBhMwB,GAAG,CkB5DjC,uBAAuB,ClB2DM,GAAwB,CkB1DpD,sBAAsB,ClB0DM,GAAwB,CkBnDrD,0BAA0B,ClBmDG,GAAwB,CkBlDpD,yBAAyB,ClBkDG,GAAwB,CiB+MvD,gBAAiB,CAChB,MAAM,CAAE,YAAqD,CAC7D,SAAS,CAAE,GAAkD,CAC7D,WAAW,ChBxMc,OAAO,CgB0MjC,kBAAmB,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,YAAqD,CAC7D,SAAS,CAAE,GAAkD,CAC7D,WAAW,ChB9Mc,OAAO,CgBkNjC,gDAAmD,CAClD,KAAK,CAAE,IAAI,CGtRZ,iBAAkB,CACd,KAAK,CAAE,IAAI,CAGf,kBAAmB,CACf,KAAK,CAAE,KAAK,CAGhB,YAAa,CACT,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,cAAc,CACtB,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,OAAO,CAGvB,gBAAiB,CACb,MAAM,CAAE,aAAa,CAGzB,uBAAwB,CACpB,MAAM,CAAE,eAAe,CACvB,UAAU,CAAE,MAAM,CAOtB,cAAe,CACX,KAAK,CAAE,IAAI,CAGf,eAAgB,CACZ,KAAK,CAAE,KAAK,CAIhB,QAAS,CACL,MAAM,CAAE,cAAc,CAG1B,WAAY,CACR,MAAM,CAAE,GAAG,CAGf,WAAY,CACR,eAAe,CAAE,IAAI,CAQxB,yBAAe,CACd,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,MAAM,CAEnB,uBAAa,CACZ,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,IAAI,CAChB,kCAAW,CACV,UAAU,CAAE,IAAI,CAGlB,wBAAc,CACb,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,KAAK,CACjB,mCAAW,CACV,UAAU,CAAE,KAAK,CAMpB,YAAa,CACZ,MAAM,CAAE,WAAW,CAChB,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,IAAI,CAGlB,8MAKa,CACZ,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,CAAC,CAGX,uBAAW,CACV,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,MAAM,CCxFpB,YAAa,CAGZ,aAAc,CACV,OAAO,CAAE,EAAE,CAIf,wLAYW,CACV,OAAO,CAAE,eAAe,CAIzB,oBAAqB,CACpB,iBAAiB,CAAG,KAAK,CAE1B,qBAAsB,CACrB,iBAAiB,CAAE,MAAM,CAE1B,oBAAqB,CACpB,KAAK,CAAC,IAAI,CACV,gBAAgB,CAAC,MAAM,CAIxB,IAAK,CACJ,OAAO,CAAE,IAAI,CAIb,wDACgC,CAC/B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,UAAU,CAAE,eAAe,CAC3B,MAAM,CAAE,eAAe,CACvB,KAAK,CAAE,eAAe,CACtB,MAAM,CAAE,IAAI,CAKd,qCACiB,CACf,OAAO,CAAE,eAAe,CAI1B,SAAU,CACT,OAAO,CAAE,IAAI,CAId,UAAW,CACV,UAAU,CAAE,gBAAgB,CAC5B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CAIpB,aAAc,CACb,MAAM,CAAE,YAAY,CACpB,KAAK,CAAE,eAAe,CACtB,MAAM,CAAE,eAAe,CACvB,UAAU,CAAE,eAAe,CAC3B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CAIpB,SAAU,CACT,iBAAiB,CAAG,KAAK,CACzB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACjB,gBAAgB,CAAE,0BAAyB,CAC3C,MAAM,CAAE,yBAAwB,CAEnC,aAAc,CACb,0BAA0B,CAAE,KAAK,CACjC,gBAAgB,CAAE,eAAe,CAEjC,MAAM,CAAE,eAAe,CAIxB,iDAAkD,CACjD,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,UAAU,CAAE,kBAA+B,CAC3C,mEAAkB,CACjB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,kBAA6C,CAMjE,gBAAiB,CAChB,iBAAiB,CAAG,KAAK,CACzB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CACjC,oCAAoB,CACnB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CAElC,uBAAO,CACN,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CAInC,IAAK,CACJ,MAAM,CAAE,CAAC,CAGV,mBAAsB,CACpB,iBAAiB,CAAE,KAAK,CAG1B,iBAAuB,CACrB,gBAAgB,CAAE,KAAK", +"sources": ["_license.scss","../../bootstrap/stylesheets/bootstrap/_normalize.scss","../../bootstrap/stylesheets/bootstrap/_print.scss","../../bootstrap/stylesheets/bootstrap/_scaffolding.scss","../../bootstrap/stylesheets/bootstrap/mixins/_vendor-prefixes.scss","_config.scss","../../bootstrap/stylesheets/bootstrap/_variables.scss","../../bootstrap/stylesheets/bootstrap/mixins/_tab-focus.scss","../../bootstrap/stylesheets/bootstrap/mixins/_image.scss","../../bootstrap/stylesheets/bootstrap/_type.scss","../../bootstrap/stylesheets/bootstrap/mixins/_text-emphasis.scss","../../bootstrap/stylesheets/bootstrap/mixins/_background-variant.scss","../../bootstrap/stylesheets/bootstrap/mixins/_clearfix.scss","../../bootstrap/stylesheets/bootstrap/mixins/_text-overflow.scss","../../font-awesome/scss/_path.scss","../../font-awesome/scss/_core.scss","modules/_helpers.scss","../../bootstrap/stylesheets/bootstrap/mixins/_opacity.scss","modules/_dialog.scss","modules/_mixins.scss","modules/_emoticons.scss","modules/_content.scss","modules/_content_embedded.scss","../../bootstrap/stylesheets/bootstrap/mixins/_border-radius.scss","../../font-awesome/scss/_variables.scss","modules/_tinymce.scss","modules/_print.scss"], "names": [], "file": "content.css" } \ No newline at end of file diff --git a/src/main/webapp/static/themes/light/modules/_cal.scss b/src/main/webapp/static/themes/light/modules/_cal.scss index 07320a8bbcf778ea1bf120cc27e344a12e54de04..e7f51f93ef87497afe7e34c1e1e7cd8f43d07ac3 100644 --- a/src/main/webapp/static/themes/light/modules/_cal.scss +++ b/src/main/webapp/static/themes/light/modules/_cal.scss @@ -117,6 +117,17 @@ $o-cal-color-width : 20px; top: 0; } +.o_cal_wv_event_tooltip_content { + .o_cal_description { + background-color: $o-cal-desc-background-color; + padding: 10px 7px; + margin: 10px -7px; + } + .o_cal_tooltip_buttons { + text-align: center; + margin-top: 20px; + } +} /* * fullcalendar bootstrapify diff --git a/src/main/webapp/static/themes/light/modules/_citation.scss b/src/main/webapp/static/themes/light/modules/_citation.scss index bfeb01c83bc81b3cdb0bb7a8a4f5839616223d06..0eaa33913341068e750bad328df8b19c7967496e 100644 --- a/src/main/webapp/static/themes/light/modules/_citation.scss +++ b/src/main/webapp/static/themes/light/modules/_citation.scss @@ -6,7 +6,12 @@ color: $o-cit-quote-color; font-size: $o-cit-quote-font-size; margin-top: $padding-base-vertical; + margin-bottom: 0; padding: 0 $padding-base-horizontal; + /* override bootstrap default */ + font-style: italic; + padding: 5px 5px 0; + border: 0; p:last-child { &:after { @@ -119,25 +124,9 @@ /* Print styles */ @media print { - .cit { - background-image: none; - padding-top: 0; - max-width: 100%; - - #styles, - #refreshContainer { - display: none; - } - - #general-info a:after{ - content:" (" attr(href) ") "; - font-size:0.8em; - font-weight:normal; - } - - #copyright { - display: block; - margin-top: 30px; + .o_cit { + blockquote.o_quote { + page-break-inside: avoid; } } } \ No newline at end of file diff --git a/src/main/webapp/static/themes/light/modules/_content_embedded.scss b/src/main/webapp/static/themes/light/modules/_content_embedded.scss index 892044d1839a63d4f0ca3d3e6e13785d232f2b35..6280a901b0641ac0a7c63d64c4ef97d2ead4d837 100644 --- a/src/main/webapp/static/themes/light/modules/_content_embedded.scss +++ b/src/main/webapp/static/themes/light/modules/_content_embedded.scss @@ -114,6 +114,8 @@ table { td, th { padding: $padding-xs-vertical $padding-xs-horizontal; border: 0; + } + thead td, th { font-weight: bold; } } @@ -277,16 +279,12 @@ p.b_figure_caption { font-family: $headings-font-family; } -/* Movie player responsive fix. Must correspond with js code in player.js*/ -span.olatFlashMovieViewer { - max-width: 100% !important; - border: none !important; -} -.mejs__container, .mejs__mediaelement video, .mejs__layers div, .me_cannotplay { - max-width: 100%; -} - /* float clear classes */ .b_clear_float, p.b_clear_float, div.b_clear_float { clear: both; -} \ No newline at end of file +} + + +/* tinymce specific css classes for alignment, figures etc.*/ +@import "tinymce"; + diff --git a/src/main/webapp/static/themes/light/modules/_course.scss b/src/main/webapp/static/themes/light/modules/_course.scss index e8fca372cf0ec2fb100f627693d8904fdcbf5549..f7540a9814ed1c271755ebb199aaffbb2536ef67 100644 --- a/src/main/webapp/static/themes/light/modules/_course.scss +++ b/src/main/webapp/static/themes/light/modules/_course.scss @@ -275,4 +275,12 @@ height:auto; } - +/* Assessment tool */ +div.o_sel_correction_navigation { + text-align: center; + + #o_cocurrent_item_SELBOX { + display: inline-block; + } + +} diff --git a/src/main/webapp/static/themes/light/modules/_coursesite.scss b/src/main/webapp/static/themes/light/modules/_coursesite.scss index d4bf9d54ee17c7152b93e334473c5a7565979316..7dbba661a2db23b06cbd30e293601972f3b36f43 100644 --- a/src/main/webapp/static/themes/light/modules/_coursesite.scss +++ b/src/main/webapp/static/themes/light/modules/_coursesite.scss @@ -173,6 +173,10 @@ .o_lifecycle { position: absolute; top: 5px; right: 40px; + z-index: 2px; + background: white; + padding: 0 3px 3px 3px; + border-radius: 0px 0px $border-radius-small $border-radius-small; font-size: 90%; line-height: normal; @include text-overflow(); diff --git a/src/main/webapp/static/themes/light/modules/_evaluation_form.scss b/src/main/webapp/static/themes/light/modules/_evaluation_form.scss index 8234646b77bab8caf02d3687d1498f3ee11a466a..143cd28b3b30e1d8389d9db92b0cfdaf01902e71 100644 --- a/src/main/webapp/static/themes/light/modules/_evaluation_form.scss +++ b/src/main/webapp/static/themes/light/modules/_evaluation_form.scss @@ -1,7 +1,12 @@ .o_evaluation_form { - + .o_evaluation_block { + margin-top: $o-evaluation-block-margin-top; + margin-bottom: $o-evaluation-block-margin-bottom; + } + .o_evaluation_step_labels { margin-bottom: $o-evaluation-step-labels-margin-bottom; + font-weight: $o-evaluation-step-labels-font-weight; div, span { display:inline-block; @@ -57,8 +62,12 @@ } .o_evaluation_steps div.radio { + background-color: $o-evaluation-step-background-color; display:inline-block; text-align: center; + &:hover { + background-color: $o-evaluation-slider-hover-background-color; + } } } } @@ -69,10 +78,12 @@ .o_evaluation_left_label { text-align: right; + font-weight: $o-evaluation-side-labels-font-weight; } .o_evaluation_right_label { text-align: left; + font-weight: $o-evaluation-side-labels-font-weight; } .o_evaluation_textinput { @@ -146,4 +157,18 @@ right: 15px; } } +} + + +/* Print styles */ +@media print { + .o_evaluation_block { + page-break-inside : avoid; + } + .o_evaluation_discrete_radio .o_slider .o_evaluation_steps div.radio { + -webkit-print-color-adjust: exact; + color-adjust: exact; + background-color: $o-evaluation-step-background-color !important; + } + } \ No newline at end of file diff --git a/src/main/webapp/static/themes/light/modules/_form.scss b/src/main/webapp/static/themes/light/modules/_form.scss index 8474cc43540ae3567c48c3ae0656831acf0aea7f..ec2b66f66e36d037337b53e38f5b603f30171188 100644 --- a/src/main/webapp/static/themes/light/modules/_form.scss +++ b/src/main/webapp/static/themes/light/modules/_form.scss @@ -75,7 +75,7 @@ } .input-group.o_date_picker { - width: 16em; + width: 12em; } /* file chooser */ @@ -104,9 +104,9 @@ right: 38px; } } - - .has-feedback.has-error .o_fileinput .o_fakechooser { - margin-right:30px; + /* hide error icon for file element - clash with file element controls */ + .o_fileElement.has-error .o_icon_error.form-control-feedback { + display: none; } /* disabled text areas are rendered in div's for improved printing and layouting features */ @@ -163,7 +163,7 @@ line-height: $o-toggle-size; font-size: $o-toggle-size; text-align: left; - padding: 0 0.5em 0 0; + padding: 0 0.5em 0 1px; margin: 0; @extend %o_undecorated; @@ -180,7 +180,7 @@ } &.o_on { text-align: right; - padding: 0 0 0 0.5em; + padding: 0 1px 0 0.5em; i { color: $o-toggle-on-color; text-shadow: -1px 0 2px rgba(0,0,0,.25); diff --git a/src/main/webapp/static/themes/light/modules/_grouptask.scss b/src/main/webapp/static/themes/light/modules/_grouptask.scss index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d3e3bba6b50b66defa0b44b68564d99bc21f8376 100644 --- a/src/main/webapp/static/themes/light/modules/_grouptask.scss +++ b/src/main/webapp/static/themes/light/modules/_grouptask.scss @@ -0,0 +1,17 @@ +.o_gta_coach_selection { + .o_noti { + display:inline-block; + float: none; + margin: 0; + } + + .o_gta_coach_selection_bar { + position: relative; + + .o_noti { + position: absolute; + top: 3px; + right: 0; + } + } +} \ No newline at end of file diff --git a/src/main/webapp/static/themes/light/modules/_helpers.scss b/src/main/webapp/static/themes/light/modules/_helpers.scss index cf65c7bee3126675cd63ed215aeb84add27a86d8..c63193a6d6723554e410746efddc90e07428499d 100644 --- a/src/main/webapp/static/themes/light/modules/_helpers.scss +++ b/src/main/webapp/static/themes/light/modules/_helpers.scss @@ -13,6 +13,16 @@ @extend %o_block_top; @extend %o_block_bottom; } +.o_block_small_bottom, %o_block_small_bottom { + margin-bottom: 0.5em; +} +.o_block_small_top, %o_block_small_top { + margin-top: 0.5em; +} +.o_block_small, %o_block_small { + @extend %o_block_small_top; + @extend %o_block_small_bottom; +} .o_block_large_bottom, %o_block_large_bottom { margin-bottom: 2em; } @@ -156,6 +166,14 @@ margin-bottom: 0; } +/* minimized text-style buttons */ +.o_button_textstyle { + &:before {content:'['} + &:after {content:']'} +} + + + .panel-imagebg { background-repeat:no-repeat; background-position: center; @@ -256,6 +274,11 @@ .o_deleted, %o_deleted { text-decoration: line-through; } +/* highlight a row on hover event */ +.o_highlight_on_hover:hover { + background-color: $table-bg-hover; +} + /* clickable elements that should indicate this with a cursor change */ .o_clickable, %o_clickable { cursor: pointer; @@ -275,19 +298,25 @@ /* link or other copy&paste code blocks that might be to long for the screen (creates a scrollbar) */ .o_copy_code, %o_copy_code { - overflow-x: auto; - overflow-y: auto; font-family: $font-family-monospace; padding: 2px 4px; font-size: 90%; color: $code-color; background-color: $code-bg; border-radius: $border-radius-base; + + input,textarea { + border: 0; + width: 95%; + background: transparent; + } } /* text that should be on one line, e.g. in tables */ .o_nowrap, %o_nowrap { white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } /* titles with subtitles */ @@ -307,6 +336,23 @@ max-width: 100%; } +/* figures with captions */ +.o_figure_caption_bottom { + display: inline-block; + min-width: 50%; + figure { + display: table; + } + figcaption { + display: table-caption; + caption-side: bottom ; + font-size: 90%; + font-style: italic; + text-align: center; + } +} + + /* vertical centered helper */ .o_image_vertical_center_helper { display: inline-block; diff --git a/src/main/webapp/static/themes/light/modules/_icons.scss b/src/main/webapp/static/themes/light/modules/_icons.scss index 6cbe10dbed59ca6b591aa1ac95fb76e87181a598..b917b278be0e95784c62410b07587d543109a06c 100644 --- a/src/main/webapp/static/themes/light/modules/_icons.scss +++ b/src/main/webapp/static/themes/light/modules/_icons.scss @@ -1,3 +1,4 @@ + /* Load font-awesome library as we use font styles for the default icons */ $fa-font-path: "../../font-awesome/fonts" !default; /* we use fonts as icon base. In case you want to use bitmap icons instead, @@ -144,6 +145,7 @@ $fa-css-prefix: "o_icon" !default; .o_icon_lifecycle:before { content: $fa-var-power-off;} .o_icon_lifecycle_date:before { content: $fa-var-calendar;} .o_icon_locked:before { content: $fa-var-lock;} +.o_icon_log:before { content: $fa-var-file-text;} .o_icon_login:before { content: $fa-var-sign-in;} .o_icon_logout:before { content: $fa-var-sign-out;} .o_icon_mandatory:before { content: $fa-var-asterisk; color: #f0ad4e;} @@ -278,6 +280,7 @@ $fa-css-prefix: "o_icon" !default; .o_icon_table_large:before { content: $fa-var-th-large; } .o_icon_tags:before { content: $fa-var-tags; } .o_icon_textinput:before { content: $fa-var-align-left; } +.o_icon_time:before { content: $fa-var-clock-o; } .o_icon_timelimit:before { content: $fa-var-clock-o; } .o_icon_timelimit_start:before { content: $fa-var-hourglass-start; } .o_icon_timelimit_half:before { content: $fa-var-hourglass-half; } @@ -492,6 +495,9 @@ $fa-css-prefix: "o_icon" !default; .o_lectures_rollcall_warning:before { content: $fa-var-adjust; color: $brand-warning; } .o_lectures_rollcall_danger:before { content: $fa-var-circle-o; color: $brand-danger; } .o_lectures_rollcall_free:before { content: $fa-var-circle; color: #969696; } +.o_lectures_attended:before { content: $fa-var-circle; color: $brand-success; } +.o_lectures_authorized:before { content: $fa-var-circle; color: $brand-warning; } +.o_lectures_absent:before { content: $fa-var-circle; color: $brand-danger; } /* coaching */ .o_black_led:before { content: $fa-var-circle; color: $brand-primary; } diff --git a/src/main/webapp/static/themes/light/modules/_lecture.scss b/src/main/webapp/static/themes/light/modules/_lecture.scss index 3ab644dab454bc4e9af370a916fecac95dd16a94..3fd2089da4a6d6936d82038470525dc09569a7ca 100644 --- a/src/main/webapp/static/themes/light/modules/_lecture.scss +++ b/src/main/webapp/static/themes/light/modules/_lecture.scss @@ -4,14 +4,55 @@ } } -.o_lectures_teacher_overview .o_table_wrapper.o_table_flexi .table { - margin-top: 0; +.o_lectures_teacher_overview { + .o_table_wrapper.o_table_flexi .table { + margin-top: 0; + /* make cells with fixed width as small as possible */ + thead { + th.o_col_date, + th.o_col_startTime, + th.o_col_endTime, + th.o_col_details, + th.o_col_tools { + width: 1%; + } + + } + } + .o_lectures_current_wrapper { + border: 1px solid $o-lm-current-border-color; + background: $o-lm-current-bg; + border-radius: $o-lm-current-border-radius; + margin: 10px -10px 20px -10px; + padding: 10px; + + .o_button_group { + margin-bottom: 0; + } + } + .o_lectures_teacher_search .o_form .o_date { + padding-right: 10px; + position: relative; + } + + .o_lectures_teacher_search span.o_chelp_wrapper { + position: absolute; + top: 0; + right: 0; + } } -.o_lectures_teacher_overview .o_info { - margin-top: 0; +.o_lectures_rollcall { + legend { + margin-bottom: 10px; + } + + .o_desc, + .o_preparation { + margin: 0; + } + } - .o_lectures_print { } @@ -39,6 +80,10 @@ } } +.o_lecture_free { + color: $text-muted; +} + .o_rollcall_portrait>div { margin: 0 auto 10px auto; width: 100px; diff --git a/src/main/webapp/static/themes/light/modules/_portfolio_v2.scss b/src/main/webapp/static/themes/light/modules/_portfolio_v2.scss index 14f9bc3f981d6cf5a981d24a40577922dbf23a8e..0c116c32032151cd6b1e7cb5d884790327090a93 100644 --- a/src/main/webapp/static/themes/light/modules/_portfolio_v2.scss +++ b/src/main/webapp/static/themes/light/modules/_portfolio_v2.scss @@ -1,4 +1,5 @@ + .o_portfolio { div#o_main_toolbar.o_toolbar { margin-top: 0px; @@ -14,6 +15,11 @@ border: 1px $o-portfolio-lead-border-color solid; } +.o_section_ended .o_section_lead { + border-color: $o-portfolio-lead-ended-border-color; + background-color: $o-portfolio-lead-ended-background-color; +} + .o_section_lead.o_assignment_2_instantiate { border-radius: $o-portfolio-lead-border-radius $o-portfolio-lead-border-radius 0px 0px; border-bottom: none; @@ -28,12 +34,96 @@ border-right: 1px $o-portfolio-lead-border-color solid; } +.o_assignment_2_instantiate.o_section_ended { + border-color: $o-portfolio-lead-ended-border-color; + background-color: $o-portfolio-lead-ended-background-color; +} + .o_assignment_2_instantiate.last { padding-bottom: $o-portfolio-lead-space-sm; border-bottom: 1px $o-portfolio-lead-border-color solid; border-radius: 0px 0px $o-portfolio-lead-border-radius $o-portfolio-lead-border-radius; } +.o_assignment_2_instantiate.o_section_ended.last { + border-color: $o-portfolio-lead-ended-border-color; +} + +/* media positioning and sizes */ +.o_media { + &.o_media_right, + &.o_media_right_large { + float: right; + margin-left: 2em; + margin-bottom: 2em; + } + &.o_media_left, + &.o_media_left_large { + float: left; + margin-right: 2em; + margin-bottom: 2em; + } + &.o_media_left, + &.o_media_right { + max-height: 200px; + max-width: 50%; + img { + max-height: 200px; + } + } + &.o_media_right_large, + &.o_media_left_large { + max-height: 300px; + max-width: 75%; + img { + max-height: 300px; + } + } + img { + border-radius: $o-portfolio-lead-border-radius; + border: 1px $o-portfolio-lead-border-color solid; + background: #fff; + height: auto; /* expand to fit */ + width: auto; + } +} +@media (max-width: $screen-xs-max) { + .o_page_lead { + .o_media { + &.o_media_right, + &.o_media_right_large { + margin-left: 1em; + margin-bottom: 1em; + } + &.o_media_left, + &.o_media_left_large { + margin-right: 1em; + margin-bottom: 1em; + } + &.o_media_left, + &.o_media_right { + max-height: 120px; + max-width: 30%; + img { + max-height: 120px; + } + } + &.o_media_right_large, + &.o_media_left_large { + max-height: 180px; + max-width: 50%; + img { + max-height: 180px; + } + } + } + } +} +.o_portfolio_page .o_block_imagebg { + border: 1px $o-portfolio-lead-border-color solid; +} + + .o_page_lead { padding: $o-portfolio-lead-space-sm * 2; @@ -51,35 +141,6 @@ } .o_media { - &.o_media_right, - &.o_media_right_large { - float: right; - margin-left: 2em; - margin-bottom: 2em; - } - &.o_media_left, - &.o_media_left_large { - float: left; - margin-right: 2em; - margin-bottom: 2em; - } - &.o_media_left, - &.o_media_right { - max-height: 200px; - max-width: 50%; - img { - max-height: 200px; - } - } - &.o_media_right_large, - &.o_media_left_large { - max-height: 300px; - max-width: 75%; - img { - max-height: 300px; - } - } - &.o_desc_empty { /* when no content is there, show larger image and centered */ max-height: 300px; @@ -88,12 +149,6 @@ max-height: 300px; } } - - img { - border-radius: $o-portfolio-lead-border-radius; - border: 1px $o-portfolio-lead-border-color solid; - background: #fff; - } } .o_portfolio_status_block { @@ -115,7 +170,11 @@ } } -.o_page_assignment{ +.o_portfolio_status_block p.o_section_ended { + font-size: 120%; +} + +.o_page_assignment { font-size: $o-portfolio-assignment-font-size; &.o_togglebox_wrapper div.o_togglebox_content { margin: 10px 0 20px 0; @@ -129,6 +188,14 @@ } } +.o_page_export .o_page_assignment .o_opener, .o_binder_export .o_page_assignment .o_opener { + visibility:hidden; +} + +.o_page_export .o_page_assignment .o_closer, .o_binder_export .o_page_assignment .o_closer { + display: none; +} + .o_portfolio_listing.o_rendertype_custom { .o_table_body.container-fluid { @@ -186,25 +253,47 @@ .o_media { &.o_media_right, &.o_media_right_large { - float: right; - margin-left: 0.5em; - margin-bottom: 0.5em; + margin-left: 1em; + margin-bottom: 1em; } &.o_media_left, &.o_media_left_large { - float: left; - margin-right: 0.5em; - margin-bottom: 0.5em; + margin-right: 1em; + margin-bottom: 1em; + } + &.o_media_left, + &.o_media_right { + max-height: 150px; + img { + max-height: 150px; + } + } + &.o_media_right_large, + &.o_media_left_large { + max-height: 230px; + img { + max-height: 230px; + } } } } - .o_portfolio_categories { .tag { font-size: 80%; font-weight: normal; } + /* the categories edit form */ + div, form { + display: inline-block; + } +} + +.o_portfolio_categories_edit { + .bootstrap-tagsinput { + margin-bottom: 0; + padding: 0px 4px; + } } .o_portfolio_last_modified + .o_portfolio_categories, .o_portfolio_page_meta + .o_portfolio_categories { @@ -277,34 +366,71 @@ } .o_pf_comments { - margin-top: 2em; + margin-top: 3em; } .o_pf_content { - .o_cit, .o_file, { - @extend %o_block; + .o_cit, .o_text, .o_file { + @extend %o_block_large; background-color: $o-portfolio-media-content-background-color; padding: $o-portfolio-media-content-space; border-radius: $o-panel-placeholder-border-radius; } .o_forum { - @extend %o_block; + @extend %o_block_large; border: 1px $o-portfolio-media-content-background-color solid; padding: $o-portfolio-media-content-space; border-radius: $o-panel-placeholder-border-radius; } .o_image, .o_video { - @extend %o_block; + @extend %o_block_large; padding: $o-portfolio-media-content-space; - text-align: center; width: 100%; img { border: 1px $o-portfolio-media-content-background-color solid; border-radius: $o-panel-placeholder-border-radius; } + + .o_artefact_metadata { + text-align: left; + } + } + + .o_efficiencystatement, .o_feed, .o_forum, .o_wiki { + @extend %o_block_large; + background-color: $o-portfolio-media-content-background-color; + padding: $o-portfolio-media-content-space; + border-radius: $o-panel-placeholder-border-radius; + + h3, .h3 { font-size: $font-size-h5; } + + .row { + margin: 0; + } + + .o_block_with_datecomp { + margin-top: 0.5em; + margin-bottom: 0; + } + } + + +} + +.o_pf_video_placeholder { + background-color: $o-portfolio-media-content-background-color; + border: 1px solid $o-portfolio-media-content-background-color; + border-radius: $o-panel-placeholder-border-radius; + display: table; + min-width: 400px; + text-align: center; + padding: 40px 10px; + i { + display: table-cell; + vertical-align: middle; } } @@ -761,4 +887,104 @@ } } } -} \ No newline at end of file +} + +/* shift header sizes, OO starts with H2 */ +.o_ed_htitle { + h1, .h1 { font-size: $font-size-h2; } + h2, .h2 { font-size: $font-size-h3; } + h3, .h3 { font-size: $font-size-h4; } + h4, .h4 { font-size: $font-size-h5; } + h5, .h5 { font-size: $font-size-h6; } + h6, .h6 { font-size: $font-size-h6; } +} + +/* Print styles */ +@media print { + .o_binder h1 { + font-size: $font-size-h1 * 1.2; + margin-top: 10cm; + } + + .o_portfolio_section { + h3:first-of-type { + font-size: $font-size-h1; + } + margin-bottom: 1cm; + } + + .o_page_lead { + border: 0; + border-bottom: 1px solid $o-portfolio-lead-border-color; + border-radius: 0; + background-color: none; + padding: 0; + margin-bottom: $o-portfolio-lead-space-sm; + + .o_portfolio_status_block { + border-top: 0; + margin-bottom: 0; /* push at bottom of lead block */ + } + .o_media img { + border: 0; + } + .o_portfolio_categories { + display: block; + margin-left: 0; + } + .o_portfolio_status_block { + padding-top: 0; + } + .o_page_summary { + margin-top: 1em; + font-style: italic; + } + } + + .o_pf_content { + .o_cit, .o_text, .o_file, + .o_forum, + .o_image, .o_video, + .o_efficiencystatement, .o_feed, .o_forum, .o_wiki { + padding: 0; + border-radius: 0; + border: 0; + .o_desc { + p { + margin: 0; + } + } + } + + } + .o_efficiencystatement table { + font-size: 90%; + } + + .o_artefact_metadata { + page-break-inside : avoid; + border: 0; + border-left: 5px solid #eee; + padding-left: 10px; + font-size: 80%; + table { + td, th { + border: 0 !important; + padding: 2px !important; + } + th:first-of-type { + width: 20%; + } + } + } + + .o_pf_video_placeholder { + background-color: $o-portfolio-media-content-background-color !important; + -webkit-print-color-adjust: exact; + color-adjust: exact; + &.visible-print-block { + display: table !important; + } + } + +} diff --git a/src/main/webapp/static/themes/light/modules/_print.scss b/src/main/webapp/static/themes/light/modules/_print.scss index 68498a17024aec1a2b78d0fc9624d8e219668196..bff58bda539c59d9234957c791122f7efc159756 100644 --- a/src/main/webapp/static/themes/light/modules/_print.scss +++ b/src/main/webapp/static/themes/light/modules/_print.scss @@ -42,6 +42,10 @@ .o_print_break_before { page-break-before: always; } + .o_print_break_after { + clear:both; + page-break-after:always; + } /* Hide buttons in forms and print text area with full content */ .btn { @@ -103,6 +107,19 @@ border: 10px solid #000; } + /* Print backgrounds on sliders */ + .ui-slider.ui-slider-horizontal.ui-widget-content { + -webkit-print-color-adjust: exact; + color-adjust: exact; + background: $o-slider-background !important; + .ui-slider-handle { + -webkit-print-color-adjust: exact; + color-adjust: exact; + background-color: $o-slider-handler-background-color !important; + } + } + + /* Print background colors in radial progress bar */ .radial-progress { page-break-inside : avoid; @@ -124,7 +141,14 @@ body { margin: 0; } + + table, figure, figure { + page-break-inside: avoid; + } + h1, h2, h3, h4, h5, h6 { + page-break-after: avoid; + } } diff --git a/src/main/webapp/static/themes/light/modules/_qti21.scss b/src/main/webapp/static/themes/light/modules/_qti21.scss index 09eb98ed43c1e0a446f6a35de81faadd9895a612..d5b664edc2c8c94bdd55a856469d02b45cc1b18e 100644 --- a/src/main/webapp/static/themes/light/modules/_qti21.scss +++ b/src/main/webapp/static/themes/light/modules/_qti21.scss @@ -130,6 +130,20 @@ div.hotspotInteraction { overflow-x: auto; } +img.o_hotspot_responsive[usemap] { + max-width: 100%; + width: auto; + height: auto; +} + +/* Gap text / FIB */ +.form-inline.o_qti_gaptext_add_first_alternative { + padding: 9px 0 3px 0; +} + +.form-inline.o_qti_gaptext_add_alternative { + margin-bottom: 3px; +} /* Essay extended text */ #itemBody .extendedTextInteraction { @@ -227,11 +241,19 @@ div.hotspotInteraction { } -/* drawing */ +/* Drawing */ .o_draw_circle.o_qti_hotspot_correct, .o_draw_rectangle.o_qti_hotspot_correct { background-color: rgba(229, 255, 204, 0.6); } +#width_range_ui, #opacity_range_ui { + width: 120px; +} + +.o_slider_width_range, .o_slider_opacity_range { + margin: 3px 10px 0 0; +} + .o_qti_hotspot_label { padding-left: 48%; } @@ -244,6 +266,20 @@ div.hotspotInteraction { .o_info.o_assessmentsection_rubrics { margin:0 0 0.5em 0; + position: relative; + + &.o_hide { + display: none; + } + &.o_show { + display: block; + } + + a.o_hide { + position: absolute; + bottom: 0.5em; + right: 1em; + } } .o_assessmentitem{ @@ -287,60 +323,87 @@ div.hotspotInteraction { div.highlight { border: 1px solid $o-qti-highlight-color; } - - div.box { - background-color: $o-qti-box-bg; - } - - div.box span.info { - margin-left: 1em; - color: $o-qti-box-color; - font-style: italic; - font-size: smaller; + + div.box.vertical { + width: 50%; + float: left; + position: relative; + padding: 0; + margin-top: 5px; + + ul { + min-height: 200px; + } } - + div.box.horizontal { - margin: 0.5em 0; - width: 100%; + ul { + min-height: 50px; + width: 100%; + } } - - ul.horizontal { - float: left; - margin: 0 1em; - padding: 1em 0; - width: 100%; + + div.box.source { + padding: 5px 10px; + border: 1px solid $o-qti-order-sources-border-color; + border-radius: $o-qti-order-border-radius; + background: $o-qti-order-sources-bg; } - - div.box.vertical { - margin: 1em 0; - width: 49%; + + div.box.source.horizontal { + padding: 5px 10px 15px 10px; } - - div.box.vertical.source { - float: left; + + div.box.target { + ul { + border: 2px solid $o-qti-order-drop-accept-border-color; + border-radius: $o-qti-order-border-radius; + background: $o-qti-order-target-bg; + } } - - div.box.vertical.target { - float: right; + + div.box.target.vertical { + padding: 6px 0 0 10px; + + ul { + padding: 10px; + } } - - ul.vertical { - margin: 0 1em; - padding: 1em 0; + + div.box.target.horizontal { + padding-top: 10px; + + ul { + padding: 10px 10px 0 10px; + } + } + + div.box.horizontal ul li { + float: left; width: auto; + margin-right: 10px; + min-width: 50px; + } + + div.box span.info { + color: $o-qti-box-color; + font-style: italic; + font-size: smaller; } ul { list-style-type: none; margin: 0; padding: 0; - width: 60%; li { - margin: 0 3px 3px 3px; - padding: 0.4em; - padding-left: 1.5em; - font-size: 1em; + padding: 10px; + margin-bottom: 10px; + border: 2px $o-qti-order-source-border-style $o-qti-gap-border-color; + border-radius: $o-qti-order-border-radius; + background-color: #ffffff; + background: $o-qti-order-source-bg; + @include clearfix; span.ui-icon { position: absolute; @@ -348,15 +411,6 @@ div.hotspotInteraction { } } } - - ul.horizontal li { - float: left; - width: auto; - } - - br { - clear: both; - } } .hottext { @@ -399,7 +453,8 @@ div.hotspotInteraction { margin: -1px 2px; line-height: 90%; vertical-align: middle; - font-size: 98%; + font-size: ($font-size-base * 0.98); + line-height: 1.5; /* smaller than #itemBody */ border: 0.5px solid $o-qti-textEntryInteraction-border-color; background: $o-qti-textEntryInteraction-bg; padding: 0.5px 1px; @@ -433,7 +488,8 @@ div.hotspotInteraction { padding: $padding-small-vertical $padding-small-horizontal; border-left: 1px solid $o-qti-item-border-color; border-right: 1px solid $o-qti-item-border-color; - line-height: 1.5em; + font-size: $font-size-base; + line-height: 1.8; /* larger than .textEntryInteraction input */ } .modalFeedback { h4:first-of-type { @@ -1149,5 +1205,15 @@ ul.testPartDrilldown { text-align: right; @extend %o_small; } -} +} + +/* Editor */ +.o_sel_assessment_item_feedbacks { + min-height: 250px; +} + +.o_alternative_question_types h4 select { + display: inline-block; + width: auto; +} diff --git a/src/main/webapp/static/themes/light/modules/_rating_and_comments.scss b/src/main/webapp/static/themes/light/modules/_rating_and_comments.scss index b0fc9ea4784c870c52beac1e76915ff9f49f506e..648b65b0f15aee667ed326b8be2b807ee0432edb 100644 --- a/src/main/webapp/static/themes/light/modules/_rating_and_comments.scss +++ b/src/main/webapp/static/themes/light/modules/_rating_and_comments.scss @@ -6,9 +6,6 @@ white-space: nowrap; .o_icon { color:$brand-warning; - &:hover { - color: $brand-primary; - } } .o_legend { margin-left: 1em; @@ -21,6 +18,12 @@ } } } + &.o_rating_personal .o_rating_items { + .o_icon { + color: $brand-primary; + } + + } .o_rating_explanation { font-size: $font-size-small; color: $text-muted; diff --git a/src/main/webapp/static/themes/light/modules/_thirdparty.scss b/src/main/webapp/static/themes/light/modules/_thirdparty.scss index 26b6003666db950640cd166d70fbf2c961470e20..834f5a2713bd8277d20dac50045da1aa83ab933a 100644 --- a/src/main/webapp/static/themes/light/modules/_thirdparty.scss +++ b/src/main/webapp/static/themes/light/modules/_thirdparty.scss @@ -1,3 +1,4 @@ + /* * Overwrite jquery ui dialog and datepicker */ @@ -92,6 +93,7 @@ .ui-slider.ui-slider-horizontal.ui-widget-content { border-color: $o-slider-border; + background: $o-slider-background; &.ui-state-disabled { opacity: 0.65; @@ -188,7 +190,17 @@ label.mce-label { } } -i.mce-ico.mce-i-media, i.mce-ico.mce-i-movie, i.mce-ico.mce-i-help, i.mce-ico.mce-i-gaptext,i.mce-ico.mce-i-gapnumerical,i.mce-ico.mce-i-hottext, i.mce-ico.mce-i-edit { +.o_richtext_mce>.o_richtext_mce_modes { + text-align: right; + padding-right: $input-border-radius; + a { + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } +} + +i.mce-ico.mce-i-media, i.mce-ico.mce-i-movie, i.mce-ico.mce-i-help, i.mce-ico.mce-i-gaptext,i.mce-ico.mce-i-gapnumerical, i.mce-ico.mce-i-hottext, i.mce-ico.mce-i-edit { display: inline-block; font: normal normal normal #{$fa-font-size-base}/1 FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override @@ -233,13 +245,31 @@ i.mce-ico.mce-i-help:before { color: white; } - - .mce-tabs span.o_chelp_wrapper { float:right; margin:5px; } +.mce-wordcount:after { + display: inline-block; + font: normal normal normal #{$fa-font-size-base}/1 FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + transform: translate(0, 0); // ensures no half-pixel rendering in firefox + content: $fa-var-question-circle; +} + +.mce-danger .mce-wordcount:after { + color: $brand-danger; + content: $fa-var-exclamation-circle; +} + +.mce-statusbar.mce-danger { + background-color: $alert-danger-bg; +} + /* * Overwrite some class of typehead needed by the flexi table */ diff --git a/src/main/webapp/static/themes/light/modules/_tinymce.scss b/src/main/webapp/static/themes/light/modules/_tinymce.scss new file mode 100644 index 0000000000000000000000000000000000000000..8a7e08687add721e4fec17741b70bec2054c2f36 --- /dev/null +++ b/src/main/webapp/static/themes/light/modules/_tinymce.scss @@ -0,0 +1,105 @@ +/* + See https://www.tinymce.com/docs/advanced/boilerplate-content-css/ +*/ + +/* Image captions using the HTML5 figure element */ +figure.align-left { + float: left; +} + +figure.align-right { + float: right; +} + +figure.image { + display: inline-block; + border: 1px solid gray; + margin: 0 2px 0 1px; + background: #f5f2f0; +} + +figure.image img { + margin: 8px 8px 0 8px; +} + +figure.image figcaption { + margin: 6px 8px 6px 8px; + text-align: center; +} + +/* + Alignment using classes rather than inline styles + check out the "formats" option +*/ +img.align-left { + float: left; +} + +img.align-right { + float: right; +} + +/* Basic styles for Table of Contents plugin (toc) */ +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + + +/* END tiny defaults, now add OpenOLAT overrides and extensions */ + +/* add missing tiny styles */ +figure.image { + &.align-center { + display: block; + text-align: center; + } + &.align-left { + float: none; + display: block; + text-align: left; + figcaption { + text-align: left; + } + } + &.align-right { + float: none; + display: block; + text-align: right; + figcaption { + text-align: right; + } + } +} + +/* remove img styles when used within a figure element generated by tinymce */ +figure.image { + margin: 2em 0 2em 0; + border: 0; + background: none; + + img { + &.b_float_left, + &.b_float_left_clear, + &.b_float_right, + &.b_float_right_clear, + &.b_float_left_clear_nomargin, + &.b_centered { + float: none; + display: inline-block; + margin: 0; + } + } + figcaption { + font-size: 90%; + font-style: italic; + } +} + diff --git a/src/main/webapp/static/themes/openolat/content.css b/src/main/webapp/static/themes/openolat/content.css index c150ca182eeb154abb3dd79ff642e732b5d459a1..7c9fcc681f93679cc71e5b02d81afda00a6a9cc4 100644 --- a/src/main/webapp/static/themes/openolat/content.css +++ b/src/main/webapp/static/themes/openolat/content.css @@ -22,5 +22,5 @@ * @author gnaegi, www.frentix.com * @date April. 2014 * ======================================================== -**//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#3b678a;text-decoration:none}a:hover,a:focus{color:#243f54;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h1 .small,h2 small,h2 .small,h3 small,h3 .small,h4 small,h4 .small,h5 small,h5 .small,h6 small,h6 .small,.h1 small,.h1 .small,.h2 small,.h2 .small,.h3 small,.h3 .small,.h4 small,.h4 .small,.h5 small,.h5 .small,.h6 small,.h6 .small{font-weight:normal;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,h1 .small,.h1 small,.h1 .small,h2 small,h2 .small,.h2 small,.h2 .small,h3 small,h3 .small,.h3 small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,h4 .small,.h4 small,.h4 .small,h5 small,h5 .small,.h5 small,.h5 .small,h6 small,h6 .small,.h6 small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width: 768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#3b678a}a.text-primary:hover{color:#2c4c66}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff}.bg-primary{background-color:#3b678a}a.bg-primary:hover{background-color:#2c4c66}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ul ol,ol ul,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857}dt{font-weight:bold}dd{margin-left:0}.dl-horizontal dd:before,.dl-horizontal dd:after{content:" ";display:table}.dl-horizontal dd:after{clear:both}@media (min-width: 768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,.blockquote-reverse small:before,.blockquote-reverse .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,.blockquote-reverse small:after,.blockquote-reverse .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857}@font-face{font-family:'FontAwesome';src:url("../../font-awesome/fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../../font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../../font-awesome/fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../../font-awesome/fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_block_bottom,.o_block,.o_button_group,.o_header_with_buttons{margin-bottom:1em}.o_block_top,.o_block,.o_button_group{margin-top:1em}.o_block_large_bottom,.o_block_large{margin-bottom:2em}.o_block_large_top,.o_block_large{margin-top:2em}.o_block_inline,.o_block_inline_left,.o_block_inline_both,.o_block_inline_right{display:inline-block}.o_block_inline_left,.o_block_inline_both{margin-left:0.5em}.o_block_inline_right,.o_block_inline_both{margin-right:0.5em}.o_block_centered_wrapper{display:table;width:100%;height:100%}.o_block_centered_content{display:table-cell;vertical-align:middle;text-align:center}.o_block_imagebg{background-repeat:no-repeat;background-position:center;background-size:cover}.o_block_imagebg span{padding:2px;background-color:rgba(255,255,255,0.8)}.o_block_imagebg h1,.o_block_imagebg h2,.o_block_imagebg h3,.o_block_imagebg h4,.o_block_imagebg h5,.o_block_imagebg p{padding:2px;background-color:rgba(255,255,255,0.8);display:inline-block}.o_block_imagebg h1:after,.o_block_imagebg h2:after,.o_block_imagebg h3:after,.o_block_imagebg h4:after,.o_block_imagebg h5:after,.o_block_imagebg p:after{content:' ';display:block}.o_scrollblock,div.b_scrollblock{overflow-x:auto;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.o_button_group{text-align:center}.o_button_group a,.o_button_group input,.o_button_group button,.o_button_group .btn-group{margin-right:5px;margin-bottom:0.5em}.o_button_group a:last-child,.o_button_group input:last-child,.o_button_group button:last-child,.o_button_group .btn-group:last-child{margin-right:0}.o_button_group .btn-group a,.o_button_group .btn-group input,.o_button_group .btn-group button{margin-right:0;margin-bottom:0}.o_button_group .dropdown-menu{text-align:left}.o_button_group_left{text-align:left}.o_button_group_right{text-align:right}.o_button_group_top{margin-top:0}.o_header_with_buttons:before,.o_header_with_buttons:after{content:" ";display:table}.o_header_with_buttons:after{clear:both}.o_header_with_buttons h1,.o_header_with_buttons h2,.o_header_with_buttons h3,.o_header_with_buttons h4,.o_header_with_buttons h5,.o_header_with_buttons h6{display:inline-block}.o_header_with_buttons .o_button_group{margin-bottom:0;float:right}.o_header_with_buttons h1+.o_button_group{margin-top:28px}.o_header_with_buttons h2+.o_button_group{margin-top:24px}.o_header_with_buttons h3+.o_button_group{margin-top:20px}.o_header_with_buttons h4+.o_button_group{margin-top:10px}.o_header_with_buttons h5+.o_button_group{margin-top:6.66667px}.o_header_with_buttons h6+.o_button_group{margin-top:5px}#o_main_center .o_header_with_buttons h2+.o_button_group{margin-top:0}.panel-heading.o_header_with_buttons{margin-bottom:0}.panel-imagebg{background-repeat:no-repeat;background-position:center;background-size:cover}.panel-imagebg.panel-default>.panel-heading{background-color:rgba(255,255,255,0.8);border-bottom:transparent}.panel-imagebg .panel-body span{padding:2px;background-color:rgba(255,255,255,0.8)}.panel-placeholder{border-width:2px;border-style:dashed;border-color:#6b9ac0;border-radius:10px}.panel-placeholder .panel-body{padding:10px}.panel-placeholder .panel-body:nth-child(n+2){border-top:none}.panel-placeholder .panel-body h3:nth-child(1),.panel-placeholder .panel-body h4:nth-child(1),.panel-placeholder .panel-body h5:nth-child(1){margin-top:0}.panel-placeholder .panel-body .o_button_group{margin-bottom:0}.panel-placeholder .panel-heading{border-top-right-radius:8px;border-top-left-radius:8px;border-width:2px;border-style:dashed;border-color:#6b9ac0;border-top:none;border-left:none;border-right:none;color:#3b678a;font-weight:bold}.panel-placeholder .panel-footer{border-bottom-right-radius:8px;border-bottom-left-radius:8px;border-width:2px;border-style:dashed;border-color:#6b9ac0;border-bottom:none;border-left:none;border-right:none}.o_xsmall,.b_xsmall,p.b_xsmall,div.b_xsmall{font-size:12px}.o_small,.b_small,p.b_small,div.b_small{font-size:12px}.o_large,.b_large,p.b_large,div.b_large{font-size:18px}.o_xlarge,.b_xlarge,p.b_xlarge,div.b_xlarge{font-size:18px}.o_disabled,.b_disabled,p.b_disabled,div.b_disabled{color:#777 !important;cursor:default}.o_disabled:hover,.b_disabled:hover{color:#777 !important}.o_dimmed,.b_dimmed,p.b_dimmed,div.b_dimmed{opacity:0.4;filter:alpha(opacity=40)}.o_selected,.b_selected,p.b_selected,div.b_selected{font-weight:bold}.o_deleted,.b_deleted,p.b_deleted,div.b_deleted{text-decoration:line-through}.o_clickable{cursor:pointer}.o_ochre{color:#c8a959}.o_blue{color:#12223F}.o_undecorated:hover,.o_undecorated:focus,.o_disabled:hover,.b_disabled:hover,.o_disabled:focus,.b_disabled:focus{text-decoration:none}.o_copy_code,.b_copy_code,p.b_copy_code,div.b_copy_code,code,pre{overflow-x:auto;overflow-y:auto;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}.o_nowrap,.b_copy_code,p.b_copy_code,div.b_copy_code,code{white-space:nowrap}.o_titled_wrapper .o_content{margin-top:20px}.o_video,.o_video video,.b_video,.o_video_wrapper{display:inline-block;max-width:100%;height:auto;max-width:100%}.o_image,.o_image img,img,.b_image{display:inline-block;max-width:100%;height:auto;max-width:100%}.o_image_vertical_center_helper{display:inline-block;height:100%;vertical-align:middle}.o_image_vertical_center_helper+.o_image img{vertical-align:middle}.o_with_hyphens{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.o_info,.b_info,p.b_info,div.b_info{margin:20px 0;padding:20px;border-left:3px solid #777;background-color:#eee}.o_info h2,.o_info h3,.o_info h4,.o_info h5,.b_info h2,.b_info h3,.b_info h4,.b_info h5{color:#777}.o_note,.b_note,p.b_note,div.b_note{margin:20px 0;padding:20px;border-left:3px solid #31708f;background-color:#d9edf7}.o_note h2,.o_note h3,.o_note h4,.o_note h5,.b_note h2,.b_note h3,.b_note h4,.b_note h5{color:#31708f}.o_important,.b_important,p.b_important,div.b_important{margin:20px 0;padding:20px;border-left:3px solid #F4D000;background-color:#FFF1A4}.o_important h2,.o_important h3,.o_important h4,.o_important h5,.b_important h2,.b_important h3,.b_important h4,.b_important h5{color:#F4D000}.o_success,.b_success,p.b_success,div.b_success{margin:20px 0;padding:20px;border-left:3px solid #3c763d;background-color:#dff0d8}.o_success h2,.o_success h3,.o_success h4,.o_success h5,.b_success h2,.b_success h3,.b_success h4,.b_success h5{color:#3c763d}.o_warning,.b_warning,p.b_warning,div.b_warning{margin:20px 0;padding:20px;border-left:3px solid #8a6d3b;background-color:#fcf8e3}.o_warning h2,.o_warning h3,.o_warning h4,.o_warning h5,.b_warning h2,.b_warning h3,.b_warning h4,.b_warning h5{color:#8a6d3b}.o_error,.b_error,p.b_error,div.b_error{margin:20px 0;padding:20px;border-left:3px solid #a94442;background-color:#f2dede}.o_error h2,.o_error h3,.o_error h4,.o_error h5,.b_error h2,.b_error h3,.b_error h4,.b_error h5{color:#a94442}div.o_callout_overlay{position:fixed;top:0;left:0;width:100%;height:100%;zoom:1;background:#000;opacity:0;filter:alpha(opacity=0)}.o_alert_info{position:fixed;top:-100%;left:0;display:none;z-index:2000;width:100%;text-align:center}.o_alert_info .alert{position:relative;width:auto;margin:0 auto;text-align:left;-webkit-box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15);box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15)}.o_alert_info .alert .o_alert_close{float:right;color:#777}.o_alert_info .alert .o_alert_close:hover{color:#555}@media (min-width: 768px){.o_alert_info .alert{width:600px}}#o_msg_sticky,#o_msg_sticky_preview{position:relative;color:#a94442;background-color:#f2dede;border:1px solid #ebccd1;padding:10px 16px 10px 60px;min-height:40px;margin:-20px 0 20px 0}#o_msg_sticky .o_icon_info_msg,#o_msg_sticky_preview .o_icon_info_msg{position:absolute;left:10px;top:5px;font-size:40px}#o_msg_sticky.o_msg_sticky_fullscreen,#o_msg_sticky_preview.o_msg_sticky_fullscreen{margin-top:0}@media (min-width: 768px){.modal .o_modal_fullwidth{width:90%}}@media (min-width: 992px){.modal .o_modal_fullwidth{width:80%}}.modal .modal-header h4{color:#3b678a;font-weight:500;font-family:inherit;line-height:1.1}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857;color:#333;background-color:#fff}a{color:#3b678a;text-decoration:none}a:hover,a:focus{color:#243f54;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}h1{color:#3b678a}h2{color:#3b678a}h3{color:#3b678a}h4{color:#3b678a}h5{color:#3b678a}h5{color:#3b678a}hr{border-top:1px solid #eee}.o_user_content_block a{color:#3b678a;text-decoration:none}.o_user_content_block a:hover,.o_user_content_block a:focus{color:#243f54;text-decoration:underline}.b_border_box,p.b_border_box,div.b_border_box{border:1px solid #777;padding:1em;border-top-right-radius:3px;border-top-left-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}table td{vertical-align:top}table.b_grid{width:99.5%;background:transparent;border-collapse:separate}table.b_grid td,table.b_grid th{padding:1px 5px;border:1px solid #777}table.b_grid thead td,table.b_grid th{background:#eee;font-weight:bold}table.b_border{width:99.5%;background:transparent;border-collapse:collapse}table.b_border td,table.b_border th{padding:1px 5px;border:1px solid #777}table.b_border thead td,table.b_border th{background:#eee;font-weight:bold}table.b_borderless{width:99.5%;background:transparent;border-collapse:separate}table.b_borderless td,table.b_borderless th{padding:1px 5px;border:0;font-weight:bold}table.b_full{width:99.5%}table.b_middle{background:transparent}table.b_middle td{vertical-align:middle}table.b_gray{border-collapse:collapse}table.b_gray td,table.b_gray th{padding:1px 5px;background:#eee;border:1px solid #fff}table.b_gray thead td,table.b_gray th{background:#d5d5d5;font-weight:bold}table.b_blue{border-collapse:collapse}table.b_blue td,table.b_blue th{padding:1px 5px;background:#d9edf7;border:1px solid #fff}table.b_blue thead td,table.b_blue th{background:#afd9ee;font-weight:bold}table.b_green{border-collapse:collapse}table.b_green td,table.b_green th{padding:1px 5px;background:#dff0d8;border:1px solid #fff}table.b_green thead td,table.b_green th{background:#c1e2b3;font-weight:bold}table.b_yellow{border-collapse:collapse}table.b_yellow td,table.b_yellow th{padding:1px 5px;background:#fcf8e3;border:1px solid #fff}table.b_yellow thead td,table.b_yellow th{background:#f7ecb5;font-weight:bold}table.b_red{border-collapse:collapse}table.b_red td,table.b_red th{padding:1px 5px;background:#f2dede;border:1px solid #fff}table.b_red thead td,table.b_red th{background:#e4b9b9;font-weight:bold}.b_align_normal{text-align:left}.b_align_center{text-align:center}.b_align_inverse{text-align:right}.b_align_justified{text-align:justify}a.b_link_extern{color:#3b678a}a.b_link_extern:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:""}a.b_link_mailto{color:#3b678a}a.b_link_mailto:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:""}a.b_link_forward{color:#3b678a}a.b_link_forward:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"ï¤"}img.b_float_left{float:left;margin:0 2em 2em 0}img.b_float_left_clear{clear:both;margin:0 2em 2em 0;display:block}img.b_float_right{float:right;margin:0 0 2em 2em}img.b_float_right_clear{clear:both;display:block;margin:0 0 2em auto}img.b_float_left_clear_nomargin{float:left;display:block;margin:0 0 0 0}img.b_centered{clear:both;display:block;margin:0 auto 2em auto}img.b_circle{border-radius:50%}img.b_with_border{border:1px solid #ddd;padding:3px;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}p.b_figure_title{margin:20px 0 5px 0;font-size:85%;font-family:inherit}p.b_figure_caption{clear:both;margin:5px 0 20px 0;font-size:85%;font-family:inherit}span.olatFlashMovieViewer{max-width:100% !important;border:none !important}.mejs__container,.mejs__mediaelement video,.mejs__layers div,.me_cannotplay{max-width:100%}.b_clear_float,p.b_clear_float,div.b_clear_float{clear:both}@media print{a[href]:after{content:""}#o_header_wrapper,#o_offcanvas_right,#o_navbar_wrapper,#o_footer_wrapper,#o_toplink,#o_main_left,#o_main_right,#o_main_toolbar,#jsMath_PrintWarning,.o_noti,.o_opener,.o_hide,.o_noprint{display:none !important}.o_print_break_avoid{page-break-inside:avoid}.o_print_break_before{page-break-before:always}.btn{display:none}.o_form textarea,.o_form .form-control.textarea_disabled{-webkit-print-color-adjust:exact;color-adjust:exact;background:#fff !important;height:auto !important;color:#000 !important;resize:none}#o_comment_form_link,.o_comments form{display:none !important}.o_avatar{display:none}body.o_dmz{background:white !important;-webkit-print-color-adjust:exact;color-adjust:exact}.modal-dialog{margin:0 !important;width:100% !important;height:100% !important;background:#fff !important;-webkit-print-color-adjust:exact;color-adjust:exact}.progress{page-break-inside:avoid;-webkit-print-color-adjust:exact;color-adjust:exact;background-color:rgba(0,0,0,0.1) !important;border:1px solid rgba(0,0,0,0.5)}.progress-bar{-webkit-print-color-adjust:exact;background-color:#000 !important;border:10px solid #000}.radial-progress{page-break-inside:avoid;-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#eee !important}.radial-progress .circle .mask .fill{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#000 !important}.radial-progress .inset{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#fff !important}body{margin:0}} +**//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#3b678a;text-decoration:none}a:hover,a:focus{color:#243f54;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h1 .small,h2 small,h2 .small,h3 small,h3 .small,h4 small,h4 .small,h5 small,h5 .small,h6 small,h6 .small,.h1 small,.h1 .small,.h2 small,.h2 .small,.h3 small,.h3 .small,.h4 small,.h4 .small,.h5 small,.h5 .small,.h6 small,.h6 .small{font-weight:normal;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,h1 .small,.h1 small,.h1 .small,h2 small,h2 .small,.h2 small,.h2 .small,h3 small,h3 .small,.h3 small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,h4 .small,.h4 small,.h4 .small,h5 small,h5 .small,.h5 small,.h5 .small,h6 small,h6 .small,.h6 small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width: 768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#3b678a}a.text-primary:hover{color:#2c4c66}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff}.bg-primary{background-color:#3b678a}a.bg-primary:hover{background-color:#2c4c66}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ul ol,ol ul,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857}dt{font-weight:bold}dd{margin-left:0}.dl-horizontal dd:before,.dl-horizontal dd:after{content:" ";display:table}.dl-horizontal dd:after{clear:both}@media (min-width: 768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,.blockquote-reverse small:before,.blockquote-reverse .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,.blockquote-reverse small:after,.blockquote-reverse .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857}@font-face{font-family:'FontAwesome';src:url("../../font-awesome/fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../../font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../../font-awesome/fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../../font-awesome/fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_block_bottom,.o_block,.o_button_group,.o_header_with_buttons{margin-bottom:1em}.o_block_top,.o_block,.o_button_group{margin-top:1em}.o_block_small_bottom,.o_block_small{margin-bottom:0.5em}.o_block_small_top,.o_block_small{margin-top:0.5em}.o_block_large_bottom,.o_block_large{margin-bottom:2em}.o_block_large_top,.o_block_large{margin-top:2em}.o_block_inline,.o_block_inline_left,.o_block_inline_both,.o_block_inline_right{display:inline-block}.o_block_inline_left,.o_block_inline_both{margin-left:0.5em}.o_block_inline_right,.o_block_inline_both{margin-right:0.5em}.o_block_centered_wrapper{display:table;width:100%;height:100%}.o_block_centered_content{display:table-cell;vertical-align:middle;text-align:center}.o_block_imagebg{background-repeat:no-repeat;background-position:center;background-size:cover}.o_block_imagebg span{padding:2px;background-color:rgba(255,255,255,0.8)}.o_block_imagebg h1,.o_block_imagebg h2,.o_block_imagebg h3,.o_block_imagebg h4,.o_block_imagebg h5,.o_block_imagebg p{padding:2px;background-color:rgba(255,255,255,0.8);display:inline-block}.o_block_imagebg h1:after,.o_block_imagebg h2:after,.o_block_imagebg h3:after,.o_block_imagebg h4:after,.o_block_imagebg h5:after,.o_block_imagebg p:after{content:' ';display:block}.o_scrollblock,div.b_scrollblock{overflow-x:auto;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.o_button_group{text-align:center}.o_button_group a,.o_button_group input,.o_button_group button,.o_button_group .btn-group{margin-right:5px;margin-bottom:0.5em}.o_button_group a:last-child,.o_button_group input:last-child,.o_button_group button:last-child,.o_button_group .btn-group:last-child{margin-right:0}.o_button_group .btn-group a,.o_button_group .btn-group input,.o_button_group .btn-group button{margin-right:0;margin-bottom:0}.o_button_group .dropdown-menu{text-align:left}.o_button_group_left{text-align:left}.o_button_group_right{text-align:right}.o_button_group_top{margin-top:0}.o_header_with_buttons:before,.o_header_with_buttons:after{content:" ";display:table}.o_header_with_buttons:after{clear:both}.o_header_with_buttons h1,.o_header_with_buttons h2,.o_header_with_buttons h3,.o_header_with_buttons h4,.o_header_with_buttons h5,.o_header_with_buttons h6{display:inline-block}.o_header_with_buttons .o_button_group{margin-bottom:0;float:right}.o_header_with_buttons h1+.o_button_group{margin-top:28px}.o_header_with_buttons h2+.o_button_group{margin-top:24px}.o_header_with_buttons h3+.o_button_group{margin-top:20px}.o_header_with_buttons h4+.o_button_group{margin-top:10px}.o_header_with_buttons h5+.o_button_group{margin-top:6.66667px}.o_header_with_buttons h6+.o_button_group{margin-top:5px}#o_main_center .o_header_with_buttons h2+.o_button_group{margin-top:0}.panel-heading.o_header_with_buttons{margin-bottom:0}.o_button_textstyle:before{content:'['}.o_button_textstyle:after{content:']'}.panel-imagebg{background-repeat:no-repeat;background-position:center;background-size:cover}.panel-imagebg.panel-default>.panel-heading{background-color:rgba(255,255,255,0.8);border-bottom:transparent}.panel-imagebg .panel-body span{padding:2px;background-color:rgba(255,255,255,0.8)}.panel-placeholder{border-width:2px;border-style:dashed;border-color:#6b9ac0;border-radius:10px}.panel-placeholder .panel-body{padding:10px}.panel-placeholder .panel-body:nth-child(n+2){border-top:none}.panel-placeholder .panel-body h3:nth-child(1),.panel-placeholder .panel-body h4:nth-child(1),.panel-placeholder .panel-body h5:nth-child(1){margin-top:0}.panel-placeholder .panel-body .o_button_group{margin-bottom:0}.panel-placeholder .panel-heading{border-top-right-radius:8px;border-top-left-radius:8px;border-width:2px;border-style:dashed;border-color:#6b9ac0;border-top:none;border-left:none;border-right:none;color:#3b678a;font-weight:bold}.panel-placeholder .panel-footer{border-bottom-right-radius:8px;border-bottom-left-radius:8px;border-width:2px;border-style:dashed;border-color:#6b9ac0;border-bottom:none;border-left:none;border-right:none}.o_xsmall,.b_xsmall,p.b_xsmall,div.b_xsmall{font-size:12px}.o_small,.b_small,p.b_small,div.b_small{font-size:12px}.o_large,.b_large,p.b_large,div.b_large{font-size:18px}.o_xlarge,.b_xlarge,p.b_xlarge,div.b_xlarge{font-size:18px}.o_disabled,.b_disabled,p.b_disabled,div.b_disabled{color:#777 !important;cursor:default}.o_disabled:hover,.b_disabled:hover{color:#777 !important}.o_dimmed,.b_dimmed,p.b_dimmed,div.b_dimmed{opacity:.4;filter:alpha(opacity=40)}.o_selected,.b_selected,p.b_selected,div.b_selected{font-weight:bold}.o_deleted,.b_deleted,p.b_deleted,div.b_deleted{text-decoration:line-through}.o_highlight_on_hover:hover{background-color:#f5f5f5}.o_clickable{cursor:pointer}.o_ochre{color:#c8a959}.o_blue{color:#12223F}.o_undecorated:hover,.o_undecorated:focus,.o_disabled:hover,.b_disabled:hover,.o_disabled:focus,.b_disabled:focus{text-decoration:none}.o_copy_code,.b_copy_code,p.b_copy_code,div.b_copy_code,code,pre{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}.o_copy_code input,.o_copy_code textarea,.b_copy_code input,code input,pre input,.b_copy_code textarea,code textarea,pre textarea{border:0;width:95%;background:transparent}.o_nowrap,.b_copy_code,p.b_copy_code,div.b_copy_code,code{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.o_titled_wrapper .o_content{margin-top:20px}.o_video,.o_video video,.b_video,.o_video_wrapper{display:inline-block;max-width:100%;height:auto;max-width:100%}.o_image,.o_image img,img,.b_image{display:inline-block;max-width:100%;height:auto;max-width:100%}.o_figure_caption_bottom{display:inline-block;min-width:50%}.o_figure_caption_bottom figure{display:table}.o_figure_caption_bottom figcaption{display:table-caption;caption-side:bottom;font-size:90%;font-style:italic;text-align:center}.o_image_vertical_center_helper{display:inline-block;height:100%;vertical-align:middle}.o_image_vertical_center_helper+.o_image img{vertical-align:middle}.o_with_hyphens{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.o_info,.b_info,p.b_info,div.b_info{margin:20px 0;padding:20px;border-left:3px solid #777;background-color:#eee}.o_info h2,.o_info h3,.o_info h4,.o_info h5,.b_info h2,.b_info h3,.b_info h4,.b_info h5{color:#777}.o_note,.b_note,p.b_note,div.b_note{margin:20px 0;padding:20px;border-left:3px solid #31708f;background-color:#d9edf7}.o_note h2,.o_note h3,.o_note h4,.o_note h5,.b_note h2,.b_note h3,.b_note h4,.b_note h5{color:#31708f}.o_important,.b_important,p.b_important,div.b_important{margin:20px 0;padding:20px;border-left:3px solid #F4D000;background-color:#FFF1A4}.o_important h2,.o_important h3,.o_important h4,.o_important h5,.b_important h2,.b_important h3,.b_important h4,.b_important h5{color:#F4D000}.o_success,.b_success,p.b_success,div.b_success{margin:20px 0;padding:20px;border-left:3px solid #3c763d;background-color:#dff0d8}.o_success h2,.o_success h3,.o_success h4,.o_success h5,.b_success h2,.b_success h3,.b_success h4,.b_success h5{color:#3c763d}.o_warning,.b_warning,p.b_warning,div.b_warning{margin:20px 0;padding:20px;border-left:3px solid #8a6d3b;background-color:#fcf8e3}.o_warning h2,.o_warning h3,.o_warning h4,.o_warning h5,.b_warning h2,.b_warning h3,.b_warning h4,.b_warning h5{color:#8a6d3b}.o_error,.b_error,p.b_error,div.b_error{margin:20px 0;padding:20px;border-left:3px solid #a94442;background-color:#f2dede}.o_error h2,.o_error h3,.o_error h4,.o_error h5,.b_error h2,.b_error h3,.b_error h4,.b_error h5{color:#a94442}div.o_callout_overlay{position:fixed;top:0;left:0;width:100%;height:100%;zoom:1;background:#000;opacity:0;filter:alpha(opacity=0)}.o_alert_info{position:fixed;top:-100%;left:0;display:none;z-index:2000;width:100%;text-align:center}.o_alert_info .alert{position:relative;width:auto;margin:0 auto;text-align:left;-webkit-box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15);box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15)}.o_alert_info .alert .o_alert_close{float:right;color:#777}.o_alert_info .alert .o_alert_close:hover{color:#555}@media (min-width: 768px){.o_alert_info .alert{width:600px}}#o_msg_sticky,#o_msg_sticky_preview{position:relative;color:#a94442;background-color:#f2dede;border:1px solid #ebccd1;padding:10px 16px 10px 60px;min-height:40px;margin:-20px 0 20px 0}#o_msg_sticky .o_icon_info_msg,#o_msg_sticky_preview .o_icon_info_msg{position:absolute;left:10px;top:5px;font-size:40px}#o_msg_sticky.o_msg_sticky_fullscreen,#o_msg_sticky_preview.o_msg_sticky_fullscreen{margin-top:0}@media (min-width: 768px){.modal .o_modal_fullwidth{width:90%}}@media (min-width: 992px){.modal .o_modal_fullwidth{width:80%}}.modal .modal-header h4{color:#3b678a;font-weight:500;font-family:inherit;line-height:1.1}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857;color:#333;background-color:#fff}a{color:#3b678a;text-decoration:none}a:hover,a:focus{color:#243f54;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}h1{color:#3b678a}h2{color:#3b678a}h3{color:#3b678a}h4{color:#3b678a}h5{color:#3b678a}h5{color:#3b678a}hr{border-top:1px solid #eee}.o_user_content_block a{color:#3b678a;text-decoration:none}.o_user_content_block a:hover,.o_user_content_block a:focus{color:#243f54;text-decoration:underline}.b_border_box,p.b_border_box,div.b_border_box{border:1px solid #777;padding:1em;border-top-right-radius:3px;border-top-left-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}table td{vertical-align:top}table.b_grid{width:99.5%;background:transparent;border-collapse:separate}table.b_grid td,table.b_grid th{padding:1px 5px;border:1px solid #777}table.b_grid thead td,table.b_grid th{background:#eee;font-weight:bold}table.b_border{width:99.5%;background:transparent;border-collapse:collapse}table.b_border td,table.b_border th{padding:1px 5px;border:1px solid #777}table.b_border thead td,table.b_border th{background:#eee;font-weight:bold}table.b_borderless{width:99.5%;background:transparent;border-collapse:separate}table.b_borderless td,table.b_borderless th{padding:1px 5px;border:0}table.b_borderless thead td,table.b_borderless th{font-weight:bold}table.b_full{width:99.5%}table.b_middle{background:transparent}table.b_middle td{vertical-align:middle}table.b_gray{border-collapse:collapse}table.b_gray td,table.b_gray th{padding:1px 5px;background:#eee;border:1px solid #fff}table.b_gray thead td,table.b_gray th{background:#d5d5d5;font-weight:bold}table.b_blue{border-collapse:collapse}table.b_blue td,table.b_blue th{padding:1px 5px;background:#d9edf7;border:1px solid #fff}table.b_blue thead td,table.b_blue th{background:#afd9ee;font-weight:bold}table.b_green{border-collapse:collapse}table.b_green td,table.b_green th{padding:1px 5px;background:#dff0d8;border:1px solid #fff}table.b_green thead td,table.b_green th{background:#c1e2b3;font-weight:bold}table.b_yellow{border-collapse:collapse}table.b_yellow td,table.b_yellow th{padding:1px 5px;background:#fcf8e3;border:1px solid #fff}table.b_yellow thead td,table.b_yellow th{background:#f7ecb5;font-weight:bold}table.b_red{border-collapse:collapse}table.b_red td,table.b_red th{padding:1px 5px;background:#f2dede;border:1px solid #fff}table.b_red thead td,table.b_red th{background:#e4b9b9;font-weight:bold}.b_align_normal{text-align:left}.b_align_center{text-align:center}.b_align_inverse{text-align:right}.b_align_justified{text-align:justify}a.b_link_extern{color:#3b678a}a.b_link_extern:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:""}a.b_link_mailto{color:#3b678a}a.b_link_mailto:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:""}a.b_link_forward{color:#3b678a}a.b_link_forward:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;padding-right:0.5em;content:"ï¤"}img.b_float_left{float:left;margin:0 2em 2em 0}img.b_float_left_clear{clear:both;margin:0 2em 2em 0;display:block}img.b_float_right{float:right;margin:0 0 2em 2em}img.b_float_right_clear{clear:both;display:block;margin:0 0 2em auto}img.b_float_left_clear_nomargin{float:left;display:block;margin:0 0 0 0}img.b_centered{clear:both;display:block;margin:0 auto 2em auto}img.b_circle{border-radius:50%}img.b_with_border{border:1px solid #ddd;padding:3px;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}p.b_figure_title{margin:20px 0 5px 0;font-size:85%;font-family:inherit}p.b_figure_caption{clear:both;margin:5px 0 20px 0;font-size:85%;font-family:inherit}.b_clear_float,p.b_clear_float,div.b_clear_float{clear:both}figure.align-left{float:left}figure.align-right{float:right}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}img.align-left{float:left}img.align-right{float:right}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}figure.image.align-center{display:block;text-align:center}figure.image.align-left{float:none;display:block;text-align:left}figure.image.align-left figcaption{text-align:left}figure.image.align-right{float:none;display:block;text-align:right}figure.image.align-right figcaption{text-align:right}figure.image{margin:2em 0 2em 0;border:0;background:none}figure.image img.b_float_left,figure.image img.b_float_left_clear,figure.image img.b_float_right,figure.image img.b_float_right_clear,figure.image img.b_float_left_clear_nomargin,figure.image img.b_centered{float:none;display:inline-block;margin:0}figure.image figcaption{font-size:90%;font-style:italic}@media print{a[href]:after{content:""}#o_header_wrapper,#o_offcanvas_right,#o_navbar_wrapper,#o_footer_wrapper,#o_toplink,#o_main_left,#o_main_right,#o_main_toolbar,#jsMath_PrintWarning,.o_noti,.o_opener,.o_hide,.o_noprint{display:none !important}.o_print_break_avoid{page-break-inside:avoid}.o_print_break_before{page-break-before:always}.o_print_break_after{clear:both;page-break-after:always}.btn{display:none}.o_form textarea,.o_form .form-control.textarea_disabled{-webkit-print-color-adjust:exact;color-adjust:exact;background:#fff !important;height:auto !important;color:#000 !important;resize:none}#o_comment_form_link,.o_comments form{display:none !important}.o_avatar{display:none}body.o_dmz{background:white !important;-webkit-print-color-adjust:exact;color-adjust:exact}.modal-dialog{margin:0 !important;width:100% !important;height:100% !important;background:#fff !important;-webkit-print-color-adjust:exact;color-adjust:exact}.progress{page-break-inside:avoid;-webkit-print-color-adjust:exact;color-adjust:exact;background-color:rgba(0,0,0,0.1) !important;border:1px solid rgba(0,0,0,0.5)}.progress-bar{-webkit-print-color-adjust:exact;background-color:#000 !important;border:10px solid #000}.ui-slider.ui-slider-horizontal.ui-widget-content{-webkit-print-color-adjust:exact;color-adjust:exact;background:#f9f9f9 !important}.ui-slider.ui-slider-horizontal.ui-widget-content .ui-slider-handle{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#3b678a !important}.radial-progress{page-break-inside:avoid;-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#eee !important}.radial-progress .circle .mask .fill{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#000 !important}.radial-progress .inset{-webkit-print-color-adjust:exact;color-adjust:exact;background-color:#fff !important}body{margin:0}table,figure,figure{page-break-inside:avoid}h1,h2,h3,h4,h5,h6{page-break-after:avoid}} /*# sourceMappingURL=content.css.map */ diff --git a/src/main/webapp/static/themes/openolat/content.css.map b/src/main/webapp/static/themes/openolat/content.css.map index 88adcb128740648355e22e1d49500ed17918137d..437a29c476b097361d44ace10c05730af5110bef 100644 --- a/src/main/webapp/static/themes/openolat/content.css.map +++ b/src/main/webapp/static/themes/openolat/content.css.map @@ -1,7 +1,7 @@ { "version": 3, -"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;+DAQA,IAAK,CACH,WAAW,CAAE,UAAU,CACvB,oBAAoB,CAAE,IAAI,CAC1B,wBAAwB,CAAE,IAAI,CAOhC,IAAK,CACH,MAAM,CAAE,CAAC,CAaX,0FAYQ,CACN,OAAO,CAAE,KAAK,CAQhB,2BAGM,CACJ,OAAO,CAAE,YAAY,CACrB,cAAc,CAAE,QAAQ,CAQ1B,qBAAsB,CACpB,OAAO,CAAE,IAAI,CACb,MAAM,CAAE,CAAC,CAQX,iBACS,CACP,OAAO,CAAE,IAAI,CAUf,CAAE,CACA,gBAAgB,CAAE,WAAW,CAO/B,gBACQ,CACN,OAAO,CAAE,CAAC,CAUZ,WAAY,CACV,aAAa,CAAE,UAAU,CAO3B,QACO,CACL,WAAW,CAAE,IAAI,CAOnB,GAAI,CACF,UAAU,CAAE,MAAM,CAQpB,EAAG,CACD,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,QAAQ,CAOlB,IAAK,CACH,UAAU,CAAE,IAAI,CAChB,KAAK,CAAE,IAAI,CAOb,KAAM,CACJ,SAAS,CAAE,GAAG,CAOhB,OACI,CACF,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,CAAC,CACd,QAAQ,CAAE,QAAQ,CAClB,cAAc,CAAE,QAAQ,CAG1B,GAAI,CACF,GAAG,CAAE,MAAM,CAGb,GAAI,CACF,MAAM,CAAE,OAAO,CAUjB,GAAI,CACF,MAAM,CAAE,CAAC,CAOX,cAAe,CACb,QAAQ,CAAE,MAAM,CAUlB,MAAO,CACL,MAAM,CAAE,QAAQ,CAOlB,EAAG,CACD,eAAe,CAAE,WAAW,CAC5B,UAAU,CAAE,WAAW,CACvB,MAAM,CAAE,CAAC,CAOX,GAAI,CACF,QAAQ,CAAE,IAAI,CAOhB,iBAGK,CACH,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAkBhB,qCAIS,CACP,KAAK,CAAE,OAAO,CACd,IAAI,CAAE,OAAO,CACb,MAAM,CAAE,CAAC,CAOX,MAAO,CACL,QAAQ,CAAE,OAAO,CAUnB,aACO,CACL,cAAc,CAAE,IAAI,CAWtB,yEAGqB,CACnB,kBAAkB,CAAE,MAAM,CAC1B,MAAM,CAAE,OAAO,CAOjB,qCACqB,CACnB,MAAM,CAAE,OAAO,CAOjB,gDACwB,CACtB,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CAQZ,KAAM,CACJ,WAAW,CAAE,MAAM,CAWrB,0CACoB,CAClB,UAAU,CAAE,UAAU,CACtB,OAAO,CAAE,CAAC,CASZ,+FACgD,CAC9C,MAAM,CAAE,IAAI,CASd,oBAAqB,CACnB,kBAAkB,CAAE,SAAS,CAC7B,eAAe,CAAE,WAAW,CAC5B,kBAAkB,CAAE,WAAW,CAC/B,UAAU,CAAE,WAAW,CASzB,kGACgD,CAC9C,kBAAkB,CAAE,IAAI,CAO1B,QAAS,CACP,MAAM,CAAE,iBAAiB,CACzB,MAAM,CAAE,KAAK,CACb,OAAO,CAAE,qBAAqB,CAQhC,MAAO,CACL,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CAOZ,QAAS,CACP,QAAQ,CAAE,IAAI,CAQhB,QAAS,CACP,WAAW,CAAE,IAAI,CAUnB,KAAM,CACJ,eAAe,CAAE,QAAQ,CACzB,cAAc,CAAE,CAAC,CAGnB,KACG,CACD,OAAO,CAAE,CAAC,sFClaZ,YAAa,CACT,kBAEQ,CACJ,UAAU,CAAE,sBAAsB,CAClC,KAAK,CAAE,eAAe,CACtB,UAAU,CAAE,eAAe,CAC3B,WAAW,CAAE,eAAe,CAGhC,WACU,CACN,eAAe,CAAE,SAAS,CAG9B,aAAc,CACV,OAAO,CAAE,mBAAmB,CAGhC,iBAAkB,CACd,OAAO,CAAE,oBAAoB,CAKjC,+CAC6B,CACzB,OAAO,CAAE,EAAE,CAGf,cACW,CACP,MAAM,CAAE,cAAc,CACtB,iBAAiB,CAAE,KAAK,CAG5B,KAAM,CACF,OAAO,CAAE,kBAAkB,CAG/B,MACI,CACA,iBAAiB,CAAE,KAAK,CAG5B,GAAI,CACA,SAAS,CAAE,eAAe,CAG9B,OAEG,CACC,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CAGb,KACG,CACC,gBAAgB,CAAE,KAAK,CAO3B,MAAO,CACH,UAAU,CAAE,eAAe,CAI/B,OAAQ,CACJ,OAAO,CAAE,IAAI,CAIb,+BAAS,CACL,gBAAgB,CAAE,eAAe,CAGzC,MAAO,CACH,MAAM,CAAE,cAAc,CAG1B,MAAO,CACH,eAAe,CAAE,mBAAmB,CAEpC,mBACG,CACC,gBAAgB,CAAE,eAAe,CAIrC,qCACG,CACC,MAAM,CAAE,yBAAyB,EC3F7C,CAAE,CCgEA,kBAAkB,CD/DE,UAAU,CCgE3B,eAAe,CDhEE,UAAU,CCiEtB,UAAU,CDjEE,UAAU,CAEhC,gBACQ,CC4DN,kBAAkB,CD3DE,UAAU,CC4D3B,eAAe,CD5DE,UAAU,CC6DtB,UAAU,CD7DE,UAAU,CAMhC,IAAK,CACH,SAAS,CAAE,IAAI,CACf,2BAA2B,CAAE,WAAa,CAG5C,IAAK,CACH,WAAW,CESkB,2CAAiB,CFR9C,SAAS,CG2Be,IAAI,CH1B5B,WAAW,CGsCa,OAAW,CHrCnC,KAAK,CEofmB,IAAW,CFnfnC,gBAAgB,CEkfM,IAAQ,CF9ehC,4BAGS,CACP,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,OAAO,CAClB,WAAW,CAAE,OAAO,CAMtB,CAAE,CACA,KAAK,CE2kB8B,OAAc,CF1kBjD,eAAe,CAAE,IAAI,CAErB,eACQ,CACN,KAAK,CEuZwB,OAAiB,CFtZ9C,eAAe,CGZK,SAAS,CHe/B,OAAQ,CIrDR,OAAO,CAAE,WAAW,CAEpB,OAAO,CAAE,iCAAiC,CAC1C,cAAc,CAAE,IAAI,CJ6DtB,MAAO,CACL,MAAM,CAAE,CAAC,CAMX,GAAI,CACF,cAAc,CAAE,MAAM,CAIxB,eAAgB,CKvEd,OAAO,CADuB,KAAK,CAEnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CL0Ed,YAAa,CACX,aAAa,CG2Ba,GAAG,CHrB/B,cAAe,CACb,OAAO,CGwoBqB,GAAG,CHvoB/B,WAAW,CG3Ba,OAAW,CH4BnC,gBAAgB,CEkbM,IAAQ,CFjb9B,MAAM,CAAE,cAA2B,CACnC,aAAa,CEnCgB,GAAwB,CD2HrD,kBAAkB,CAAE,oBAAW,CAC1B,aAAa,CAAE,oBAAW,CACvB,UAAU,CAAE,oBAAW,CIlL/B,OAAO,CL4FiB,YAAY,CK3FpC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CL8Fd,WAAY,CACV,aAAa,CAAE,GAAG,CAMpB,EAAG,CACD,UAAU,CEqFgB,IAAqB,CFpF/C,aAAa,CEoFa,IAAqB,CFnF/C,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,cAAoB,CAQlC,QAAS,CACP,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,GAAG,CACV,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,CAAC,CACV,QAAQ,CAAE,MAAM,CAChB,IAAI,CAAE,gBAAa,CACnB,MAAM,CAAE,CAAC,CAQT,kDACQ,CACN,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CACjB,IAAI,CAAE,IAAI,CM3Id,yCAC6B,CAC3B,WAAW,CH8Da,OAAO,CG7D/B,WAAW,CH8Da,GAAG,CG7D3B,WAAW,CH8Da,GAAG,CG7D3B,KAAK,CH8DmB,OAAO,CG5D/B,+OACO,CACL,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,KAAK,CJ0kB0B,IAAW,CItkB9C,oBAEQ,CACN,UAAU,CJ4KgB,IAAqB,CI3K/C,aAAa,CAAE,IAA2B,CAE1C,uHACO,CACL,SAAS,CAAE,GAAG,CAGlB,oBAEQ,CACN,UAAU,CAAE,IAA2B,CACvC,aAAa,CAAE,IAA2B,CAE1C,uHACO,CACL,SAAS,CAAE,GAAG,CAIlB,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGZxD,MAAQ,CAAE,SAAS,CHaO,IAA+B,CGZzD,MAAQ,CAAE,SAAS,CHaO,IAA6B,CGZvD,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGZxD,MAAQ,CAAE,SAAS,CHaO,IAAe,CGZzC,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGPxD,CAAE,CACA,MAAM,CAAE,QAA+B,CAGzC,KAAM,CACJ,aAAa,CJwIa,IAAqB,CIvI/C,SAAS,CAAE,IAA+B,CAC1C,WAAW,CAAE,GAAG,CAChB,WAAW,CAAE,GAAG,CAEhB,yBAAmC,CANrC,KAAM,CAOF,SAAS,CAAE,IAAuB,EAStC,YACO,CACL,SAAS,CAAE,GAAkD,CAG/D,UACM,CACJ,gBAAgB,CJ0aK,OAAiB,CIzatC,OAAO,CAAE,IAAI,CAIf,UAAqB,CAAE,UAAU,CAAE,IAAI,CACvC,WAAqB,CAAE,UAAU,CAAE,KAAK,CACxC,YAAqB,CAAE,UAAU,CAAE,MAAM,CACzC,aAAqB,CAAE,UAAU,CAAE,OAAO,CAC1C,YAAqB,CAAE,WAAW,CAAE,MAAM,CAG1C,eAAqB,CAAE,cAAc,CAAE,SAAS,CAChD,eAAqB,CAAE,cAAc,CAAE,SAAS,CAChD,gBAAqB,CAAE,cAAc,CAAE,UAAU,CAGjD,WAAY,CACV,KAAK,CJuf4B,IAAW,CKzlB5C,aAAW,CACT,KAAK,CLsnB4B,OAAc,CKpnBjD,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,aAAW,CACT,KAAK,CLwfgB,OAAmB,CKtf1C,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,UAAW,CACT,KAAK,CLofc,OAAgB,CKlfrC,iBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,aAAW,CACT,KAAK,CL0fgB,OAAmB,CKxf1C,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,YAAW,CACT,KAAK,CL4fe,OAAkB,CK1fxC,mBAAkB,CAChB,KAAK,CAAE,OAAmB,CD8G9B,WAAY,CAGV,KAAK,CAAE,IAAI,CErHX,WAAW,CACT,gBAAgB,CNsnBiB,OAAc,CMpnBjD,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,WAAW,CACT,gBAAgB,CNufG,OAAiB,CMrftC,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,QAAW,CACT,gBAAgB,CNmfC,OAAc,CMjfjC,eAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,WAAW,CACT,gBAAgB,CNyfG,OAAiB,CMvftC,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,UAAW,CACT,gBAAgB,CN2fE,OAAgB,CMzfpC,iBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CFiIzC,YAAa,CACX,cAAc,CAAE,GAAiC,CACjD,MAAM,CAAE,WAAmD,CAC3D,aAAa,CAAE,cAAmC,CAQpD,KACG,CACD,UAAU,CAAE,CAAC,CACb,aAAa,CAAE,IAA2B,CAC1C,uBACG,CACD,aAAa,CAAE,CAAC,CAYpB,cAAe,CAJb,YAAY,CAAE,CAAC,CACf,UAAU,CAAE,IAAI,CASlB,YAAa,CAVX,YAAY,CAAE,CAAC,CACf,UAAU,CAAE,IAAI,CAWhB,WAAW,CAAE,IAAI,CAEjB,eAAK,CACH,OAAO,CAAE,YAAY,CACrB,YAAY,CAAE,GAAG,CACjB,aAAa,CAAE,GAAG,CAKtB,EAAG,CACD,UAAU,CAAE,CAAC,CACb,aAAa,CJYa,IAAqB,CIVjD,KACG,CACD,WAAW,CH3Ha,OAAW,CG6HrC,EAAG,CACD,WAAW,CAAE,IAAI,CAEnB,EAAG,CACD,WAAW,CAAE,CAAC,CGvLd,gDACQ,CACN,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAEhB,uBAAQ,CACN,KAAK,CAAE,IAAI,CH8Lb,yBAA2C,CACzC,iBAAG,CACD,KAAK,CAAE,IAAI,CACX,KAAK,CAAE,KAA4B,CACnC,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,KAAK,CIlNrB,QAAQ,CAAE,MAAM,CAChB,aAAa,CAAE,QAAQ,CACvB,WAAW,CAAE,MAAM,CJmNjB,iBAAG,CACD,WAAW,CHmoBa,KAA4B,EGznB1D,qCAE0B,CACxB,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,eAA6B,CAE9C,WAAY,CACV,SAAS,CAAE,GAAG,CACd,cAAc,CAAE,SAAS,CAI3B,UAAW,CACT,OAAO,CAAE,SAAiD,CAC1D,MAAM,CAAE,QAAyB,CACjC,SAAS,CHomBoB,MAAsB,CGnmBnD,WAAW,CAAE,cAAkC,CAK7C,yEAAa,CACX,aAAa,CAAE,CAAC,CAMpB,oDAEO,CACL,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,GAAG,CACd,WAAW,CHlMW,OAAW,CGmMjC,KAAK,CJuV0B,IAAW,CIrV1C,yEAAS,CACP,OAAO,CAAE,aAAa,CAQ5B,yCACsB,CACpB,aAAa,CAAE,IAAI,CACnB,YAAY,CAAE,CAAC,CACf,YAAY,CAAE,cAAkC,CAChD,WAAW,CAAE,CAAC,CACd,UAAU,CAAE,KAAK,CAMf,+MAAS,CAAE,OAAO,CAAE,EAAE,CACtB,yMAAQ,CACN,OAAO,CAAE,aAAa,CAM5B,OAAQ,CACN,aAAa,CJhGa,IAAqB,CIiG/C,UAAU,CAAE,MAAM,CAClB,WAAW,CHrOa,OAAW,CQhErC,UAWC,CAVC,WAAW,CAAE,aAAa,CAC1B,GAAG,CAAE,+DAAgE,CACrE,GAAG,CAAE,wbAI8F,CAEnG,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CCVpB,OAAmB,CACjB,OAAO,CAAE,YAAY,CACrB,IAAI,CAAE,uCAA8E,CACpF,SAAS,CAAE,OAAO,CAClB,cAAc,CAAE,IAAI,CACpB,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CCJpC,+DAAiC,CAChC,aAAa,CAAE,GAAG,CAEnB,qCAA2B,CAC1B,UAAU,CAAE,GAAG,CAMhB,oCAA6C,CAC5C,aAAa,CAAE,GAAG,CAEnB,iCAAuC,CACtC,UAAU,CAAE,GAAG,CAMhB,+EAAiC,CAChC,OAAO,CAAE,YAAY,CAEtB,yCAA2C,CAE1C,WAAW,CAAE,KAAK,CAGnB,0CAA6C,CAE5C,YAAY,CAAE,KAAK,CAQpB,yBAA0B,CACzB,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CAEb,yBAA0B,CACzB,OAAO,CAAE,UAAU,CACnB,cAAc,CAAE,MAAM,CACtB,UAAU,CAAE,MAAM,CAInB,gBAAiB,CAChB,iBAAiB,CAAC,SAAS,CAC3B,mBAAmB,CAAE,MAAM,CAC3B,eAAe,CAAE,KAAK,CACtB,qBAAK,CACJ,OAAO,CAAE,GAAG,CACZ,gBAAgB,CXokBY,qBAAwB,CWjkBrD,sHACE,CACD,OAAO,CAAE,GAAG,CACZ,gBAAgB,CX8jBY,qBAAwB,CW7jBpD,OAAO,CAAE,YAAY,CACrB,0JAAQ,CACP,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAOjB,gCAA+B,CAE9B,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,MAAM,CAEf,kBAAkB,CAAE,wBAAwB,CAC5C,0BAA0B,CAAE,KAAK,CAIrC,eAAgB,CAEf,UAAU,CAAE,MAAM,CAClB,yFAA6B,CAC5B,YAAY,CAAE,GAAG,CACjB,aAAa,CAAE,KAAK,CACpB,qIAAa,CACZ,YAAY,CAAE,CAAC,CAIhB,+FAAiB,CAChB,YAAY,CAAE,CAAC,CACf,aAAa,CAAE,CAAC,CAGlB,8BAAe,CACd,UAAU,CAAE,IAAI,CAIlB,oBAAqB,CACpB,UAAU,CAAE,IAAI,CAEjB,qBAAsB,CACrB,UAAU,CAAE,KAAK,CAElB,mBAAoB,CACnB,UAAU,CAAE,CAAC,CJvGZ,0DACQ,CACN,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAEhB,4BAAQ,CACN,KAAK,CAAE,IAAI,CIuGd,2JAAuB,CACtB,OAAO,CAAE,YAAY,CAEtB,sCAAgB,CACf,aAAa,CAAE,CAAC,CAChB,KAAK,CAAE,KAAK,CAGb,yCAAoB,CAClB,UAAU,CAAE,IAA6B,CAE3C,yCAAoB,CAClB,UAAU,CAAE,IAA6B,CAE3C,yCAAoB,CAClB,UAAU,CX6De,IAAqB,CW3DhD,yCAAoB,CAClB,UAAU,CAAE,IAA2B,CAEzC,yCAAoB,CAClB,UAAU,CAAE,SAA2B,CAEzC,yCAAoB,CAClB,UAAU,CAAE,GAA2B,CAI1C,wDAA0D,CACzD,UAAU,CAAE,CAAC,CAGd,oCAAqC,CACpC,aAAa,CAAE,CAAC,CAGjB,cAAe,CACd,iBAAiB,CAAC,SAAS,CAC3B,mBAAmB,CAAE,MAAM,CAC3B,eAAe,CAAE,KAAK,CAEtB,2CAA+B,CAC9B,gBAAgB,CX6dY,qBAAwB,CW5dpD,aAAa,CAAE,WAAW,CAE3B,+BAAiB,CAChB,OAAO,CAAE,GAAG,CACZ,gBAAgB,CXwdY,qBAAwB,CWndtD,kBAAmB,CAClB,YAAY,CX8buB,GAAG,CW7btC,YAAY,CAAE,MAAM,CACpB,YAAY,CXgcuB,OAAwC,CW/b3E,aAAa,CX4buB,IAAI,CW1bxC,8BAAY,CACX,OAAO,CX6buB,IAAI,CW5blC,6CAAiB,CAChB,UAAU,CAAE,IAAI,CAEjB,4IAEgB,CACf,UAAU,CAAE,CAAC,CAGd,8CAAgB,CACf,aAAa,CAAE,CAAC,CAGlB,iCAAe,CACd,uBAAuB,CAAE,GAAwE,CACjG,sBAAsB,CAAE,GAAwE,CAChG,YAAY,CXuasB,GAAG,CWtarC,YAAY,CAAE,MAAM,CACpB,YAAY,CXyasB,OAAwC,CWxa1E,UAAU,CAAE,IAAI,CAChB,WAAW,CAAE,IAAI,CACjB,YAAY,CAAE,IAAI,CAClB,KAAK,CX+a8B,OAAc,CW9ajD,WAAW,CXmasB,IAAI,CWjatC,gCAAc,CACb,0BAA0B,CAAE,GAAwE,CACpG,yBAAyB,CAAE,GAAwE,CACnG,YAAY,CX2ZsB,GAAG,CW1ZrC,YAAY,CAAE,MAAM,CACpB,YAAY,CX6ZsB,OAAwC,CW5Z1E,aAAa,CAAE,IAAI,CACnB,WAAW,CAAE,IAAI,CACjB,YAAY,CAAE,IAAI,CASpB,2CAAqB,CACpB,SAAS,CX2WY,IAAgB,CWzWtC,uCAAmB,CAClB,SAAS,CXwWY,IAAgB,CWtWtC,uCAAmB,CAClB,SAAS,CX8YiB,IAAgB,CW5Y3C,2CAAqB,CACpB,SAAS,CX2YiB,IAAgB,CWvY3C,mDAAyB,CACxB,KAAK,CAAE,eAAoC,CAK3C,MAAM,CAAE,OAAO,CAJf,mCAAO,CACN,KAAK,CAAE,eAAoC,CAM7C,2CAAqB,CCpPnB,OAAO,CDqPS,GAAE,CClPlB,MAAM,CAAE,iBAA6B,CDqPvC,mDAAyB,CACxB,WAAW,CAAE,IAAI,CAGlB,+CAAuB,CACtB,eAAe,CAAE,YAAY,CAG9B,YAA2B,CAC1B,MAAM,CAAE,OAAO,CAIhB,QAAS,CAAE,KAAK,CAAE,OAAO,CACzB,OAAQ,CAAE,KAAK,CAAE,OAAO,CAKvB,iHAAgB,CACf,eAAe,CAAE,IAAI,CAKvB,gEAA2B,CAC1B,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,IAAI,CACd,WAAW,CVnOY,6CAAiD,CUoOxE,OAAO,CAAE,OAAO,CAChB,SAAS,CAAE,GAAG,CACd,KAAK,CVkiBsB,OAAO,CUjiBnC,gBAAgB,CVkiBY,OAAO,CUjiBlC,aAAa,CV5KY,GAAG,CUgL/B,yDAAqB,CACpB,WAAW,CAAE,MAAM,CAKnB,4BAAW,CACV,UAAU,CAAE,IAA2B,CAKzC,iDAAqD,CRnSnD,OAAO,CQoSgB,YAAY,CRnSnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CQmSb,SAAS,CAAE,IAAI,CAEhB,kCAAiC,CRvS/B,OAAO,CQwSgB,YAAY,CRvSnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CQuSb,SAAS,CAAE,IAAI,CAIhB,+BAAgC,CAC/B,OAAO,CAAE,YAAY,CAClB,MAAM,CAAE,IAAI,CACZ,cAAc,CAAE,MAAM,CACtB,4CAAgB,CACf,cAAc,CAAE,MAAM,CAK3B,eAAiC,CAChC,eAAe,CAAE,IAAI,CACrB,YAAY,CAAE,IAAI,CAClB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,IAAI,CEnUd,mCAAiB,CCChB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,cAAyC,CACtD,gBAAgB,CdifI,IAAa,CchfjC,uFAAe,CAAE,KAAK,CdulBY,IAAW,CazlB9C,mCAAiB,CCFhB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdmfI,OAAc,CclflC,uFAAe,CAAE,KAAK,CdmfA,OAAgB,CalfvC,uDAA2B,CCL1B,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdqfQ,OAAO,Ccpf/B,+HAAe,CAAE,KAAK,CdqfI,OAAO,CajflC,+CAAuB,CCRtB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdufM,OAAiB,CctfvC,+GAAe,CAAE,KAAK,CdufE,OAAmB,Cahf5C,+CAAuB,CCXtB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdyfM,OAAiB,CcxfvC,+GAAe,CAAE,KAAK,CdyfE,OAAmB,Ca/e5C,uCAAmB,CCdlB,MAAM,CAAE,MAAe,CACvB,OAAO,Cdifa,IAAI,CchfxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,Cd2fK,OAAgB,Cc1frC,+FAAe,CAAE,KAAK,Cd2fC,OAAkB,Ca3e1C,qBAAsB,CACrB,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CAAE,IAAI,CAAE,CAAC,CACf,KAAK,CAAC,IAAI,CAAE,MAAM,CAAC,IAAI,CACvB,IAAI,CAAC,CAAC,CACN,UAAU,CAAE,IAAI,CDxBf,OAAO,CCyBS,CAAC,CDtBjB,MAAM,CAAE,gBAA6B,CC0BvC,aAAc,CACb,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,KAAK,CACV,IAAI,CAAE,CAAC,CACP,OAAO,CAAE,IAAI,CACZ,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,MAAM,CAElB,oBAAO,CACP,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAC,MAAM,CACb,UAAU,CAAE,IAAI,CduBhB,kBAAkB,CAAE,iCAAO,CACnB,UAAU,CAAE,iCAAO,CcrB3B,mCAAe,CACd,KAAK,CAAE,KAAK,CACZ,KAAK,Cb2iB2B,IAAW,Ca1iB3C,yCAAQ,CACP,KAAK,CbkkBe,IAAoB,Ca/jB1C,yBAAmC,CAdnC,oBAAO,CAgBH,KAAK,CZ0iBmB,KAAK,EYpiBnC,mCAAqC,CACpC,QAAQ,CAAE,QAAQ,CAClB,KAAK,CbgckB,OAAkB,Ca/bzC,gBAAgB,Cb8bK,OAAgB,Ca7brC,MAAM,CAAE,iBAA8B,CACtC,OAAO,CAAE,mBAAmG,CAC5G,UAAU,CAAE,IAAyB,CAErC,MAAM,CAAE,cAAgD,CAExD,qEAAiB,CAChB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,IAAgC,CACtC,GAAG,CAAE,GAAgC,CACrC,SAAS,CAAE,IAAyB,CAGrC,mFAA0B,CACzB,UAAU,CAAE,CAAC,CAOb,yBAAmC,CADpC,yBAAmB,CAEjB,KAAK,CAAE,GAAG,EAEX,yBAAmC,CAJpC,yBAAmB,CAKjB,KAAK,CAAE,GAAG,EAGZ,uBAAiB,CAChB,KAAK,Cb2hB8B,OAAc,Ca1hB/C,WAAW,CbwVgB,GAAqB,CavVlD,WAAW,CZ1Ba,OAAO,CY2B7B,WAAW,CZzBW,GAAG,CczE7B,qBAA0B,CAAC,UAAU,CAAG,+CAAgD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACnH,qBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,wBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,wBAA0B,CAAC,UAAU,CAAG,iDAAkD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACrH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,mBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,qBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,mBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,oBAA0B,CAAC,UAAU,CAAG,kDAAmD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACtH,qBAA0B,CAAC,UAAU,CAAG,yCAA0C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAC7G,sBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,+CAAgD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACnH,qBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,uBAA0B,CAAC,UAAU,CAAG,mDAAoD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACvH,kBAAwB,CAAC,UAAU,CAAG,2CAA4C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAC7G,oBAA0B,CAAC,UAAU,CAAG,wCAAyC,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CCA5G,IAAK,CACH,WAAW,ChBekB,2CAAiB,CgBd9C,SAAS,ChBekB,IAAe,CgBd1C,WAAW,ChBekB,OAAiB,CgBd9C,KAAK,ChB0fmB,IAAW,CgBzfnC,gBAAgB,ChBwfM,IAAQ,CgBrfhC,CAAE,CACA,KAAK,ChB8lB8B,OAAc,CgB7lBjD,eAAe,CAAE,IAAI,CAErB,eACQ,CACN,KAAK,ChB0awB,OAAiB,CgBza9C,eAAe,ChBSW,SAAS,CgBNrC,OAAQ,CdlCR,OAAO,CAAE,WAAW,CAEpB,OAAO,CAAE,iCAAiC,CAC1C,cAAc,CAAE,IAAI,CcoCtB,EAAG,CACF,KAAK,ChB+kB+B,OAAc,CgB7kBnD,EAAG,CACF,KAAK,ChB4kB+B,OAAc,CgB1kBnD,EAAG,CACF,KAAK,ChBykB+B,OAAc,CgBvkBnD,EAAG,CACF,KAAK,ChBskB+B,OAAc,CgBpkBnD,EAAG,CACF,KAAK,ChBmkB+B,OAAc,CgBjkBnD,EAAG,CACF,KAAK,ChBgkB+B,OAAc,CgB9jBnD,EAAG,CACF,UAAU,CAAE,cAA4C,CCtDxD,uBAAE,CACD,KAAK,CjBknB8B,OAAc,CiBjnBjD,eAAe,CAAE,IAAI,CACrB,2DACQ,CACP,KAAK,CjB+byB,OAAiB,CiB9b/C,eAAe,CjB8BY,SAAS,CiBAvC,6CAAgD,CAC/C,MAAM,CAAE,cAAsC,CAC9C,OAAO,CjBcwB,GAAG,CkBzDjC,uBAAuB,ClBwDM,GAAoB,CkBvDhD,sBAAsB,ClBuDM,GAAoB,CkBhDjD,0BAA0B,ClBgDG,GAAoB,CkB/ChD,yBAAyB,ClB+CG,GAAoB,CiBoBlD,QAAG,CACF,cAAc,CAAE,GAAG,CAGpB,YAAS,CACR,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,cAAiC,CAE1C,qCAAa,CACZ,UAAU,CjB0ZQ,IAAa,CiBzZ/B,WAAW,CAAE,IAAI,CAGnB,cAAW,CACV,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,mCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,cAAiC,CAE1C,yCAAa,CACZ,UAAU,CjB6YQ,IAAa,CiB5Y/B,WAAW,CAAE,IAAI,CAGnB,kBAAe,CACd,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,2CAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,CAAC,CACT,WAAW,CAAE,IAAI,CAGnB,YAAS,CACR,KAAK,CAAE,KAAK,CAEb,cAAW,CACV,UAAU,CAAE,WAAW,CACvB,iBAAG,CACF,cAAc,CAAE,MAAM,CAGxB,YAAS,CAhET,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBmbS,IAAa,CiBlbhC,MAAM,CAAE,cAA+B,CAExC,qCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CA2DlB,YAAS,CAnET,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBqbS,OAAc,CiBpbjC,MAAM,CAAE,cAA+B,CAExC,qCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CA8DlB,aAAU,CAtEV,eAAe,CAAE,QAAQ,CACzB,iCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBybW,OAAiB,CiBxbtC,MAAM,CAAE,cAA+B,CAExC,uCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAiElB,cAAW,CAzEX,eAAe,CAAE,QAAQ,CACzB,mCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjB2bW,OAAiB,CiB1btC,MAAM,CAAE,cAA+B,CAExC,yCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAoElB,WAAQ,CA5ER,eAAe,CAAE,QAAQ,CACzB,6BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjB6bU,OAAgB,CiB5bpC,MAAM,CAAE,cAA+B,CAExC,mCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAsGnB,eAAgB,CACf,UAAU,CAAE,IAAI,CAEjB,eAAgB,CACf,UAAU,CAAE,MAAM,CAEnB,gBAAiB,CAChB,UAAU,CAAE,KAAK,CAElB,kBAAmB,CAClB,UAAU,CAAC,OAAO,CAInB,eAAgB,CACf,KAAK,CjB8b+B,OAAc,CiB7blD,sBAAS,CHlLR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CG8KlC,aAAa,CAAE,KAAK,CACpB,OAAO,CE0Dc,GAAO,CFvD9B,eAAgB,CACf,KAAK,CjBsb+B,OAAc,CiBrblD,sBAAS,CH1LR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CGsLlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEmCW,GAAO,CF/B3B,gBAAiB,CAChB,KAAK,CjB6a+B,OAAc,CiB5alD,uBAAS,CHnMR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CG+LlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEoXM,GAAO,CF1WtB,gBAAiB,CAChB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,WAAW,CAEpB,sBAAuB,CACtB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,WAAW,CACnB,OAAO,CAAE,KAAK,CAEf,iBAAkB,CACjB,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,WAAW,CAEpB,uBAAwB,CACvB,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,YAAY,CAErB,+BAAgC,CAC/B,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,OAAO,CAEhB,cAAe,CACd,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,eAAe,CAExB,YAAa,CACZ,aAAa,CAAE,GAAG,CAEnB,iBAAkB,CACjB,MAAM,CAAE,cAAsC,CAC9C,OAAO,CjB9LwB,GAAG,CkB5DjC,uBAAuB,ClB2DM,GAAwB,CkB1DpD,sBAAsB,ClB0DM,GAAwB,CkBnDrD,0BAA0B,ClBmDG,GAAwB,CkBlDpD,yBAAyB,ClBkDG,GAAwB,CiB6MvD,gBAAiB,CAChB,MAAM,CAAE,YAAqD,CAC7D,SAAS,CAAE,GAAkD,CAC7D,WAAW,ChBtMc,OAAO,CgBwMjC,kBAAmB,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,YAAqD,CAC7D,SAAS,CAAE,GAAkD,CAC7D,WAAW,ChB5Mc,OAAO,CgBgNjC,yBAA0B,CACzB,SAAS,CAAE,eAAe,CAC1B,MAAM,CAAE,eAAe,CAExB,2EAA+E,CAC9E,SAAS,CAAE,IAAI,CAIhB,gDAAmD,CAClD,KAAK,CAAE,IAAI,CGrRZ,YAAa,CAGZ,aAAc,CACV,OAAO,CAAE,EAAE,CAIf,wLAYW,CACV,OAAO,CAAE,eAAe,CAIzB,oBAAqB,CACpB,iBAAiB,CAAG,KAAK,CAE1B,qBAAsB,CACrB,iBAAiB,CAAE,MAAM,CAI1B,IAAK,CACJ,OAAO,CAAE,IAAI,CAIb,wDACgC,CAC/B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,UAAU,CAAE,eAAe,CAC3B,MAAM,CAAE,eAAe,CACvB,KAAK,CAAE,eAAe,CACtB,MAAM,CAAE,IAAI,CAKd,qCACiB,CACf,OAAO,CAAE,eAAe,CAI1B,SAAU,CACT,OAAO,CAAE,IAAI,CAId,UAAW,CACV,UAAU,CAAE,gBAAgB,CAC5B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CAIpB,aAAc,CACb,MAAM,CAAE,YAAY,CACpB,KAAK,CAAE,eAAe,CACtB,MAAM,CAAE,eAAe,CACvB,UAAU,CAAE,eAAe,CAC3B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CAIpB,SAAU,CACT,iBAAiB,CAAG,KAAK,CACzB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACjB,gBAAgB,CAAE,0BAAyB,CAC3C,MAAM,CAAE,yBAAwB,CAEnC,aAAc,CACb,0BAA0B,CAAE,KAAK,CACjC,gBAAgB,CAAE,eAAe,CAEjC,MAAM,CAAE,eAAe,CAIxB,gBAAiB,CAChB,iBAAiB,CAAG,KAAK,CACzB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CACjC,oCAAoB,CACnB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CAElC,uBAAO,CACN,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CAInC,IAAK,CACJ,MAAM,CAAE,CAAC", -"sources": ["../../bootstrap/stylesheets/bootstrap/_normalize.scss","../../bootstrap/stylesheets/bootstrap/_print.scss","../../bootstrap/stylesheets/bootstrap/_scaffolding.scss","../../bootstrap/stylesheets/bootstrap/mixins/_vendor-prefixes.scss","../light/_config.scss","../../bootstrap/stylesheets/bootstrap/_variables.scss","../../bootstrap/stylesheets/bootstrap/mixins/_tab-focus.scss","../../bootstrap/stylesheets/bootstrap/mixins/_image.scss","../../bootstrap/stylesheets/bootstrap/_type.scss","../../bootstrap/stylesheets/bootstrap/mixins/_text-emphasis.scss","../../bootstrap/stylesheets/bootstrap/mixins/_background-variant.scss","../../bootstrap/stylesheets/bootstrap/mixins/_clearfix.scss","../../bootstrap/stylesheets/bootstrap/mixins/_text-overflow.scss","../../font-awesome/scss/_path.scss","../../font-awesome/scss/_core.scss","../light/modules/_helpers.scss","../../bootstrap/stylesheets/bootstrap/mixins/_opacity.scss","../light/modules/_dialog.scss","../light/modules/_mixins.scss","../light/modules/_emoticons.scss","../light/modules/_content.scss","../light/modules/_content_embedded.scss","../../bootstrap/stylesheets/bootstrap/mixins/_border-radius.scss","../../font-awesome/scss/_variables.scss","../light/modules/_print.scss"], +"mappings": "CAEA;;;;;;;;;;;;;;;;;;;;;;;;IAwBG,DC1BH,4DAA4D,AAQ5D,IAAK,CACH,WAAW,CAAE,UAAU,CACvB,oBAAoB,CAAE,IAAI,CAC1B,wBAAwB,CAAE,IAAI,CAOhC,IAAK,CACH,MAAM,CAAE,CAAC,CAaX,0FAYQ,CACN,OAAO,CAAE,KAAK,CAQhB,2BAGM,CACJ,OAAO,CAAE,YAAY,CACrB,cAAc,CAAE,QAAQ,CAQ1B,qBAAsB,CACpB,OAAO,CAAE,IAAI,CACb,MAAM,CAAE,CAAC,CAQX,iBACS,CACP,OAAO,CAAE,IAAI,CAUf,CAAE,CACA,gBAAgB,CAAE,WAAW,CAO/B,gBACQ,CACN,OAAO,CAAE,CAAC,CAUZ,WAAY,CACV,aAAa,CAAE,UAAU,CAO3B,QACO,CACL,WAAW,CAAE,IAAI,CAOnB,GAAI,CACF,UAAU,CAAE,MAAM,CAQpB,EAAG,CACD,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,QAAQ,CAOlB,IAAK,CACH,UAAU,CAAE,IAAI,CAChB,KAAK,CAAE,IAAI,CAOb,KAAM,CACJ,SAAS,CAAE,GAAG,CAOhB,OACI,CACF,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,CAAC,CACd,QAAQ,CAAE,QAAQ,CAClB,cAAc,CAAE,QAAQ,CAG1B,GAAI,CACF,GAAG,CAAE,MAAM,CAGb,GAAI,CACF,MAAM,CAAE,OAAO,CAUjB,GAAI,CACF,MAAM,CAAE,CAAC,CAOX,cAAe,CACb,QAAQ,CAAE,MAAM,CAUlB,MAAO,CACL,MAAM,CAAE,QAAQ,CAOlB,EAAG,CACD,eAAe,CAAE,WAAW,CAC5B,UAAU,CAAE,WAAW,CACvB,MAAM,CAAE,CAAC,CAOX,GAAI,CACF,QAAQ,CAAE,IAAI,CAOhB,iBAGK,CACH,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAkBhB,qCAIS,CACP,KAAK,CAAE,OAAO,CACd,IAAI,CAAE,OAAO,CACb,MAAM,CAAE,CAAC,CAOX,MAAO,CACL,QAAQ,CAAE,OAAO,CAUnB,aACO,CACL,cAAc,CAAE,IAAI,CAWtB,yEAGqB,CACnB,kBAAkB,CAAE,MAAM,CAC1B,MAAM,CAAE,OAAO,CAOjB,qCACqB,CACnB,MAAM,CAAE,OAAO,CAOjB,gDACwB,CACtB,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CAQZ,KAAM,CACJ,WAAW,CAAE,MAAM,CAWrB,0CACoB,CAClB,UAAU,CAAE,UAAU,CACtB,OAAO,CAAE,CAAC,CASZ,+FACgD,CAC9C,MAAM,CAAE,IAAI,CASd,oBAAqB,CACnB,kBAAkB,CAAE,SAAS,CAC7B,eAAe,CAAE,WAAW,CAC5B,kBAAkB,CAAE,WAAW,CAC/B,UAAU,CAAE,WAAW,CASzB,kGACgD,CAC9C,kBAAkB,CAAE,IAAI,CAO1B,QAAS,CACP,MAAM,CAAE,iBAAiB,CACzB,MAAM,CAAE,KAAK,CACb,OAAO,CAAE,qBAAqB,CAQhC,MAAO,CACL,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CAOZ,QAAS,CACP,QAAQ,CAAE,IAAI,CAQhB,QAAS,CACP,WAAW,CAAE,IAAI,CAUnB,KAAM,CACJ,eAAe,CAAE,QAAQ,CACzB,cAAc,CAAE,CAAC,CAGnB,KACG,CACD,OAAO,CAAE,CAAC,CCzaZ,qFAAqF,AAOrF,YAAa,CACT,kBAEQ,CACJ,UAAU,CAAE,sBAAsB,CAClC,KAAK,CAAE,eAAe,CACtB,UAAU,CAAE,eAAe,CAC3B,WAAW,CAAE,eAAe,CAGhC,WACU,CACN,eAAe,CAAE,SAAS,CAG9B,aAAc,CACV,OAAO,CAAE,mBAAmB,CAGhC,iBAAkB,CACd,OAAO,CAAE,oBAAoB,CAKjC,+CAC6B,CACzB,OAAO,CAAE,EAAE,CAGf,cACW,CACP,MAAM,CAAE,cAAc,CACtB,iBAAiB,CAAE,KAAK,CAG5B,KAAM,CACF,OAAO,CAAE,kBAAkB,CAG/B,MACI,CACA,iBAAiB,CAAE,KAAK,CAG5B,GAAI,CACA,SAAS,CAAE,eAAe,CAG9B,OAEG,CACC,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CAGb,KACG,CACC,gBAAgB,CAAE,KAAK,CAO3B,MAAO,CACH,UAAU,CAAE,eAAe,CAI/B,OAAQ,CACJ,OAAO,CAAE,IAAI,CAIb,+BAAS,CACL,gBAAgB,CAAE,eAAe,CAGzC,MAAO,CACH,MAAM,CAAE,cAAc,CAG1B,MAAO,CACH,eAAe,CAAE,mBAAmB,CAEpC,mBACG,CACC,gBAAgB,CAAE,eAAe,CAIrC,qCACG,CACC,MAAM,CAAE,yBAAyB,EC3F7C,CAAE,CCgEA,kBAAkB,CD/DE,UAAU,CCgE3B,eAAe,CDhEE,UAAU,CCiEtB,UAAU,CDjEE,UAAU,CAEhC,gBACQ,CC4DN,kBAAkB,CD3DE,UAAU,CC4D3B,eAAe,CD5DE,UAAU,CC6DtB,UAAU,CD7DE,UAAU,CAMhC,IAAK,CACH,SAAS,CAAE,IAAI,CACf,2BAA2B,CAAE,WAAa,CAG5C,IAAK,CACH,WAAW,CESkB,2CAAiB,CFR9C,SAAS,CG2Be,IAAI,CH1B5B,WAAW,CGsCa,OAAW,CHrCnC,KAAK,CEwgBmB,IAAW,CFvgBnC,gBAAgB,CEsgBM,IAAQ,CFlgBhC,4BAGS,CACP,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,OAAO,CAClB,WAAW,CAAE,OAAO,CAMtB,CAAE,CACA,KAAK,CEgmB8B,OAAc,CF/lBjD,eAAe,CAAE,IAAI,CAErB,eACQ,CACN,KAAK,CEqawB,OAAiB,CFpa9C,eAAe,CGZK,SAAS,CHe/B,OAAQ,CIrDR,OAAO,CAAE,WAAW,CAEpB,OAAO,CAAE,iCAAiC,CAC1C,cAAc,CAAE,IAAI,CJ6DtB,MAAO,CACL,MAAM,CAAE,CAAC,CAMX,GAAI,CACF,cAAc,CAAE,MAAM,CAIxB,eAAgB,CKvEd,OAAO,CADuB,KAAK,CAEnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CL0Ed,YAAa,CACX,aAAa,CG2Ba,GAAG,CHrB/B,cAAe,CACb,OAAO,CGwoBqB,GAAG,CHvoB/B,WAAW,CG3Ba,OAAW,CH4BnC,gBAAgB,CEscM,IAAQ,CFrc9B,MAAM,CAAE,cAA2B,CACnC,aAAa,CEnCgB,GAAwB,CD2HrD,kBAAkB,CAAE,oBAAW,CAC1B,aAAa,CAAE,oBAAW,CACvB,UAAU,CAAE,oBAAW,CIlL/B,OAAO,CL4FiB,YAAY,CK3FpC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CL8Fd,WAAY,CACV,aAAa,CAAE,GAAG,CAMpB,EAAG,CACD,UAAU,CEqFgB,IAAqB,CFpF/C,aAAa,CEoFa,IAAqB,CFnF/C,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,cAAoB,CAQlC,QAAS,CACP,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,GAAG,CACV,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,CAAC,CACV,QAAQ,CAAE,MAAM,CAChB,IAAI,CAAE,gBAAa,CACnB,MAAM,CAAE,CAAC,CAQT,kDACQ,CACN,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CACjB,IAAI,CAAE,IAAI,CM3Id,yCAC6B,CAC3B,WAAW,CH8Da,OAAO,CG7D/B,WAAW,CH8Da,GAAG,CG7D3B,WAAW,CH8Da,GAAG,CG7D3B,KAAK,CH8DmB,OAAO,CG5D/B,+OACO,CACL,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,KAAK,CJ8lB0B,IAAW,CI1lB9C,oBAEQ,CACN,UAAU,CJ4KgB,IAAqB,CI3K/C,aAAa,CAAE,IAA2B,CAE1C,uHACO,CACL,SAAS,CAAE,GAAG,CAGlB,oBAEQ,CACN,UAAU,CAAE,IAA2B,CACvC,aAAa,CAAE,IAA2B,CAE1C,uHACO,CACL,SAAS,CAAE,GAAG,CAIlB,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGZxD,MAAQ,CAAE,SAAS,CHaO,IAA+B,CGZzD,MAAQ,CAAE,SAAS,CHaO,IAA6B,CGZvD,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGZxD,MAAQ,CAAE,SAAS,CHaO,IAAe,CGZzC,MAAQ,CAAE,SAAS,CHaO,IAA8B,CGPxD,CAAE,CACA,MAAM,CAAE,QAA+B,CAGzC,KAAM,CACJ,aAAa,CJwIa,IAAqB,CIvI/C,SAAS,CAAE,IAA+B,CAC1C,WAAW,CAAE,GAAG,CAChB,WAAW,CAAE,GAAG,CAEhB,yBAAmC,CANrC,KAAM,CAOF,SAAS,CAAE,IAAuB,EAStC,YACO,CACL,SAAS,CAAE,GAAkD,CAG/D,UACM,CACJ,gBAAgB,CJ8bK,OAAiB,CI7btC,OAAO,CAAE,IAAI,CAIf,UAAqB,CAAE,UAAU,CAAE,IAAI,CACvC,WAAqB,CAAE,UAAU,CAAE,KAAK,CACxC,YAAqB,CAAE,UAAU,CAAE,MAAM,CACzC,aAAqB,CAAE,UAAU,CAAE,OAAO,CAC1C,YAAqB,CAAE,WAAW,CAAE,MAAM,CAG1C,eAAqB,CAAE,cAAc,CAAE,SAAS,CAChD,eAAqB,CAAE,cAAc,CAAE,SAAS,CAChD,gBAAqB,CAAE,cAAc,CAAE,UAAU,CAGjD,WAAY,CACV,KAAK,CJ2gB4B,IAAW,CK7mB5C,aAAW,CACT,KAAK,CL2oB4B,OAAc,CKzoBjD,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,aAAW,CACT,KAAK,CL4gBgB,OAAmB,CK1gB1C,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,UAAW,CACT,KAAK,CLwgBc,OAAgB,CKtgBrC,iBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,aAAW,CACT,KAAK,CL8gBgB,OAAmB,CK5gB1C,oBAAkB,CAChB,KAAK,CAAE,OAAmB,CAJ5B,YAAW,CACT,KAAK,CLghBe,OAAkB,CK9gBxC,mBAAkB,CAChB,KAAK,CAAE,OAAmB,CD8G9B,WAAY,CAGV,KAAK,CAAE,IAAI,CErHX,WAAW,CACT,gBAAgB,CN2oBiB,OAAc,CMzoBjD,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,WAAW,CACT,gBAAgB,CN2gBG,OAAiB,CMzgBtC,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,QAAW,CACT,gBAAgB,CNugBC,OAAc,CMrgBjC,eAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,WAAW,CACT,gBAAgB,CN6gBG,OAAiB,CM3gBtC,kBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CAJvC,UAAW,CACT,gBAAgB,CN+gBE,OAAgB,CM7gBpC,iBAAkB,CAChB,gBAAgB,CAAE,OAAmB,CFiIzC,YAAa,CACX,cAAc,CAAE,GAAiC,CACjD,MAAM,CAAE,WAAmD,CAC3D,aAAa,CAAE,cAAmC,CAQpD,KACG,CACD,UAAU,CAAE,CAAC,CACb,aAAa,CAAE,IAA2B,CAC1C,uBACG,CACD,aAAa,CAAE,CAAC,CAYpB,cAAe,CAJb,YAAY,CAAE,CAAC,CACf,UAAU,CAAE,IAAI,CASlB,YAAa,CAVX,YAAY,CAAE,CAAC,CACf,UAAU,CAAE,IAAI,CAWhB,WAAW,CAAE,IAAI,CAEjB,eAAK,CACH,OAAO,CAAE,YAAY,CACrB,YAAY,CAAE,GAAG,CACjB,aAAa,CAAE,GAAG,CAKtB,EAAG,CACD,UAAU,CAAE,CAAC,CACb,aAAa,CJYa,IAAqB,CIVjD,KACG,CACD,WAAW,CH3Ha,OAAW,CG6HrC,EAAG,CACD,WAAW,CAAE,IAAI,CAEnB,EAAG,CACD,WAAW,CAAE,CAAC,CGvLd,gDACQ,CACN,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAEhB,uBAAQ,CACN,KAAK,CAAE,IAAI,CH8Lb,yBAA2C,CACzC,iBAAG,CACD,KAAK,CAAE,IAAI,CACX,KAAK,CAAE,KAA4B,CACnC,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,KAAK,CIlNrB,QAAQ,CAAE,MAAM,CAChB,aAAa,CAAE,QAAQ,CACvB,WAAW,CAAE,MAAM,CJmNjB,iBAAG,CACD,WAAW,CHmoBa,KAA4B,EGznB1D,qCAE0B,CACxB,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,eAA6B,CAE9C,WAAY,CACV,SAAS,CAAE,GAAG,CACd,cAAc,CAAE,SAAS,CAI3B,UAAW,CACT,OAAO,CAAE,SAAiD,CAC1D,MAAM,CAAE,QAAyB,CACjC,SAAS,CHomBoB,MAAsB,CGnmBnD,WAAW,CAAE,cAAkC,CAK7C,yEAAa,CACX,aAAa,CAAE,CAAC,CAMpB,oDAEO,CACL,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,GAAG,CACd,WAAW,CHlMW,OAAW,CGmMjC,KAAK,CJ2W0B,IAAW,CIzW1C,yEAAS,CACP,OAAO,CAAE,aAAa,CAQ5B,yCACsB,CACpB,aAAa,CAAE,IAAI,CACnB,YAAY,CAAE,CAAC,CACf,YAAY,CAAE,cAAkC,CAChD,WAAW,CAAE,CAAC,CACd,UAAU,CAAE,KAAK,CAMf,+MAAS,CAAE,OAAO,CAAE,EAAE,CACtB,yMAAQ,CACN,OAAO,CAAE,aAAa,CAM5B,OAAQ,CACN,aAAa,CJhGa,IAAqB,CIiG/C,UAAU,CAAE,MAAM,CAClB,WAAW,CHrOa,OAAW,CQhErC,UAWC,CAVC,WAAW,CAAE,aAAa,CAC1B,GAAG,CAAE,+DAAgE,CACrE,GAAG,CAAE,wbAI8F,CAEnG,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CCVpB,OAAmB,CACjB,OAAO,CAAE,YAAY,CACrB,IAAI,CAAE,uCAA8E,CACpF,SAAS,CAAE,OAAO,CAClB,cAAc,CAAE,IAAI,CACpB,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CCJpC,+DAAiC,CAChC,aAAa,CAAE,GAAG,CAEnB,qCAA2B,CAC1B,UAAU,CAAE,GAAG,CAMhB,oCAA6C,CAC5C,aAAa,CAAE,KAAK,CAErB,iCAAuC,CACtC,UAAU,CAAE,KAAK,CAMlB,oCAA6C,CAC5C,aAAa,CAAE,GAAG,CAEnB,iCAAuC,CACtC,UAAU,CAAE,GAAG,CAMhB,+EAAiC,CAChC,OAAO,CAAE,YAAY,CAEtB,yCAA2C,CAE1C,WAAW,CAAE,KAAK,CAGnB,0CAA6C,CAE5C,YAAY,CAAE,KAAK,CAQpB,yBAA0B,CACzB,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CAEb,yBAA0B,CACzB,OAAO,CAAE,UAAU,CACnB,cAAc,CAAE,MAAM,CACtB,UAAU,CAAE,MAAM,CAInB,gBAAiB,CAChB,iBAAiB,CAAC,SAAS,CAC3B,mBAAmB,CAAE,MAAM,CAC3B,eAAe,CAAE,KAAK,CACtB,qBAAK,CACJ,OAAO,CAAE,GAAG,CACZ,gBAAgB,CX+kBY,qBAAwB,CW5kBrD,sHACE,CACD,OAAO,CAAE,GAAG,CACZ,gBAAgB,CXykBY,qBAAwB,CWxkBpD,OAAO,CAAE,YAAY,CACrB,0JAAQ,CACP,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAOjB,gCAA+B,CAE9B,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,MAAM,CAEf,kBAAkB,CAAE,wBAAwB,CAC5C,0BAA0B,CAAE,KAAK,CAIrC,eAAgB,CAEf,UAAU,CAAE,MAAM,CAClB,yFAA6B,CAC5B,YAAY,CAAE,GAAG,CACjB,aAAa,CAAE,KAAK,CACpB,qIAAa,CACZ,YAAY,CAAE,CAAC,CAIhB,+FAAiB,CAChB,YAAY,CAAE,CAAC,CACf,aAAa,CAAE,CAAC,CAGlB,8BAAe,CACd,UAAU,CAAE,IAAI,CAIlB,oBAAqB,CACpB,UAAU,CAAE,IAAI,CAEjB,qBAAsB,CACrB,UAAU,CAAE,KAAK,CAElB,mBAAoB,CACnB,UAAU,CAAE,CAAC,CJjHZ,0DACQ,CACN,OAAO,CAAE,GAAG,CACZ,OAAO,CAAE,KAAK,CAEhB,4BAAQ,CACN,KAAK,CAAE,IAAI,CIiHd,2JAAuB,CACtB,OAAO,CAAE,YAAY,CAEtB,sCAAgB,CACf,aAAa,CAAE,CAAC,CAChB,KAAK,CAAE,KAAK,CAGb,yCAAoB,CAClB,UAAU,CAAE,IAA6B,CAE3C,yCAAoB,CAClB,UAAU,CAAE,IAA6B,CAE3C,yCAAoB,CAClB,UAAU,CXmDe,IAAqB,CWjDhD,yCAAoB,CAClB,UAAU,CAAE,IAA2B,CAEzC,yCAAoB,CAClB,UAAU,CAAE,SAA2B,CAEzC,yCAAoB,CAClB,UAAU,CAAE,GAA2B,CAI1C,wDAA0D,CACzD,UAAU,CAAE,CAAC,CAGd,oCAAqC,CACpC,aAAa,CAAE,CAAC,CAKhB,0BAAS,CAAC,OAAO,CAAC,GAAG,CACrB,yBAAQ,CAAC,OAAO,CAAC,GAAG,CAKrB,cAAe,CACd,iBAAiB,CAAC,SAAS,CAC3B,mBAAmB,CAAE,MAAM,CAC3B,eAAe,CAAE,KAAK,CAEtB,2CAA+B,CAC9B,gBAAgB,CXgeY,qBAAwB,CW/dpD,aAAa,CAAE,WAAW,CAE3B,+BAAiB,CAChB,OAAO,CAAE,GAAG,CACZ,gBAAgB,CX2dY,qBAAwB,CWtdtD,kBAAmB,CAClB,YAAY,CXgcuB,GAAG,CW/btC,YAAY,CAAE,MAAM,CACpB,YAAY,CXkcuB,OAAwC,CWjc3E,aAAa,CX8buB,IAAI,CW5bxC,8BAAY,CACX,OAAO,CX+buB,IAAI,CW9blC,6CAAiB,CAChB,UAAU,CAAE,IAAI,CAEjB,4IAEgB,CACf,UAAU,CAAE,CAAC,CAGd,8CAAgB,CACf,aAAa,CAAE,CAAC,CAGlB,iCAAe,CACd,uBAAuB,CAAE,GAAwE,CACjG,sBAAsB,CAAE,GAAwE,CAChG,YAAY,CXyasB,GAAG,CWxarC,YAAY,CAAE,MAAM,CACpB,YAAY,CX2asB,OAAwC,CW1a1E,UAAU,CAAE,IAAI,CAChB,WAAW,CAAE,IAAI,CACjB,YAAY,CAAE,IAAI,CAClB,KAAK,CXkb8B,OAAc,CWjbjD,WAAW,CXqasB,IAAI,CWnatC,gCAAc,CACb,0BAA0B,CAAE,GAAwE,CACpG,yBAAyB,CAAE,GAAwE,CACnG,YAAY,CX6ZsB,GAAG,CW5ZrC,YAAY,CAAE,MAAM,CACpB,YAAY,CX+ZsB,OAAwC,CW9Z1E,aAAa,CAAE,IAAI,CACnB,WAAW,CAAE,IAAI,CACjB,YAAY,CAAE,IAAI,CASpB,2CAAqB,CACpB,SAAS,CX6WY,IAAgB,CW3WtC,uCAAmB,CAClB,SAAS,CX0WY,IAAgB,CWxWtC,uCAAmB,CAClB,SAAS,CXgZiB,IAAgB,CW9Y3C,2CAAqB,CACpB,SAAS,CX6YiB,IAAgB,CWzY3C,mDAAyB,CACxB,KAAK,CAAE,eAAoC,CAK3C,MAAM,CAAE,OAAO,CAJf,mCAAO,CACN,KAAK,CAAE,eAAoC,CAM7C,2CAAqB,CCtQnB,OAAO,CDuQS,EAAE,CCpQlB,MAAM,CAAE,iBAA6B,CDuQvC,mDAAyB,CACxB,WAAW,CAAE,IAAI,CAGlB,+CAAuB,CACtB,eAAe,CAAE,YAAY,CAG9B,2BAA4B,CAC3B,gBAAgB,CX4N6B,OAAe,CWxN7D,YAA2B,CAC1B,MAAM,CAAE,OAAO,CAIhB,QAAS,CAAE,KAAK,CAAE,OAAO,CACzB,OAAQ,CAAE,KAAK,CAAE,OAAO,CAKvB,iHAAgB,CACf,eAAe,CAAE,IAAI,CAKvB,gEAA2B,CACxB,WAAW,CVxPY,6CAAiD,CUyPxE,OAAO,CAAE,OAAO,CAChB,SAAS,CAAE,GAAG,CACd,KAAK,CV6gBsB,OAAO,CU5gBnC,gBAAgB,CV6gBY,OAAO,CU5gBlC,aAAa,CVjMY,GAAG,CUmM5B,iIAAe,CACd,MAAM,CAAE,CAAC,CACT,KAAK,CAAE,GAAG,CACV,UAAU,CAAE,WAAW,CAK3B,yDAAqB,CACpB,WAAW,CAAE,MAAM,CACnB,QAAQ,CAAE,MAAM,CAChB,aAAa,CAAE,QAAQ,CAKvB,4BAAW,CACV,UAAU,CAAE,IAA2B,CAKzC,iDAAqD,CRhUnD,OAAO,CQiUgB,YAAY,CRhUnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CQgUb,SAAS,CAAE,IAAI,CAEhB,kCAAiC,CRpU/B,OAAO,CQqUgB,YAAY,CRpUnC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,IAAI,CQoUb,SAAS,CAAE,IAAI,CAIhB,wBAAyB,CACxB,OAAO,CAAE,YAAY,CACrB,SAAS,CAAE,GAAG,CACd,+BAAO,CACN,OAAO,CAAE,KAAK,CAEf,mCAAW,CACV,OAAO,CAAE,aAAa,CACtB,YAAY,CAAE,MAAM,CACpB,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,MAAM,CAMpB,+BAAgC,CAC/B,OAAO,CAAE,YAAY,CAClB,MAAM,CAAE,IAAI,CACZ,cAAc,CAAE,MAAM,CACtB,4CAAgB,CACf,cAAc,CAAE,MAAM,CAK3B,eAAiC,CAChC,eAAe,CAAE,IAAI,CACrB,YAAY,CAAE,IAAI,CAClB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,IAAI,CEjXd,mCAAiB,CCChB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,cAAyC,CACtD,gBAAgB,CdqgBI,IAAa,CcpgBjC,uFAAe,CAAE,KAAK,Cd2mBY,IAAW,Ca7mB9C,mCAAiB,CCFhB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdugBI,OAAc,CctgBlC,uFAAe,CAAE,KAAK,CdugBA,OAAgB,CatgBvC,uDAA2B,CCL1B,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,CdygBQ,OAAO,CcxgB/B,+HAAe,CAAE,KAAK,CdygBI,OAAO,CargBlC,+CAAuB,CCRtB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,Cd2gBM,OAAiB,Cc1gBvC,+GAAe,CAAE,KAAK,Cd2gBE,OAAmB,CapgB5C,+CAAuB,CCXtB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,Cd6gBM,OAAiB,Cc5gBvC,+GAAe,CAAE,KAAK,Cd6gBE,OAAmB,CangB5C,uCAAmB,CCdlB,MAAM,CAAE,MAAe,CACvB,OAAO,CdqgBa,IAAI,CcpgBxB,WAAW,CAAE,iBAAyC,CACtD,gBAAgB,Cd+gBK,OAAgB,Cc9gBrC,+FAAe,CAAE,KAAK,Cd+gBC,OAAkB,Ca/f1C,qBAAsB,CACrB,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CAAE,IAAI,CAAE,CAAC,CACf,KAAK,CAAC,IAAI,CAAE,MAAM,CAAC,IAAI,CACvB,IAAI,CAAC,CAAC,CACN,UAAU,CAAE,IAAI,CDxBf,OAAO,CCyBS,CAAC,CDtBjB,MAAM,CAAE,gBAA6B,CC0BvC,aAAc,CACb,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,KAAK,CACV,IAAI,CAAE,CAAC,CACP,OAAO,CAAE,IAAI,CACZ,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,MAAM,CAElB,oBAAO,CACP,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAC,MAAM,CACb,UAAU,CAAE,IAAI,CduBhB,kBAAkB,CAAE,iCAAO,CACnB,UAAU,CAAE,iCAAO,CcrB3B,mCAAe,CACd,KAAK,CAAE,KAAK,CACZ,KAAK,Cb+jB2B,IAAW,Ca9jB3C,yCAAQ,CACP,KAAK,CbslBe,IAAoB,CanlB1C,yBAAmC,CAdnC,oBAAO,CAgBH,KAAK,CZ0iBmB,KAAK,EYpiBnC,mCAAqC,CACpC,QAAQ,CAAE,QAAQ,CAClB,KAAK,CbodkB,OAAkB,CandzC,gBAAgB,CbkdK,OAAgB,CajdrC,MAAM,CAAE,iBAA8B,CACtC,OAAO,CAAE,mBAAmG,CAC5G,UAAU,CAAE,IAAyB,CAErC,MAAM,CAAE,cAAgD,CAExD,qEAAiB,CAChB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,IAAgC,CACtC,GAAG,CAAE,GAAgC,CACrC,SAAS,CAAE,IAAyB,CAGrC,mFAA0B,CACzB,UAAU,CAAE,CAAC,CAOb,yBAAmC,CADpC,yBAAmB,CAEjB,KAAK,CAAE,GAAG,EAEX,yBAAmC,CAJpC,yBAAmB,CAKjB,KAAK,CAAE,GAAG,EAGZ,uBAAiB,CAChB,KAAK,CbgjB8B,OAAc,Ca/iB/C,WAAW,CbsWgB,GAAqB,CarWlD,WAAW,CZ1Ba,OAAO,CY2B7B,WAAW,CZzBW,GAAG,CczE7B,qBAA0B,CAAC,UAAU,CAAG,+CAAgD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACnH,qBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,wBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,wBAA0B,CAAC,UAAU,CAAG,iDAAkD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACrH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,mBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,qBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,mBAA0B,CAAC,UAAU,CAAG,6CAA8C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACjH,oBAA0B,CAAC,UAAU,CAAG,kDAAmD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACtH,qBAA0B,CAAC,UAAU,CAAG,yCAA0C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAC7G,sBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,+CAAgD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACnH,qBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,oBAA0B,CAAC,UAAU,CAAG,8CAA+C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAClH,uBAA0B,CAAC,UAAU,CAAG,mDAAoD,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CACvH,kBAAwB,CAAC,UAAU,CAAG,2CAA4C,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CAC7G,oBAA0B,CAAC,UAAU,CAAG,wCAAyC,CAAE,KAAK,CAAE,IAAI,CAAE,MAAM,CAAE,IAAI,CCA5G,IAAK,CACH,WAAW,ChBekB,2CAAiB,CgBd9C,SAAS,ChBekB,IAAe,CgBd1C,WAAW,ChBekB,OAAiB,CgBd9C,KAAK,ChB8gBmB,IAAW,CgB7gBnC,gBAAgB,ChB4gBM,IAAQ,CgBzgBhC,CAAE,CACA,KAAK,ChBmnB8B,OAAc,CgBlnBjD,eAAe,CAAE,IAAI,CAErB,eACQ,CACN,KAAK,ChBwbwB,OAAiB,CgBvb9C,eAAe,ChBSW,SAAS,CgBNrC,OAAQ,CdlCR,OAAO,CAAE,WAAW,CAEpB,OAAO,CAAE,iCAAiC,CAC1C,cAAc,CAAE,IAAI,CcoCtB,EAAG,CACF,KAAK,ChBomB+B,OAAc,CgBlmBnD,EAAG,CACF,KAAK,ChBimB+B,OAAc,CgB/lBnD,EAAG,CACF,KAAK,ChB8lB+B,OAAc,CgB5lBnD,EAAG,CACF,KAAK,ChB2lB+B,OAAc,CgBzlBnD,EAAG,CACF,KAAK,ChBwlB+B,OAAc,CgBtlBnD,EAAG,CACF,KAAK,ChBqlB+B,OAAc,CgBnlBnD,EAAG,CACF,UAAU,CAAE,cAA4C,CCtDxD,uBAAE,CACD,KAAK,CjBuoB8B,OAAc,CiBtoBjD,eAAe,CAAE,IAAI,CACrB,2DACQ,CACP,KAAK,CjB6cyB,OAAiB,CiB5c/C,eAAe,CjB8BY,SAAS,CiBAvC,6CAAgD,CAC/C,MAAM,CAAE,cAAsC,CAC9C,OAAO,CjBcwB,GAAG,CkBzDjC,uBAAuB,ClBwDM,GAAoB,CkBvDhD,sBAAsB,ClBuDM,GAAoB,CkBhDjD,0BAA0B,ClBgDG,GAAoB,CkB/ChD,yBAAyB,ClB+CG,GAAoB,CiBoBlD,QAAG,CACF,cAAc,CAAE,GAAG,CAGpB,YAAS,CACR,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,cAAiC,CAE1C,qCAAa,CACZ,UAAU,CjB8aQ,IAAa,CiB7a/B,WAAW,CAAE,IAAI,CAGnB,cAAW,CACV,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,mCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,cAAiC,CAE1C,yCAAa,CACZ,UAAU,CjBiaQ,IAAa,CiBha/B,WAAW,CAAE,IAAI,CAGnB,kBAAe,CACd,KAAK,CAAE,KAAK,CACZ,UAAU,CAAE,WAAW,CACvB,eAAe,CAAE,QAAQ,CACzB,2CAAO,CACN,OAAO,CAAE,OAA2C,CACpD,MAAM,CAAE,CAAC,CAEV,iDAAa,CACZ,WAAW,CAAE,IAAI,CAGnB,YAAS,CACR,KAAK,CAAE,KAAK,CAEb,cAAW,CACV,UAAU,CAAE,WAAW,CACvB,iBAAG,CACF,cAAc,CAAE,MAAM,CAGxB,YAAS,CAlET,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBucS,IAAa,CiBtchC,MAAM,CAAE,cAA+B,CAExC,qCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CA6DlB,YAAS,CArET,eAAe,CAAE,QAAQ,CACzB,+BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBycS,OAAc,CiBxcjC,MAAM,CAAE,cAA+B,CAExC,qCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAgElB,aAAU,CAxEV,eAAe,CAAE,QAAQ,CACzB,iCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjB6cW,OAAiB,CiB5ctC,MAAM,CAAE,cAA+B,CAExC,uCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAmElB,cAAW,CA3EX,eAAe,CAAE,QAAQ,CACzB,mCAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjB+cW,OAAiB,CiB9ctC,MAAM,CAAE,cAA+B,CAExC,yCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAsElB,WAAQ,CA9ER,eAAe,CAAE,QAAQ,CACzB,6BAAO,CACN,OAAO,CAAE,OAA2C,CACpD,UAAU,CjBidU,OAAgB,CiBhdpC,MAAM,CAAE,cAA+B,CAExC,mCAAa,CACZ,UAAU,CAAE,OAAoB,CAChC,WAAW,CAAE,IAAI,CAwGnB,eAAgB,CACf,UAAU,CAAE,IAAI,CAEjB,eAAgB,CACf,UAAU,CAAE,MAAM,CAEnB,gBAAiB,CAChB,UAAU,CAAE,KAAK,CAElB,kBAAmB,CAClB,UAAU,CAAC,OAAO,CAInB,eAAgB,CACf,KAAK,CjBid+B,OAAc,CiBhdlD,sBAAS,CHpLR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CGgLlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEwDc,GAAO,CFrD9B,eAAgB,CACf,KAAK,CjByc+B,OAAc,CiBxclD,sBAAS,CH5LR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CGwLlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEiCW,GAAO,CF7B3B,gBAAiB,CAChB,KAAK,CjBgc+B,OAAc,CiB/blD,uBAAS,CHrMR,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,WAAW,CACxB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CGiMlC,aAAa,CAAE,KAAK,CACpB,OAAO,CEkXM,GAAO,CFxWtB,gBAAiB,CAChB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,WAAW,CAEpB,sBAAuB,CACtB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,WAAW,CACnB,OAAO,CAAE,KAAK,CAEf,iBAAkB,CACjB,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,WAAW,CAEpB,uBAAwB,CACvB,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,YAAY,CAErB,+BAAgC,CAC/B,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,OAAO,CAEhB,cAAe,CACd,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,eAAe,CAExB,YAAa,CACZ,aAAa,CAAE,GAAG,CAEnB,iBAAkB,CACjB,MAAM,CAAE,cAAsC,CAC9C,OAAO,CjBhMwB,GAAG,CkB5DjC,uBAAuB,ClB2DM,GAAwB,CkB1DpD,sBAAsB,ClB0DM,GAAwB,CkBnDrD,0BAA0B,ClBmDG,GAAwB,CkBlDpD,yBAAyB,ClBkDG,GAAwB,CiB+MvD,gBAAiB,CAChB,MAAM,CAAE,YAAqD,CAC7D,SAAS,CAAE,GAAkD,CAC7D,WAAW,ChBxMc,OAAO,CgB0MjC,kBAAmB,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,YAAqD,CAC7D,SAAS,CAAE,GAAkD,CAC7D,WAAW,ChB9Mc,OAAO,CgBkNjC,gDAAmD,CAClD,KAAK,CAAE,IAAI,CGtRZ,iBAAkB,CACd,KAAK,CAAE,IAAI,CAGf,kBAAmB,CACf,KAAK,CAAE,KAAK,CAGhB,YAAa,CACT,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,cAAc,CACtB,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,OAAO,CAGvB,gBAAiB,CACb,MAAM,CAAE,aAAa,CAGzB,uBAAwB,CACpB,MAAM,CAAE,eAAe,CACvB,UAAU,CAAE,MAAM,CAOtB,cAAe,CACX,KAAK,CAAE,IAAI,CAGf,eAAgB,CACZ,KAAK,CAAE,KAAK,CAIhB,QAAS,CACL,MAAM,CAAE,cAAc,CAG1B,WAAY,CACR,MAAM,CAAE,GAAG,CAGf,WAAY,CACR,eAAe,CAAE,IAAI,CAQxB,yBAAe,CACd,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,MAAM,CAEnB,uBAAa,CACZ,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,IAAI,CAChB,kCAAW,CACV,UAAU,CAAE,IAAI,CAGlB,wBAAc,CACb,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,KAAK,CACjB,mCAAW,CACV,UAAU,CAAE,KAAK,CAMpB,YAAa,CACZ,MAAM,CAAE,WAAW,CAChB,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,IAAI,CAGlB,8MAKa,CACZ,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,CAAC,CAGX,uBAAW,CACV,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,MAAM,CCxFpB,YAAa,CAGZ,aAAc,CACV,OAAO,CAAE,EAAE,CAIf,wLAYW,CACV,OAAO,CAAE,eAAe,CAIzB,oBAAqB,CACpB,iBAAiB,CAAG,KAAK,CAE1B,qBAAsB,CACrB,iBAAiB,CAAE,MAAM,CAE1B,oBAAqB,CACpB,KAAK,CAAC,IAAI,CACV,gBAAgB,CAAC,MAAM,CAIxB,IAAK,CACJ,OAAO,CAAE,IAAI,CAIb,wDACgC,CAC/B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,UAAU,CAAE,eAAe,CAC3B,MAAM,CAAE,eAAe,CACvB,KAAK,CAAE,eAAe,CACtB,MAAM,CAAE,IAAI,CAKd,qCACiB,CACf,OAAO,CAAE,eAAe,CAI1B,SAAU,CACT,OAAO,CAAE,IAAI,CAId,UAAW,CACV,UAAU,CAAE,gBAAgB,CAC5B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CAIpB,aAAc,CACb,MAAM,CAAE,YAAY,CACpB,KAAK,CAAE,eAAe,CACtB,MAAM,CAAE,eAAe,CACvB,UAAU,CAAE,eAAe,CAC3B,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CAIpB,SAAU,CACT,iBAAiB,CAAG,KAAK,CACzB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACjB,gBAAgB,CAAE,0BAAyB,CAC3C,MAAM,CAAE,yBAAwB,CAEnC,aAAc,CACb,0BAA0B,CAAE,KAAK,CACjC,gBAAgB,CAAE,eAAe,CAEjC,MAAM,CAAE,eAAe,CAIxB,iDAAkD,CACjD,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,UAAU,CAAE,kBAA+B,CAC3C,mEAAkB,CACjB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,kBAA6C,CAMjE,gBAAiB,CAChB,iBAAiB,CAAG,KAAK,CACzB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CACjC,oCAAoB,CACnB,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CAElC,uBAAO,CACN,0BAA0B,CAAE,KAAK,CACjC,YAAY,CAAE,KAAK,CACnB,gBAAgB,CAAE,eAAe,CAInC,IAAK,CACJ,MAAM,CAAE,CAAC,CAGV,mBAAsB,CACpB,iBAAiB,CAAE,KAAK,CAG1B,iBAAuB,CACrB,gBAAgB,CAAE,KAAK", +"sources": ["../light/_license.scss","../../bootstrap/stylesheets/bootstrap/_normalize.scss","../../bootstrap/stylesheets/bootstrap/_print.scss","../../bootstrap/stylesheets/bootstrap/_scaffolding.scss","../../bootstrap/stylesheets/bootstrap/mixins/_vendor-prefixes.scss","../light/_config.scss","../../bootstrap/stylesheets/bootstrap/_variables.scss","../../bootstrap/stylesheets/bootstrap/mixins/_tab-focus.scss","../../bootstrap/stylesheets/bootstrap/mixins/_image.scss","../../bootstrap/stylesheets/bootstrap/_type.scss","../../bootstrap/stylesheets/bootstrap/mixins/_text-emphasis.scss","../../bootstrap/stylesheets/bootstrap/mixins/_background-variant.scss","../../bootstrap/stylesheets/bootstrap/mixins/_clearfix.scss","../../bootstrap/stylesheets/bootstrap/mixins/_text-overflow.scss","../../font-awesome/scss/_path.scss","../../font-awesome/scss/_core.scss","../light/modules/_helpers.scss","../../bootstrap/stylesheets/bootstrap/mixins/_opacity.scss","../light/modules/_dialog.scss","../light/modules/_mixins.scss","../light/modules/_emoticons.scss","../light/modules/_content.scss","../light/modules/_content_embedded.scss","../../bootstrap/stylesheets/bootstrap/mixins/_border-radius.scss","../../font-awesome/scss/_variables.scss","../light/modules/_tinymce.scss","../light/modules/_print.scss"], "names": [], "file": "content.css" } \ No newline at end of file diff --git a/src/test/java/org/olat/commons/calendar/CalendarImportTest.java b/src/test/java/org/olat/commons/calendar/CalendarImportTest.java index 5227f27415de5c9c1c218037af36f942d04c42cf..a4364f3b1dfd6bd6ff2fc9808f5998798b4bc2c1 100644 --- a/src/test/java/org/olat/commons/calendar/CalendarImportTest.java +++ b/src/test/java/org/olat/commons/calendar/CalendarImportTest.java @@ -1,4 +1,5 @@ /** + * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> @@ -91,6 +92,17 @@ public class CalendarImportTest { assertNotNull(calendar); } + /* + * Why is this test not reliable??? + @Test(expected = ParserException.class) + public void testImportRefresh() throws IOException, ParserException { + InputStream in = CalendarImportTest.class.getResourceAsStream("Refresh.ics"); + CalendarBuilder builder = new CalendarBuilder(); + Calendar calendar = builder.build(in); + assertNotNull(calendar); + } + */ + @Test @Ignore public void testImportFromFGiCal() throws IOException, ParserException { //default settings in olat @@ -134,16 +146,13 @@ public class CalendarImportTest { Period period = new Period(start, end); PeriodList pList = rootEvent.calculateRecurrenceSet(period); for(Object obj:pList) { - Period p = (Period)obj; - System.out.println("Period: " + p.getStart()); + Period p = (Period)obj; + System.out.println("Period: " + p.getStart()); } RecurrenceId recurrenceId = exceptionEvent.getRecurrenceId(); Date recurrenceDate = recurrenceId.getDate(); System.out.println("Recurrence: " + recurrenceDate); - exceptionEvent.getSequence(); } - - } diff --git a/src/test/java/org/olat/commons/calendar/manager/ICalFileCalendarManagerTest.java b/src/test/java/org/olat/commons/calendar/manager/ICalFileCalendarManagerTest.java index 0d0be10ff4e4203235496c42d0c48bb198442373..85a021e74c631e754beca953f5b38ee942fb68e6 100644 --- a/src/test/java/org/olat/commons/calendar/manager/ICalFileCalendarManagerTest.java +++ b/src/test/java/org/olat/commons/calendar/manager/ICalFileCalendarManagerTest.java @@ -583,9 +583,48 @@ public class ICalFileCalendarManagerTest extends OlatTestCase { .importCalendar(test, calendarName, CalendarManager.TYPE_USER, calendarFile); List<KalendarEvent> events = importedCalendar.getKalendar().getEvents(); Assert.assertEquals(2, events.size()); - } + @Test + public void testImportICal_outlookFullDay() throws URISyntaxException, IOException { + Identity test = JunitTestHelper.createAndPersistIdentityAsRndUser("ur2-"); + URL calendarUrl = ICalFileCalendarManagerTest.class.getResource("Fullday_outlook.ics"); + File calendarFile = new File(calendarUrl.toURI()); + String calendarName = UUID.randomUUID().toString().replace("-", ""); + + KalendarRenderWrapper importedCalendar = importCalendarManager + .importCalendar(test, calendarName, CalendarManager.TYPE_USER, calendarFile); + List<KalendarEvent> events = importedCalendar.getKalendar().getEvents(); + Assert.assertEquals(1, events.size()); + + KalendarEvent event = events.get(0); + Assert.assertTrue(event.isAllDayEvent()); + } + + @Test + public void testImportICal_icalFullDay() throws URISyntaxException, IOException { + Identity test = JunitTestHelper.createAndPersistIdentityAsRndUser("ur3-"); + URL calendarUrl = ICalFileCalendarManagerTest.class.getResource("Fullday_ical.ics"); + File calendarFile = new File(calendarUrl.toURI()); + String calendarName = UUID.randomUUID().toString().replace("-", ""); + + KalendarRenderWrapper importedCalendar = importCalendarManager + .importCalendar(test, calendarName, CalendarManager.TYPE_USER, calendarFile); + List<KalendarEvent> events = importedCalendar.getKalendar().getEvents(); + Assert.assertEquals(3, events.size()); + + // 24 hours but on 2 days + KalendarEvent on2days = importedCalendar.getKalendar().getEvent("EFE10508-15B0-4FCE-A258-37BA642B760D", null); + Assert.assertFalse(on2days.isAllDayEvent()); + // real all day with the iCal standard + KalendarEvent allDay = importedCalendar.getKalendar().getEvent("14C0ACCD-AC0B-4B10-A448-0BF129492091", null); + Assert.assertTrue(allDay.isAllDayEvent()); + // almost a full day bit it miss one minute + KalendarEvent longDay = importedCalendar.getKalendar().getEvent("C562E736-DCFF-4002-9E5B-77D891D4A322", null); + Assert.assertFalse(longDay.isAllDayEvent()); + } + + /** * Test concurrent add event with two threads and code-point to control concurrency. * diff --git a/src/test/java/org/olat/commons/info/InfoManagerTest.java b/src/test/java/org/olat/commons/info/InfoManagerTest.java index d57d2cb0115a01a1e74171c1a99ba1d1f4edc924..63d1f08e63af5303454d855234b221b9dd158cd4 100644 --- a/src/test/java/org/olat/commons/info/InfoManagerTest.java +++ b/src/test/java/org/olat/commons/info/InfoManagerTest.java @@ -33,8 +33,6 @@ import java.util.UUID; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.olat.commons.info.manager.InfoMessageManager; -import org.olat.commons.info.model.InfoMessage; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; diff --git a/src/test/java/org/olat/commons/info/InfoMessageFrontendManagerTest.java b/src/test/java/org/olat/commons/info/InfoMessageFrontendManagerTest.java index f1fb12220c02a4818be6b92a074e7967d892a063..7099e96c8863580c829fef1b378a0baa2cc11c99 100644 --- a/src/test/java/org/olat/commons/info/InfoMessageFrontendManagerTest.java +++ b/src/test/java/org/olat/commons/info/InfoMessageFrontendManagerTest.java @@ -28,8 +28,6 @@ import java.util.UUID; import org.junit.Assert; import org.junit.Test; -import org.olat.commons.info.manager.InfoMessageFrontendManager; -import org.olat.commons.info.model.InfoMessage; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.services.notifications.NotificationsManager; import org.olat.core.commons.services.notifications.Publisher; diff --git a/src/test/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImplTest.java b/src/test/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..601b6d56787f09ce2695cd28d2164ae997b678dd --- /dev/null +++ b/src/test/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImplTest.java @@ -0,0 +1,183 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.commentAndRating.manager; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.core.commons.services.commentAndRating.model.UserComment; +import org.olat.core.commons.services.notifications.NotificationsManager; +import org.olat.core.id.Identity; +import org.olat.resource.OLATResource; + +/** + * + * Initial date: 17.09.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class CommentAndRatingServiceImplTest { + + private static final String RESOURCEABLE_TYPE_NAME = "resurcable type name"; + private static final Long RESOURCABLE_ID = 5L; + private static final String RES_SUB_PATH = "resSubPath"; + private static final String COMMENT_TEXT = "commentText"; + private static final String UPDATED_COMMENT_TEXT = "updated comment"; + private static final String REPLY_TEXT = "my reply"; + private static Identity IGNORE_NEWS_FOR_NOBODY = null; + private static boolean SEND_NO_EVENTS = false; + + @Mock + private Identity identityDummy; + @Mock + private OLATResource resourceMock; + @Mock + private UserComment userCommentMock; + + @Mock + private UserCommentsDAO userCommentsDaoMock; + @Mock + private NotificationsManager notificationsManagerMock; + + @InjectMocks + private CommentAndRatingServiceImpl sut = new CommentAndRatingServiceImpl(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(resourceMock.getResourceableId()).thenReturn(RESOURCABLE_ID); + when(resourceMock.getResourceableTypeName()).thenReturn(RESOURCEABLE_TYPE_NAME); + + when(userCommentMock.getResId()).thenReturn(RESOURCABLE_ID); + when(userCommentMock.getResName()).thenReturn(RESOURCEABLE_TYPE_NAME); + } + + @Test + public void shouldSaveCommentWhenCommentCreated() { + sut.createComment(identityDummy, resourceMock, RES_SUB_PATH, COMMENT_TEXT); + + verify(userCommentsDaoMock).createComment(identityDummy, resourceMock, RES_SUB_PATH, COMMENT_TEXT); + } + + @Test + public void shouldSaveCommentWhenCommentUpdated() { + sut.updateComment(userCommentMock, UPDATED_COMMENT_TEXT); + + verify(userCommentsDaoMock).updateComment(userCommentMock, UPDATED_COMMENT_TEXT); + } + + @Test + public void shouldSaveCommentWhenReplyToComment() { + sut.replyTo(userCommentMock, identityDummy, REPLY_TEXT); + + verify(userCommentsDaoMock).replyTo(userCommentMock, identityDummy, REPLY_TEXT); + } + + @Test + public void shouldMarkPublisherNewsWhenCommentCreated() { + when(userCommentsDaoMock.createComment(identityDummy, resourceMock, RES_SUB_PATH, COMMENT_TEXT)) + .thenReturn(userCommentMock); + + sut.createComment(identityDummy, resourceMock, RES_SUB_PATH, COMMENT_TEXT); + + verify(notificationsManagerMock).markPublisherNews( + RESOURCEABLE_TYPE_NAME, + RESOURCABLE_ID.toString(), + IGNORE_NEWS_FOR_NOBODY, + SEND_NO_EVENTS); + } + + @Test + public void shouldMarkPublisherNewsWhenCommentUpdated() { + when(userCommentsDaoMock.updateComment(userCommentMock, UPDATED_COMMENT_TEXT)) + .thenReturn(userCommentMock); + + sut.updateComment(userCommentMock, UPDATED_COMMENT_TEXT); + + verify(notificationsManagerMock).markPublisherNews( + RESOURCEABLE_TYPE_NAME, + RESOURCABLE_ID.toString(), + IGNORE_NEWS_FOR_NOBODY, + SEND_NO_EVENTS); + } + + @Test + public void shouldMarkPublisherNewsWhenRepliedToComment() { + when(userCommentsDaoMock.replyTo(userCommentMock, identityDummy, REPLY_TEXT)) + .thenReturn(userCommentMock); + + sut.replyTo(userCommentMock, identityDummy, REPLY_TEXT); + + verify(notificationsManagerMock).markPublisherNews( + RESOURCEABLE_TYPE_NAME, + RESOURCABLE_ID.toString(), + IGNORE_NEWS_FOR_NOBODY, + SEND_NO_EVENTS); + } + + @Test + public void shouldNotMarkPublisherNewsWhenCommentCreationFailed() { + when(userCommentsDaoMock.createComment(identityDummy, resourceMock, RES_SUB_PATH, COMMENT_TEXT)) + .thenReturn(null); + + sut.createComment(identityDummy, resourceMock, RES_SUB_PATH, COMMENT_TEXT); + + verify(notificationsManagerMock, never()).markPublisherNews( + RESOURCEABLE_TYPE_NAME, + RESOURCABLE_ID.toString(), + IGNORE_NEWS_FOR_NOBODY, + SEND_NO_EVENTS); + } + + @Test + public void shouldNotMarkPublisherNewsWhenCommentUpdateFailed() { + when(userCommentsDaoMock.updateComment(userCommentMock, UPDATED_COMMENT_TEXT)) + .thenReturn(null); + + sut.updateComment(userCommentMock, UPDATED_COMMENT_TEXT); + + verify(notificationsManagerMock, never()).markPublisherNews( + RESOURCEABLE_TYPE_NAME, + RESOURCABLE_ID.toString(), + IGNORE_NEWS_FOR_NOBODY, + SEND_NO_EVENTS); + } + + @Test + public void shouldNotMarkPublisherNewsWhenReplyToCommentFailed() { + when(userCommentsDaoMock.replyTo(userCommentMock, identityDummy, REPLY_TEXT)) + .thenReturn(null); + + sut.replyTo(userCommentMock, identityDummy, REPLY_TEXT); + + verify(notificationsManagerMock, never()).markPublisherNews( + RESOURCEABLE_TYPE_NAME, + RESOURCABLE_ID.toString(), + IGNORE_NEWS_FOR_NOBODY, + SEND_NO_EVENTS); + } +} diff --git a/src/test/java/org/olat/core/commons/services/commentAndRating/UserCommentsTest.java b/src/test/java/org/olat/core/commons/services/commentAndRating/manager/UserCommentsDAOTest.java similarity index 98% rename from src/test/java/org/olat/core/commons/services/commentAndRating/UserCommentsTest.java rename to src/test/java/org/olat/core/commons/services/commentAndRating/manager/UserCommentsDAOTest.java index 707cb20783f7a0a2c6b793a50821a2956556e3f2..e8bafd9f3a8c0fcd1e274aaa25a09b983588033d 100644 --- a/src/test/java/org/olat/core/commons/services/commentAndRating/UserCommentsTest.java +++ b/src/test/java/org/olat/core/commons/services/commentAndRating/manager/UserCommentsDAOTest.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.core.commons.services.commentAndRating; +package org.olat.core.commons.services.commentAndRating.manager; import static org.junit.Assert.assertEquals; @@ -43,7 +43,7 @@ import org.springframework.beans.factory.annotation.Autowired; * * @author gnaegi */ -public class UserCommentsTest extends OlatTestCase { +public class UserCommentsDAOTest extends OlatTestCase { @Autowired private UserCommentsDAO userCommentsDao; diff --git a/src/test/java/org/olat/core/commons/services/commentAndRating/UserRatingsDAOTest.java b/src/test/java/org/olat/core/commons/services/commentAndRating/manager/UserRatingsDAOTest.java similarity index 99% rename from src/test/java/org/olat/core/commons/services/commentAndRating/UserRatingsDAOTest.java rename to src/test/java/org/olat/core/commons/services/commentAndRating/manager/UserRatingsDAOTest.java index eff1bfbc29fc3e4bb2f42ca7845df63cc3b246d2..2185c6b2395db34fc742b4b9184b8310118c4bcf 100644 --- a/src/test/java/org/olat/core/commons/services/commentAndRating/UserRatingsDAOTest.java +++ b/src/test/java/org/olat/core/commons/services/commentAndRating/manager/UserRatingsDAOTest.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.core.commons.services.commentAndRating; +package org.olat.core.commons.services.commentAndRating.manager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; diff --git a/src/test/java/org/olat/core/commons/services/scheduler/SchedulerTest.java b/src/test/java/org/olat/core/commons/services/scheduler/SchedulerTest.java index 33dbdb7d6c6457f8745e01eef97ccefe233c1e60..6d0a9d0ac8f427c72f809a0a66c81218dad24a2d 100644 --- a/src/test/java/org/olat/core/commons/services/scheduler/SchedulerTest.java +++ b/src/test/java/org/olat/core/commons/services/scheduler/SchedulerTest.java @@ -25,19 +25,22 @@ */ package org.olat.core.commons.services.scheduler; -import static org.junit.Assert.assertEquals; +import static org.quartz.JobBuilder.newJob; import java.text.ParseException; import java.util.Calendar; import java.util.Date; +import org.junit.Assert; import org.junit.Test; import org.olat.test.OlatTestCase; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; +import org.quartz.TriggerUtils; +import org.quartz.spi.OperableTrigger; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.quartz.SimpleTriggerBean; +import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; /** * Description:<br> @@ -53,8 +56,11 @@ public class SchedulerTest extends OlatTestCase { @Test public void testSimpleTrigger() throws SchedulerException, ParseException { - JobDetail job = new JobDetail("schedulerTestJobSimpleTrigger", Scheduler.DEFAULT_GROUP, SchedulerTestJob.class); - SimpleTriggerBean trigger = new SimpleTriggerBean(); + JobDetail job = newJob(SchedulerTestJob.class) + .withIdentity("schedulerTestJobSimpleTrigger", Scheduler.DEFAULT_GROUP) + .build(); + + SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean(); trigger.setName("Test scheduler trigger"); trigger.setStartDelay(0); trigger.setRepeatInterval(1000); @@ -62,14 +68,17 @@ public class SchedulerTest extends OlatTestCase { trigger.setJobDetail(job); trigger.afterPropertiesSet(); // Schedule job now - scheduler.scheduleJob(job, trigger); + scheduler.scheduleJob(job, trigger.getObject()); + + sleep(20);//because of cal.add(Calendar.MILLISECOND, 11); - //check next time + //check number of calls to the job + org.quartz.Calendar quartzCal = scheduler.getCalendar(trigger.getObject().getCalendarName()); Calendar cal = Calendar.getInstance(); Date start = cal.getTime(); cal.add(Calendar.SECOND, 5); - cal.add(Calendar.MILLISECOND, 011); + cal.add(Calendar.MILLISECOND, 11); Date end = cal.getTime(); - assertEquals(5, trigger.computeNumTimesFiredBetween(start, end)); + Assert.assertEquals(5, TriggerUtils.computeFireTimesBetween((OperableTrigger)trigger.getObject(), quartzCal, start, end).size()); } } diff --git a/src/test/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TextModeTest.java b/src/test/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TextModeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3f1ff99a8d086687a6b919b37e8ca15c0c0ecd48 --- /dev/null +++ b/src/test/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/TextModeTest.java @@ -0,0 +1,72 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.gui.components.form.flexible.impl.elements.richText; + +import org.junit.Assert; +import org.junit.Test; + +/** + * + * Initial date: 19 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class TextModeTest { + + @Test + public void guessOneLine() { + TextMode mode1 = TextMode.guess("bla bla"); + Assert.assertEquals(TextMode.oneLine, mode1); + + TextMode mode2 = TextMode.guess("<p>bla bla</p>"); + Assert.assertEquals(TextMode.oneLine, mode2); + } + + @Test + public void guessMultiLine() { + TextMode mode1 = TextMode.guess("bla<br>bla"); + Assert.assertEquals(TextMode.multiLine, mode1); + TextMode mode1alt = TextMode.guess("bla<br/>bla"); + Assert.assertEquals(TextMode.multiLine, mode1alt); + TextMode mode1alt_b = TextMode.guess("bla<br />bla"); + Assert.assertEquals(TextMode.multiLine, mode1alt_b); + + TextMode mode2 = TextMode.guess("<p>bla</p><p>bla</p>"); + Assert.assertEquals(TextMode.multiLine, mode2); + + TextMode mode3 = TextMode.guess("<p>bla<br>bla</p>"); + Assert.assertEquals(TextMode.multiLine, mode3); + } + + @Test + public void guessFormatted() { + TextMode mode = TextMode.guess("bla<img src='openolat.png'>bla"); + Assert.assertEquals(TextMode.formatted, mode); + } + + @Test + public void toMultiLine() { + String linedText1 = TextMode.toMultiLine("<p>Lorem ipsum </p>\n <p>dolor sit amet </p>"); + Assert.assertEquals("Lorem ipsum\ndolor sit amet", linedText1); + + String linedText2 = TextMode.toMultiLine("<p>Lorem</p>ipsum<br>dolor<p>sit amet</p>"); + Assert.assertEquals("Lorem\nipsum\ndolor\nsit amet", linedText2); + } +} diff --git a/src/test/java/org/olat/core/util/filter/impl/XSSFilterTest.java b/src/test/java/org/olat/core/util/filter/impl/XSSFilterTest.java index 0668162858432caf8894f95d37dd02474603be36..80ab437ea01288cfa81943a161b26f223a6bf1cd 100644 --- a/src/test/java/org/olat/core/util/filter/impl/XSSFilterTest.java +++ b/src/test/java/org/olat/core/util/filter/impl/XSSFilterTest.java @@ -273,7 +273,14 @@ public class XSSFilterTest { // for now i tags must have at least a space to not b removed t("<i class=\"o_icon o_icon_dev\"> </i> ", "<i class=\"o_icon o_icon_dev\"> </i> "); } + + @Test + public void test_figure() { + // for now i tags must have at least a space to not b removed + t("<figure class=\"image\"><img src=\"bla.png\" /><figcaption>gugs</figcaption></figure>", "<figure class=\"image\"><img src=\"bla.png\" /><figcaption>gugs</figcaption></figure>"); + } + @Test public void test_big_tiny_output(){ testsToRun = 1; diff --git a/src/test/java/org/olat/core/util/i18n/I18nTest.java b/src/test/java/org/olat/core/util/i18n/I18nTest.java index e98b518ca211334e68517a515fd2db002f0bf004..1c3965a469a170b4e2eb5b6061c1238baf22315b 100644 --- a/src/test/java/org/olat/core/util/i18n/I18nTest.java +++ b/src/test/java/org/olat/core/util/i18n/I18nTest.java @@ -77,6 +77,8 @@ public class I18nTest extends OlatTestCase { @Autowired private I18nManager i18nMgr; @Autowired + private I18nModule i18nModule; + @Autowired private TranslationDevManager tDMgr; private static final String testSourceBundle = "org.olat.core.util.i18n.junittestdata.devtools.source"; private static final String testTargetBundle = "org.olat.core.util.i18n.junittestdata.devtools.target"; @@ -95,7 +97,7 @@ public class I18nTest extends OlatTestCase { public void tearDown() throws Exception { String testNewBundle = "org.olat.core.util.i18n.junittestdata.new"; Locale testLocale = i18nMgr.getLocaleOrDefault("de"); - File baseDir = I18nModule.getPropertyFilesBaseDir(testLocale, testNewBundle); + File baseDir = i18nModule.getPropertyFilesBaseDir(testLocale, testNewBundle); // only delete files when basedir available if (baseDir == null) return; File testFile = i18nMgr.getPropertiesFile(testLocale, testNewBundle, baseDir); @@ -129,17 +131,17 @@ public class I18nTest extends OlatTestCase { Locale testLocale = i18nMgr.getLocaleOrDefault("de"); // cleanup devtools source/target files // 1) source files - File baseDir = I18nModule.getPropertyFilesBaseDir(testLocale, testSourceBundle); + File baseDir = i18nModule.getPropertyFilesBaseDir(testLocale, testSourceBundle); File testSFile = i18nMgr.getPropertiesFile(testLocale, testSourceBundle, baseDir); File sourcePath = testSFile.getParentFile().getParentFile(); FileUtils.deleteDirsAndFiles(sourcePath, true, true); // 2) target files - baseDir = I18nModule.getPropertyFilesBaseDir(testLocale, testTargetBundle); + baseDir = i18nModule.getPropertyFilesBaseDir(testLocale, testTargetBundle); File testTFile = i18nMgr.getPropertiesFile(testLocale, testTargetBundle, baseDir); File targetPath = testTFile.getParentFile().getParentFile(); FileUtils.deleteDirsAndFiles(targetPath, true, true); // 3) move target files - baseDir = I18nModule.getPropertyFilesBaseDir(testLocale, testMoveTargetBundle); + baseDir = i18nModule.getPropertyFilesBaseDir(testLocale, testMoveTargetBundle); File testMFile = i18nMgr.getPropertiesFile(testLocale, testMoveTargetBundle, baseDir); File movePath = testMFile.getParentFile().getParentFile().getParentFile(); FileUtils.deleteDirsAndFiles(movePath, true, true); @@ -150,7 +152,7 @@ public class I18nTest extends OlatTestCase { // set languages that is used as reference: all keys there are the keys should not to be deleted String[] referenceLanguages = new String[]{"de", "en"}; // set the languages that should be cleaned up - Set<String> targetLanguages = I18nModule.getTranslatableLanguageKeys(); + Set<String> targetLanguages = i18nModule.getTranslatableLanguageKeys(); //Set<String> targetLanguages = new HashSet<String>(); //targetLanguages.add("en"); tDMgr.removeDeletedKeys(false, referenceLanguages, targetLanguages); @@ -158,7 +160,7 @@ public class I18nTest extends OlatTestCase { @Test public void testMoveKeyTask() { - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { prepareDevToolTests(); Locale testLocale = i18nMgr.getLocaleOrDefault("de"); String ktm = "key.to.move"; @@ -182,38 +184,35 @@ public class I18nTest extends OlatTestCase { //check for changed references in value //if correctly done, should still be resolvable assertTrue(sourcePropResolved.getProperty("key.to.stay2").indexOf(matchString)!=-1); - tDMgr.logToFile("moveKey"); } } @Test public void testMovePackageTask(){ - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { prepareDevToolTests(); tDMgr.movePackageTask(testSourceBundle, testTargetBundle); i18nMgr.clearCaches(); Properties sourceProp = i18nMgr.getPropertiesWithoutResolvingRecursively(null, testSourceBundle); assertTrue(sourceProp.isEmpty()); Properties targetProp = i18nMgr.getPropertiesWithoutResolvingRecursively(null, testTargetBundle); - assertFalse(targetProp.isEmpty()); - tDMgr.logToFile("movePackage"); + assertFalse(targetProp.isEmpty()); } } @Test public void testMovePackageByMovingSingleKeysTask(){ - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { prepareDevToolTests(); tDMgr.movePackageByMovingSingleKeysTask(testSourceBundle, testTargetBundle); i18nMgr.clearCaches(); Properties sourceProp = i18nMgr.getPropertiesWithoutResolvingRecursively(null, testSourceBundle); assertTrue(sourceProp.isEmpty()); Properties targetProp = i18nMgr.getPropertiesWithoutResolvingRecursively(null, testTargetBundle); - assertFalse(targetProp.isEmpty()); - tDMgr.logToFile("movePackageSingle"); + assertFalse(targetProp.isEmpty()); } } @Test public void testMergePackageTask(){ - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { prepareDevToolTests(); tDMgr.mergePackageTask(testSourceBundle, testTargetBundle); i18nMgr.clearCaches(); @@ -224,7 +223,7 @@ public class I18nTest extends OlatTestCase { } @Test public void testRenameLanguageTask(){ - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { prepareDevToolTests(); // create source Locale xxLocale = new Locale("xx"); @@ -256,9 +255,9 @@ public class I18nTest extends OlatTestCase { } @Test public void testMoveLanguageTask(){ - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { prepareDevToolTests(); - String srcPath = I18nModule.getTransToolApplicationLanguagesSrcDir().getAbsolutePath() + "/../../test/java/org/olat/core/util/i18n/junittestdata/devtools"; + String srcPath = i18nModule.getTransToolApplicationLanguagesSrcDir().getAbsolutePath() + "/../../test/java/org/olat/core/util/i18n/junittestdata/devtools"; String targetPath = srcPath + "/../movetarget"; //only copy: target should exist Locale mvLocale = i18nMgr.getLocaleOrDefault("de"); @@ -287,30 +286,26 @@ public class I18nTest extends OlatTestCase { //remove after execution! @Test public void testRemoveXKeyTask(){ - tDMgr.removeXKeysTask(false); - tDMgr.logToFile("XKeys"); + tDMgr.removeXKeysTask(false); } //remove after execution! @Test public void testRemoveTodoKeyTask(){ tDMgr.removeTodoKeysTask(false); - tDMgr.logToFile("todoKeys"); } //remove after execution! @Test public void testRemoveEmptyKeysTask(){ tDMgr.removeEmptyKeysTask(false); - tDMgr.logToFile("emptyKeys"); } //remove after execution! @Test public void testRemoveReferenceLanguageCopiesTask(){ - if (I18nModule.isTransToolEnabled()) { - tDMgr.removeReferenceLanguageCopiesTask(false); - tDMgr.logToFile("refLangCopied"); + if (i18nModule.isTransToolEnabled()) { + tDMgr.removeReferenceLanguageCopiesTask(false); } } @@ -318,11 +313,11 @@ public class I18nTest extends OlatTestCase { * Test method i18nManager.searchForAvailableLanguages() */ @Test public void testSearchForAvailableLanguages() { - if (I18nModule.isTransToolEnabled()) { + if (i18nModule.isTransToolEnabled()) { // Try to load i18n files and a jar from the testdata dir - File testDataDir = new File(I18nModule.getTransToolApplicationLanguagesSrcDir(), "/../../test/java/org/olat/core/util/i18n/junittestdata/"); + File testDataDir = new File(i18nModule.getTransToolApplicationLanguagesSrcDir(), "/../../test/java/org/olat/core/util/i18n/junittestdata/"); assertTrue(testDataDir.exists()); - Set<String> foundLanguages = i18nMgr.searchForAvailableLanguages(testDataDir); + Set<String> foundLanguages = i18nModule.searchForAvailableLanguages(testDataDir); // Set must contain some LocalStrings file: assertTrue(foundLanguages.contains("de")); assertTrue(foundLanguages.contains("en")); @@ -333,7 +328,7 @@ public class I18nTest extends OlatTestCase { // Final check assertEquals(6, foundLanguages.size()); } else { - Set<String> foundLanguages = I18nModule.getAvailableLanguageKeys(); + Set<String> foundLanguages = i18nModule.getAvailableLanguageKeys(); // Set must contain some LocaleStrings from the jar package assertTrue(foundLanguages.contains("fr")); assertTrue(foundLanguages.contains("zh_CN")); @@ -345,7 +340,7 @@ public class I18nTest extends OlatTestCase { */ @Test public void testSearchForBundleNamesContainingI18nFiles() { long start = System.currentTimeMillis(); - List<String> foundBundles = i18nMgr.searchForBundleNamesContainingI18nFiles(); + List<String> foundBundles = i18nModule.searchForBundleNamesContainingI18nFiles(); long end = System.currentTimeMillis(); log.info("Searching for " + foundBundles.size() + " bundles on OLAT source path took me " + (end-start) + "ms", "testSearchForBundleNamesContainingI18nFiles"); // Must contain packages from core @@ -361,7 +356,7 @@ public class I18nTest extends OlatTestCase { * Test method i18nManager.buildI18nFilename() */ @Test public void testBuildI18nFilename() { - String overlay = I18nModule.getOverlayName(); + String overlay = i18nModule.getOverlayName(); String testFileName = i18nMgr.buildI18nFilename(new Locale("de")); assertEquals("LocalStrings_de.properties", testFileName); testFileName = i18nMgr.buildI18nFilename(new Locale("de","","__" + overlay)); @@ -386,9 +381,9 @@ public class I18nTest extends OlatTestCase { locale = i18nMgr.getLocaleOrDefault("xy"); assertEquals(I18nModule.getDefaultLocale(), locale); // Test trying to get overlay via getLocale method which should not return the overlay - Locale overlay = i18nMgr.getLocaleOrDefault("de__" + I18nModule.getOverlayName()); + Locale overlay = i18nMgr.getLocaleOrDefault("de__" + i18nModule.getOverlayName()); assertEquals(I18nModule.getDefaultLocale(), overlay); - overlay = i18nMgr.getLocaleOrDefault("zh_CN__" + I18nModule.getOverlayName()); + overlay = i18nMgr.getLocaleOrDefault("zh_CN__" + i18nModule.getOverlayName()); assertEquals(I18nModule.getDefaultLocale(), overlay); } @@ -397,25 +392,25 @@ public class I18nTest extends OlatTestCase { */ @Test public void testCreateLocale() { // standard locale - Locale loc = i18nMgr.createLocale("de"); + Locale loc = i18nModule.createLocale("de"); assertNotNull(loc); assertEquals("de",loc.getLanguage()); assertEquals("",loc.getCountry()); assertEquals("",loc.getVariant()); // with country - loc = i18nMgr.createLocale("de_CH"); + loc = i18nModule.createLocale("de_CH"); assertNotNull(loc); assertEquals("de", loc.getLanguage()); assertEquals("CH", loc.getCountry()); assertEquals("", loc.getVariant()); // with variant - loc = i18nMgr.createLocale("de_CH_ZH"); + loc = i18nModule.createLocale("de_CH_ZH"); assertNotNull(loc); assertEquals("de", loc.getLanguage()); assertEquals("CH", loc.getCountry()); assertEquals("ZH", loc.getVariant()); // with variant but no country - loc = i18nMgr.createLocale("de__VENDOR"); + loc = i18nModule.createLocale("de__VENDOR"); assertNotNull(loc); assertEquals("de", loc.getLanguage()); assertEquals("", loc.getCountry()); @@ -423,21 +418,21 @@ public class I18nTest extends OlatTestCase { // // With overlay // with language - String overlay = I18nModule.getOverlayName(); - loc = i18nMgr.createLocale("de"); - Locale over = i18nMgr.createOverlay(loc); + String overlay = i18nModule.getOverlayName(); + loc = i18nModule.createLocale("de"); + Locale over = i18nModule.createOverlay(loc); assertEquals("de____" + overlay, over.toString()); - assertEquals(i18nMgr.createOverlayKeyForLanguage(loc.toString()), i18nMgr.getLocaleKey(over)); + assertEquals(i18nModule.createOverlayKeyForLanguage(loc.toString()), i18nModule.getLocaleKey(over)); // with country - loc = i18nMgr.createLocale("de_CH"); - over = i18nMgr.createOverlay(loc); + loc = i18nModule.createLocale("de_CH"); + over = i18nModule.createOverlay(loc); assertEquals("de_CH___" + overlay, over.toString()); - assertEquals(i18nMgr.createOverlayKeyForLanguage(loc.toString()), i18nMgr.getLocaleKey(over)); + assertEquals(i18nModule.createOverlayKeyForLanguage(loc.toString()), i18nModule.getLocaleKey(over)); // with variant - loc = i18nMgr.createLocale("de_CH_ZH"); - over = i18nMgr.createOverlay(loc); + loc = i18nModule.createLocale("de_CH_ZH"); + over = i18nModule.createOverlay(loc); assertEquals("de_CH_ZH__" + overlay, over.toString()); - assertEquals(i18nMgr.createOverlayKeyForLanguage(loc.toString()), i18nMgr.getLocaleKey(over)); + assertEquals(i18nModule.createOverlayKeyForLanguage(loc.toString()), i18nModule.getLocaleKey(over)); } /** @@ -454,8 +449,8 @@ public class I18nTest extends OlatTestCase { * Test methods i18nManager.getLanguageTranslated() i18nManager.getLanguageInEnglish() */ @Test public void testGetPropertyFile() { - if (I18nModule.isTransToolEnabled()) { - File baseDir = I18nModule.getPropertyFilesBaseDir(i18nMgr.getLocaleOrDefault("de"), "org.olat.core"); + if (i18nModule.isTransToolEnabled()) { + File baseDir = i18nModule.getPropertyFilesBaseDir(i18nMgr.getLocaleOrDefault("de"), "org.olat.core"); assertNotNull(baseDir); File file = i18nMgr.getPropertiesFile(i18nMgr.getLocaleOrDefault("de"), "org.olat.core", baseDir); assertTrue(file.exists()); @@ -486,7 +481,7 @@ public class I18nTest extends OlatTestCase { // test with non existing files String testNewBundle = "org.olat.core.util.i18n.junittestdata.new"; Locale testLocale = i18nMgr.getLocaleOrDefault("de"); - File baseDir = I18nModule.getPropertyFilesBaseDir(testLocale, testNewBundle); + File baseDir = i18nModule.getPropertyFilesBaseDir(testLocale, testNewBundle); File testFile = i18nMgr.getPropertiesFile(testLocale, testNewBundle, baseDir); // clean first existing files from previous broken testcase if (testFile.exists()) { @@ -580,11 +575,11 @@ public class I18nTest extends OlatTestCase { */ @Ignore @Test public void testCountI18nItemsAndBundles() { - I18nModule.initBundleNames(); // remove dirty stuff from previous tests - int bundleCounter = I18nModule.getBundleNamesContainingI18nFiles().size(); + i18nModule.initBundleNames(); // remove dirty stuff from previous tests + int bundleCounter = i18nModule.getBundleNamesContainingI18nFiles().size(); String testNewBundle = "org.olat.core.util.i18n.junittestdata.new"; Locale testLocale = i18nMgr.getLocaleOrDefault("de"); - File baseDir = I18nModule.getPropertyFilesBaseDir(testLocale, testNewBundle); + File baseDir = i18nModule.getPropertyFilesBaseDir(testLocale, testNewBundle); File testFile = i18nMgr.getPropertiesFile(testLocale, testNewBundle, baseDir); // clean first existing files from previous broken testcase if (testFile.exists()) { @@ -598,7 +593,7 @@ public class I18nTest extends OlatTestCase { i18nMgr.saveOrUpdateProperties(props, testLocale, testNewBundle); assertEquals(2, i18nMgr.countI18nItems(testLocale, testNewBundle, false)); assertEquals(0, i18nMgr.countI18nItems(i18nMgr.getLocaleOrDefault("en"), testNewBundle, false)); - assertEquals(bundleCounter + 1, I18nModule.getBundleNamesContainingI18nFiles().size()); + assertEquals(bundleCounter + 1, i18nModule.getBundleNamesContainingI18nFiles().size()); // test all bundles int allCount = i18nMgr.countI18nItems(testLocale, null, true); assertEquals(allCount, i18nMgr.countI18nItems(testLocale, null, false)); @@ -607,7 +602,7 @@ public class I18nTest extends OlatTestCase { assertEquals(allCount-1, i18nMgr.countI18nItems(testLocale, null, false)); i18nMgr.deleteProperties(testLocale, testNewBundle); assertEquals(allCount-2, i18nMgr.countI18nItems(testLocale, null, false)); - assertEquals(bundleCounter, I18nModule.getBundleNamesContainingI18nFiles().size()); + assertEquals(bundleCounter, i18nModule.getBundleNamesContainingI18nFiles().size()); // count bundles tests assertEquals(0, i18nMgr.countBundles("org.olat.core.util.i18n.nonexisting", true)); assertEquals(1, i18nMgr.countBundles("org.olat.core.util.i18n.ui", true)); diff --git a/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java b/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java index 851ca4ae359d0800e3be9ef14bb26872a61e904d..bb40e0ed1874f68f85b79e33161c22bf168a1b3e 100644 --- a/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java +++ b/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java @@ -59,6 +59,7 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; +import org.olat.modules.assessment.Role; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.test.JunitTestHelper; @@ -162,7 +163,7 @@ public class AssessmentManagerTest extends OlatTestCase { UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment()); boolean incrementAttempts = true; //assessableCourseNode.updateUserScoreEvaluation(scoreEvaluation, userCourseEnv, tutor, incrementAttempts); //alternative - assessmentManager.saveScoreEvaluation(assessableCourseNode, tutor, student, scoreEvaluation, userCourseEnv, incrementAttempts); + assessmentManager.saveScoreEvaluation(assessableCourseNode, tutor, student, scoreEvaluation, userCourseEnv, incrementAttempts, Role.coach); DBFactory.getInstance().closeSession(); //the attempts mut have been incremented //assertEquals(attempts, assessableCourseNode.getUserAttempts(userCourseEnv)); //alternative @@ -175,7 +176,7 @@ public class AssessmentManagerTest extends OlatTestCase { //assessableCourseNode.updateUserUserComment(userComment, userCourseEnv, tutor); //alternative attempts++; - assessmentManager.saveNodeAttempts(assessableCourseNode, tutor, student, attempts); + assessmentManager.saveNodeAttempts(assessableCourseNode, tutor, student, attempts, Role.coach); assertEquals(attempts, assessmentManager.getNodeAttempts(assessableCourseNode, student)); //assessableCourseNode.updateUserAttempts(attempts, userCourseEnv, tutor); //alternative diff --git a/src/test/java/org/olat/course/assessment/manager/AssessmentToolManagerTest.java b/src/test/java/org/olat/course/assessment/manager/AssessmentToolManagerTest.java index c205043a6173e298a1f8f0b15460818d6a6b146a..5226817d9741bcb53c8e6c80026f0e625b0352a5 100644 --- a/src/test/java/org/olat/course/assessment/manager/AssessmentToolManagerTest.java +++ b/src/test/java/org/olat/course/assessment/manager/AssessmentToolManagerTest.java @@ -96,10 +96,10 @@ public class AssessmentToolManagerTest extends OlatTestCase { dbInstance.commitAndCloseSession(); // some datas - assessmentEntryDao.createAssessmentEntry(assessedIdentity1, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE); - assessmentEntryDao.createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 5.0f, Boolean.TRUE); - assessmentEntryDao.createAssessmentEntry(assessedIdentity3, null, entry, subIdent, refEntry, 8.0f, Boolean.TRUE); - assessmentEntryDao.createAssessmentEntry(assessedIdentity4, null, entry, subIdent, refEntry, 9.0f, Boolean.TRUE); + assessmentEntryDao.createAssessmentEntry(assessedIdentity1, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); + assessmentEntryDao.createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 5.0f, Boolean.TRUE, null, null); + assessmentEntryDao.createAssessmentEntry(assessedIdentity3, null, entry, subIdent, refEntry, 8.0f, Boolean.TRUE, null, null); + assessmentEntryDao.createAssessmentEntry(assessedIdentity4, null, entry, subIdent, refEntry, 9.0f, Boolean.TRUE, null, null); assessmentEntryDao.createAssessmentEntry(null, UUID.randomUUID().toString(), entry, subIdent, refEntry); dbInstance.commitAndCloseSession(); diff --git a/src/test/java/org/olat/course/assessment/manager/UserCourseInformationsManagerTest.java b/src/test/java/org/olat/course/assessment/manager/UserCourseInformationsManagerTest.java index 867acde6abc1adc5059b619e41b70cbff0adaf71..176f752387f9b10f599cb54a24158f72fc5ba325 100644 --- a/src/test/java/org/olat/course/assessment/manager/UserCourseInformationsManagerTest.java +++ b/src/test/java/org/olat/course/assessment/manager/UserCourseInformationsManagerTest.java @@ -30,12 +30,17 @@ import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Test; +import org.olat.basesecurity.GroupRoles; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.course.ICourse; import org.olat.course.assessment.UserCourseInformations; +import org.olat.group.BusinessGroup; +import org.olat.group.BusinessGroupService; +import org.olat.group.manager.BusinessGroupRelationDAO; +import org.olat.repository.RepositoryEntry; import org.olat.resource.OLATResource; import org.olat.restapi.repository.course.CoursesWebService; import org.olat.test.JunitTestHelper; @@ -55,6 +60,10 @@ public class UserCourseInformationsManagerTest extends OlatTestCase { @Autowired private DB dbInstance; @Autowired + private BusinessGroupService businessGroupService; + @Autowired + private BusinessGroupRelationDAO businessGroupRelationDao; + @Autowired private UserCourseInformationsManager userCourseInformationsManager; @Test @@ -142,7 +151,7 @@ public class UserCourseInformationsManagerTest extends OlatTestCase { } @Test - public void getInitialLaunchDate() { + public void getInitialLaunchDate_ressource() { Identity user = JunitTestHelper.createAndPersistIdentityAsUser("user-launch-2-" + UUID.randomUUID().toString()); ICourse course = CoursesWebService.createEmptyCourse(user, "course-launch-dates", "course long name", null); dbInstance.commitAndCloseSession(); @@ -155,6 +164,44 @@ public class UserCourseInformationsManagerTest extends OlatTestCase { Assert.assertNotNull(launchDate); } + @Test + public void getInitialLaunchDate_repositoryEntry() { + Identity user = JunitTestHelper.createAndPersistIdentityAsUser("user-launch-2-" + UUID.randomUUID().toString()); + ICourse course = CoursesWebService.createEmptyCourse(user, "course-launch-dates", "course long name", null); + dbInstance.commitAndCloseSession(); + + OLATResource courseResource = course.getCourseEnvironment().getCourseGroupManager().getCourseResource(); + RepositoryEntry courseEntry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + userCourseInformationsManager.updateUserCourseInformations(courseResource, user); + dbInstance.commitAndCloseSession(); + + Date launchDate = userCourseInformationsManager.getInitialLaunchDate(courseEntry, user); + Assert.assertNotNull(launchDate); + } + + @Test + public void getInitialParticiantLaunchDate_businessGroup() { + Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("init-launch-1-"); + Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("init-launch-2-"); + ICourse course = CoursesWebService.createEmptyCourse(id1, "course-launch-dates", "course long name", null); + dbInstance.commitAndCloseSession(); + + OLATResource courseResource = course.getCourseEnvironment().getCourseGroupManager().getCourseResource(); + RepositoryEntry courseEntry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + userCourseInformationsManager.updateUserCourseInformations(courseResource, id1); + userCourseInformationsManager.updateUserCourseInformations(courseResource, id2); + dbInstance.commit(); + + //add user to a group + BusinessGroup group = businessGroupService.createBusinessGroup(null, "initial launch", "tg", null, null, false, false, courseEntry); + businessGroupRelationDao.addRole(id1, group, GroupRoles.participant.name()); + businessGroupRelationDao.addRole(id2, group, GroupRoles.participant.name()); + dbInstance.commitAndCloseSession(); + + Date launchDate = userCourseInformationsManager.getInitialParticipantLaunchDate(courseEntry, group); + Assert.assertNotNull(launchDate); + } + @Test public void getInitialLaunchDates() { Identity user1 = JunitTestHelper.createAndPersistIdentityAsUser("user-launch-3-" + UUID.randomUUID().toString()); @@ -206,8 +253,6 @@ public class UserCourseInformationsManagerTest extends OlatTestCase { Assert.assertNotNull(launchDates.get(user3.getKey())); } - - /** * This test is to analyze a red screen */ diff --git a/src/test/java/org/olat/course/highscore/HighScoreManagerTest.java b/src/test/java/org/olat/course/highscore/HighScoreManagerTest.java index 3b1cd5164bac0bdbdd6e19b04741b2a5a7971cb1..7c82bb9d5176e32062a486c06a853582dc9de8af 100644 --- a/src/test/java/org/olat/course/highscore/HighScoreManagerTest.java +++ b/src/test/java/org/olat/course/highscore/HighScoreManagerTest.java @@ -24,6 +24,12 @@ * <p> */ package org.olat.course.highscore; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +import java.util.ArrayList; /** * Description:<br> * HighScoreManagerTest @@ -31,11 +37,6 @@ package org.olat.course.highscore; * @author fkiefer */ import java.util.List; - -import static org.junit.Assert.*; - -import java.math.BigDecimal; -import java.util.ArrayList; import java.util.UUID; import org.junit.Test; @@ -48,35 +49,19 @@ import org.olat.modules.assessment.manager.AssessmentEntryDAO; import org.olat.repository.RepositoryEntry; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; -import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; public class HighScoreManagerTest extends OlatTestCase { - private List<HighScoreTableEntry> allMembers, ownIdMembers; - private List<List<HighScoreTableEntry>> allPodium; - private List<Integer> ownIdIndices; - - @Autowired - private HighScoreManager highScoreManager; - @Autowired - private UserManager userManager; @Autowired private DB dbInstance; @Autowired + private HighScoreManager highScoreManager; + @Autowired private AssessmentEntryDAO courseNodeAssessmentDao; - - @Test - public void springtest() { - assertNotNull(highScoreManager); - assertNotNull(userManager); - assertNotNull(dbInstance); - assertNotNull(courseNodeAssessmentDao); - } @Test public void highscoreTest() { - List<AssessmentEntry> assessEntries = new ArrayList<>(); int[] scores = {1,23,10}; Identity assessedIdentity = null; @@ -92,17 +77,17 @@ public class HighScoreManagerTest extends OlatTestCase { AssessmentEntry reloadedAssessment = courseNodeAssessmentDao.loadAssessmentEntryById(nodeAssessment.getKey()); assessEntries.add(reloadedAssessment); } - - ownIdIndices = new ArrayList<>(); - allMembers = new ArrayList<>(); - ownIdMembers = new ArrayList<>(); - allPodium = new ArrayList<>(); + + List<Integer> ownIdIndices = new ArrayList<>(); + List<HighScoreTableEntry> allMembers = new ArrayList<>(); + List<HighScoreTableEntry> ownIdMembers = new ArrayList<>(); + List<List<HighScoreTableEntry>> allPodium = new ArrayList<>(); allPodium.add(new ArrayList<>()); allPodium.add(new ArrayList<>()); allPodium.add(new ArrayList<>()); double[] allScores = highScoreManager.sortRankByScore(assessEntries, allMembers, ownIdMembers, allPodium, - ownIdIndices, 5, JunitTestHelper.createAndPersistIdentityAsRndUser("as-node-2"), userManager) + ownIdIndices, 5, JunitTestHelper.createAndPersistIdentityAsRndUser("as-node-2")) .getScores(); assertNotNull(allScores); @@ -115,7 +100,5 @@ public class HighScoreManagerTest extends OlatTestCase { long classwidth = highScoreManager.processHistogramData(allScores, 0F, 30F).getClasswidth(); assertEquals(2L, classwidth); - } - -} +} \ No newline at end of file diff --git a/src/test/java/org/olat/course/nodes/gta/manager/GTAManagerTest.java b/src/test/java/org/olat/course/nodes/gta/manager/GTAManagerTest.java index f96e3b4394de2f9decacd1c0109acc09d91e1643..899b5a35b578395071a8cf75a4f0858a8f1fad34 100644 --- a/src/test/java/org/olat/course/nodes/gta/manager/GTAManagerTest.java +++ b/src/test/java/org/olat/course/nodes/gta/manager/GTAManagerTest.java @@ -20,20 +20,32 @@ package org.olat.course.nodes.gta.manager; import java.io.File; +import java.net.URISyntaxException; +import java.net.URL; import java.util.ArrayList; +import java.util.Date; import java.util.List; +import java.util.UUID; import org.junit.Assert; import org.junit.Test; import org.olat.basesecurity.GroupRoles; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.nodes.INode; +import org.olat.course.CourseFactory; +import org.olat.course.ICourse; +import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.AssignmentResponse; import org.olat.course.nodes.gta.AssignmentResponse.Status; import org.olat.course.nodes.gta.GTAType; import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskList; +import org.olat.course.nodes.gta.TaskProcess; +import org.olat.course.nodes.gta.TaskRevisionDate; import org.olat.course.nodes.gta.model.TaskListImpl; import org.olat.group.BusinessGroup; import org.olat.group.manager.BusinessGroupDAO; @@ -53,6 +65,8 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class GTAManagerTest extends OlatTestCase { + private static final OLog log = Tracing.createLoggerFor(GTAManagerTest.class); + @Autowired private DB dbInstance; @Autowired @@ -66,8 +80,8 @@ public class GTAManagerTest extends OlatTestCase { @Test public void createIfNotExists() { - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); Assert.assertNotNull(node.getIdent()); TaskList tasks = gtaManager.createIfNotExists(re, node); @@ -97,8 +111,8 @@ public class GTAManagerTest extends OlatTestCase { public void selectTask_identity() { //prepare Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-1"); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList tasks = gtaManager.createIfNotExists(re, node); File taskFile = new File("solo.txt"); @@ -129,8 +143,8 @@ public class GTAManagerTest extends OlatTestCase { Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-2"); BusinessGroup businessGroup = businessGroupDao.createAndPersist(coach, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); dbInstance.commit(); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.group.name()); TaskList tasks = gtaManager.createIfNotExists(re, node); File taskFile = new File("bg.txt"); @@ -162,8 +176,8 @@ public class GTAManagerTest extends OlatTestCase { BusinessGroup businessGroup = businessGroupDao.createAndPersist(coach, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); businessGroupRelationDao.addRole(participant, businessGroup, GroupRole.participant.name()); dbInstance.commit(); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.group.name()); TaskList tasks = gtaManager.createIfNotExists(re, node); File taskFile = new File("bg.txt"); @@ -184,8 +198,8 @@ public class GTAManagerTest extends OlatTestCase { public void isTaskAssigned() { //create an individual task Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-6"); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList tasks = gtaManager.createIfNotExists(re, node); dbInstance.commit(); @@ -208,8 +222,8 @@ public class GTAManagerTest extends OlatTestCase { public void isTaskInProcess() { //prepare Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-11"); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList tasks = gtaManager.createIfNotExists(re, node); File taskFile = new File("solo.txt"); @@ -235,8 +249,8 @@ public class GTAManagerTest extends OlatTestCase { public void isTasksInProcess_yes() { //prepare Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-12"); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList tasks = gtaManager.createIfNotExists(re, node); File taskFile = new File("solo.txt"); @@ -257,8 +271,8 @@ public class GTAManagerTest extends OlatTestCase { @Test public void isTasksInProcess_no() { //prepare - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList tasks = gtaManager.createIfNotExists(re, node); Assert.assertNotNull(tasks); @@ -274,8 +288,8 @@ public class GTAManagerTest extends OlatTestCase { //create an individual task Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-7"); Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-8"); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList taskList = gtaManager.createIfNotExists(re, node); dbInstance.commit(); @@ -298,8 +312,8 @@ public class GTAManagerTest extends OlatTestCase { //create an individual task Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-7"); Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-8"); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList taskList = gtaManager.createIfNotExists(re, node); dbInstance.commit(); @@ -331,8 +345,8 @@ public class GTAManagerTest extends OlatTestCase { //create an individual task Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-7"); Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-8"); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList taskList = gtaManager.createIfNotExists(re, node); dbInstance.commit(); @@ -371,6 +385,26 @@ public class GTAManagerTest extends OlatTestCase { Assert.assertEquals("work_1.txt", assignedTaskRefToId1.getTaskName()); } + @Test + public void getEnrollmentDate() { + Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-20"); + BusinessGroup businessGroup = businessGroupDao.createAndPersist(coach, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); + dbInstance.commit(); + + //no participant enrolled + Date noEnrollmentDate = gtaManager.getEnrollmentDate(businessGroup); + Assert.assertNull(noEnrollmentDate); + + //add participant + Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-21"); + businessGroupRelationDao.addRole(participant, businessGroup, GroupRole.participant.name()); + dbInstance.commit(); + + // there is a participant enrolled + Date enrollmentDate = gtaManager.getEnrollmentDate(businessGroup); + Assert.assertNotNull(enrollmentDate); + } + @Test public void deleteTaskList() { Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-9"); @@ -378,8 +412,8 @@ public class GTAManagerTest extends OlatTestCase { BusinessGroup businessGroup = businessGroupDao.createAndPersist(coach, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); businessGroupRelationDao.addRole(participant, businessGroup, GroupRole.participant.name()); dbInstance.commit(); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); - GTACourseNode node = new GTACourseNode(); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.group.name()); TaskList tasks = gtaManager.createIfNotExists(re, node); File taskFile = new File("bg.txt"); @@ -419,10 +453,10 @@ public class GTAManagerTest extends OlatTestCase { BusinessGroup businessGroup = businessGroupDao.createAndPersist(coach, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); businessGroupRelationDao.addRole(participant, businessGroup, GroupRole.participant.name()); dbInstance.commit(); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); + RepositoryEntry re = deployGTACourse(); //node 1 - GTACourseNode node1 = new GTACourseNode(); + GTACourseNode node1 = getGTACourseNode(re); node1.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.group.name()); TaskList tasks1 = gtaManager.createIfNotExists(re, node1); File taskFile = new File("bg.txt"); @@ -476,11 +510,11 @@ public class GTAManagerTest extends OlatTestCase { Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-9"); Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-10"); dbInstance.commit(); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); + RepositoryEntry re = deployGTACourse(); repositoryEntryRelationDao.addRole(coach, re, GroupRoles.coach.name()); repositoryEntryRelationDao.addRole(participant, re, GroupRoles.participant.name()); - GTACourseNode node = new GTACourseNode(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList tasks = gtaManager.createIfNotExists(re, node); File taskFile = new File("bg.txt"); @@ -519,25 +553,25 @@ public class GTAManagerTest extends OlatTestCase { Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-21"); Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-22"); - RepositoryEntry re1 = JunitTestHelper.createAndPersistRepositoryEntry("", false); + RepositoryEntry re1 = deployGTACourse(); repositoryEntryRelationDao.addRole(coach, re1, GroupRoles.coach.name()); repositoryEntryRelationDao.addRole(participant1, re1, GroupRoles.participant.name()); repositoryEntryRelationDao.addRole(participant2, re1, GroupRoles.participant.name()); //course 1 - GTACourseNode node1 = new GTACourseNode(); + GTACourseNode node1 = getGTACourseNode(re1); node1.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList tasks1 = gtaManager.createIfNotExists(re1, node1); File taskFile = new File("bg.txt"); Assert.assertNotNull(tasks1); dbInstance.commit(); - RepositoryEntry re2 = JunitTestHelper.createAndPersistRepositoryEntry("", false); + RepositoryEntry re2 = deployGTACourse(); repositoryEntryRelationDao.addRole(coach, re2, GroupRoles.coach.name()); repositoryEntryRelationDao.addRole(participant1, re2, GroupRoles.participant.name()); //participant 2 course 2 - GTACourseNode node2 = new GTACourseNode(); + GTACourseNode node2 = getGTACourseNode(re2); node2.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); TaskList tasks2 = gtaManager.createIfNotExists(re2, node2); Assert.assertNotNull(tasks2); @@ -588,6 +622,62 @@ public class GTAManagerTest extends OlatTestCase { Assert.assertEquals(1, notDeletedAssignedTasks2_2.size()); } + @Test + public void createTaskRevisionDate() { + //prepare + Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-20"); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); + TaskList tasks = gtaManager.createIfNotExists(re, node); + dbInstance.commit(); + + //create task + Task task = gtaManager.createAndPersistTask(null, tasks, TaskProcess.assignment, null, participant, node); + dbInstance.commitAndCloseSession(); + + //create the revision log + TaskRevisionDate taskRevision = gtaManager.createAndPersistTaskRevisionDate(task, 2, TaskProcess.correction); + Assert.assertNotNull(taskRevision); + dbInstance.commitAndCloseSession(); + Assert.assertNotNull(taskRevision.getKey()); + Assert.assertNotNull(taskRevision.getDate()); + Assert.assertEquals(task, taskRevision.getTask()); + Assert.assertEquals(2, taskRevision.getRevisionLoop()); + Assert.assertEquals(TaskProcess.correction, taskRevision.getTaskStatus()); + } + + @Test + public void getTaskRevisions() { + //prepare + Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-21"); + RepositoryEntry re = deployGTACourse(); + GTACourseNode node = getGTACourseNode(re); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); + TaskList tasks = gtaManager.createIfNotExists(re, node); + dbInstance.commit(); + + //create a task + Task task = gtaManager.createAndPersistTask(null, tasks, TaskProcess.assignment, null, participant, node); + dbInstance.commitAndCloseSession(); + + //add the revision log + TaskRevisionDate taskRevision = gtaManager.createAndPersistTaskRevisionDate(task, 2, TaskProcess.correction); + Assert.assertNotNull(taskRevision); + dbInstance.commitAndCloseSession(); + + //load the revisions + List<TaskRevisionDate> taskRevisions = gtaManager.getTaskRevisions(task); + Assert.assertNotNull(taskRevisions); + Assert.assertEquals(1, taskRevisions.size()); + TaskRevisionDate loadedTaskRevision = taskRevisions.get(0); + Assert.assertNotNull(loadedTaskRevision.getKey()); + Assert.assertNotNull(loadedTaskRevision.getDate()); + Assert.assertEquals(task, loadedTaskRevision.getTask()); + Assert.assertEquals(2, loadedTaskRevision.getRevisionLoop()); + Assert.assertEquals(TaskProcess.correction, loadedTaskRevision.getTaskStatus()); + } + @Test public void roundRobin() { String[] slots = new String[]{ "A", "B", "C" }; @@ -644,4 +734,31 @@ public class GTAManagerTest extends OlatTestCase { String nextSlot = gtaManager.nextSlotRoundRobin(slots, usedSlots); Assert.assertEquals("C", nextSlot); } + + private RepositoryEntry deployGTACourse() { + try { + Identity initialAuthor = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-author"); + String displayname = "GTA-" + UUID.randomUUID(); + + URL courseUrl = JunitTestHelper.class.getResource("file_resources/GTA_course.zip"); + File courseFile = new File(courseUrl.toURI()); + return JunitTestHelper.deployCourse(initialAuthor, displayname, courseFile); + } catch (URISyntaxException e) { + log.error("", e); + return null; + } + } + + private GTACourseNode getGTACourseNode(RepositoryEntry courseEntry) { + ICourse course = CourseFactory.loadCourse(courseEntry); + CourseNode rootNode = course.getRunStructure().getRootNode(); + for(int i=rootNode.getChildCount(); i-->0; ) { + INode child = rootNode.getChildAt(i); + if(child instanceof GTACourseNode) { + return ((GTACourseNode)child); + } + } + + return null; + } } diff --git a/src/test/java/org/olat/course/nodes/gta/rule/GTAReminderRuleTest.java b/src/test/java/org/olat/course/nodes/gta/rule/GTAReminderRuleTest.java index aa88c554cad581ca7f4c88ee86224a72fda9119a..6d78418506b6aefb8390b39f6119d2bcf8ebbe91 100644 --- a/src/test/java/org/olat/course/nodes/gta/rule/GTAReminderRuleTest.java +++ b/src/test/java/org/olat/course/nodes/gta/rule/GTAReminderRuleTest.java @@ -20,6 +20,8 @@ package org.olat.course.nodes.gta.rule; import java.io.File; +import java.net.URISyntaxException; +import java.net.URL; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -32,9 +34,14 @@ import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.model.GroupMembershipImpl; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.nodes.INode; +import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.assessment.manager.UserCourseInformationsManager; import org.olat.course.assessment.model.UserCourseInfosImpl; +import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.AssignmentResponse; import org.olat.course.nodes.gta.GTARelativeToDates; @@ -66,6 +73,8 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class GTAReminderRuleTest extends OlatTestCase { + private static final OLog log = Tracing.createLoggerFor(GTAReminderRuleTest.class); + @Autowired private DB dbInstance; @Autowired @@ -92,12 +101,12 @@ public class GTAReminderRuleTest extends OlatTestCase { //prepare a course with a volatile task Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-1"); Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-2"); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); + RepositoryEntry re = deployGTACourse(); repositoryEntryRelationDao.addRole(participant1, re, GroupRoles.participant.name()); repositoryEntryRelationDao.addRole(participant2, re, GroupRoles.participant.name()); dbInstance.commit(); - GTACourseNode node = new GTACourseNode(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); Calendar cal = Calendar.getInstance(); @@ -404,12 +413,12 @@ public class GTAReminderRuleTest extends OlatTestCase { //prepare a course with a volatile task Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-1"); Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-2"); - RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); + RepositoryEntry re = deployGTACourse(); repositoryEntryRelationDao.addRole(participant1, re, GroupRoles.participant.name()); repositoryEntryRelationDao.addRole(participant2, re, GroupRoles.participant.name()); dbInstance.commit(); - GTACourseNode node = new GTACourseNode(); + GTACourseNode node = getGTACourseNode(re); node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); Calendar cal = Calendar.getInstance(); @@ -599,4 +608,31 @@ public class GTAReminderRuleTest extends OlatTestCase { rule.setRightUnit(unit.name()); return rule; } + + private RepositoryEntry deployGTACourse() { + try { + Identity initialAuthor = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-reminder"); + String displayname = "GTARemind-" + UUID.randomUUID(); + + URL courseUrl = JunitTestHelper.class.getResource("file_resources/GTA_course.zip"); + File courseFile = new File(courseUrl.toURI()); + return JunitTestHelper.deployCourse(initialAuthor, displayname, courseFile); + } catch (URISyntaxException e) { + log.error("", e); + return null; + } + } + + private GTACourseNode getGTACourseNode(RepositoryEntry courseEntry) { + ICourse course = CourseFactory.loadCourse(courseEntry); + CourseNode rootNode = course.getRunStructure().getRootNode(); + for(int i=rootNode.getChildCount(); i-->0; ) { + INode child = rootNode.getChildAt(i); + if(child instanceof GTACourseNode) { + return ((GTACourseNode)child); + } + } + + return null; + } } diff --git a/src/test/java/org/olat/course/statistic/HourOfDayStatisticUpdateManagerTest.java b/src/test/java/org/olat/course/statistic/HourOfDayStatisticUpdateManagerTest.java index 010df41580301767f9655540ae721870f04e7942..604af1369a6d05f4288fc0a22827fd7ca2d27e04 100644 --- a/src/test/java/org/olat/course/statistic/HourOfDayStatisticUpdateManagerTest.java +++ b/src/test/java/org/olat/course/statistic/HourOfDayStatisticUpdateManagerTest.java @@ -70,8 +70,8 @@ public class HourOfDayStatisticUpdateManagerTest extends AbstractStatisticUpdate cleanUpLog(); for(int i=0; i<12; i++) { - addLogEntry(re1, rootNode1, ref, 0, ref.get(Calendar.HOUR_OF_DAY), 1, i + 1); - addLogEntry(re2, firstNode2, ref, 0, ref.get(Calendar.HOUR_OF_DAY), 1, i + 1); + addLogEntry(re1, rootNode1, ref, 0, getSecuredNowRef(ref, 1, i + 1), 1, i + 1); + addLogEntry(re2, firstNode2, ref, 0, getSecuredNowRef(ref, 1, i + 1), 1, i + 1); } for(int i=0; i<7; i++) { addLogEntry(re1, rootNode1, ref, 1, 3 + i, 1, 1); @@ -115,6 +115,23 @@ public class HourOfDayStatisticUpdateManagerTest extends AbstractStatisticUpdate checkStatistics(course2, firstNode2, date); } + /** + * Prevent date in future. + * @param now + * @return + */ + private int getSecuredNowRef(Calendar now, int minute, int secondes) { + int hour = now.get(Calendar.HOUR_OF_DAY); + if(now.get(Calendar.MINUTE) < minute) { + hour--; + } else if(now.get(Calendar.MINUTE) == minute) { + if(now.get(Calendar.SECOND) < secondes) { + hour--; + } + } + return hour < 0 ? 0 : hour; + } + private void checkStatistics(ICourse course, CourseNode node, String date) { RepositoryEntry re = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); StatisticResult updatedResult = hourOfDayStatisticManager.generateStatisticResult(new SyntheticUserRequest(null, Locale.ENGLISH), course, re.getKey()); @@ -132,8 +149,8 @@ public class HourOfDayStatisticUpdateManagerTest extends AbstractStatisticUpdate protected String addLogEntry(RepositoryEntry repositoryEntry, CourseNode courseNode, Calendar start, int dayInPast, int hour, int minute, int second) { Calendar cal = addLog(repositoryEntry.getKey(), courseNode.getIdent(), start, dayInPast, hour, minute, second); - String week = getHourOfDay(cal); - incrementInMemoryStatistics(repositoryEntry.getKey(), courseNode.getIdent(), week); - return week; + String hourOfDay = getHourOfDay(cal); + incrementInMemoryStatistics(repositoryEntry.getKey(), courseNode.getIdent(), hourOfDay); + return hourOfDay; } } diff --git a/src/test/java/org/olat/group/test/BusinessGroupDAOTest.java b/src/test/java/org/olat/group/test/BusinessGroupDAOTest.java index 2017031211073bcd5fcb01ee0f3cc7bf1120cf52..aaeea9ae542f5bc26005a48f1e8d1a535a0bcd8d 100644 --- a/src/test/java/org/olat/group/test/BusinessGroupDAOTest.java +++ b/src/test/java/org/olat/group/test/BusinessGroupDAOTest.java @@ -48,29 +48,35 @@ import org.olat.group.model.BusinessGroupMembershipViewImpl; import org.olat.group.model.BusinessGroupQueryParams; import org.olat.group.model.BusinessGroupRow; import org.olat.group.model.OpenBusinessGroupRow; -import org.olat.group.model.StatisticsBusinessGroupRow; import org.olat.group.model.SearchBusinessGroupParams; +import org.olat.group.model.StatisticsBusinessGroupRow; import org.olat.repository.RepositoryEntry; import org.olat.repository.manager.RepositoryEntryRelationDAO; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.olat.resource.accesscontrol.ACService; import org.olat.resource.accesscontrol.Offer; +import org.olat.resource.accesscontrol.OfferAccess; +import org.olat.resource.accesscontrol.manager.ACMethodDAO; +import org.olat.resource.accesscontrol.model.AccessMethod; +import org.olat.resource.accesscontrol.model.TokenAccessMethod; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; /** - * + * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public class BusinessGroupDAOTest extends OlatTestCase { - + @Autowired private DB dbInstance; @Autowired private ACService acService; @Autowired + private ACMethodDAO acMethodManager; + @Autowired private MarkManager markManager; @Autowired private BusinessGroupDAO businessGroupDao; @@ -80,12 +86,12 @@ public class BusinessGroupDAOTest extends OlatTestCase { private BusinessGroupRelationDAO businessGroupRelationDao; @Autowired private RepositoryEntryRelationDAO repositoryEntryRelationDao; - + @Test public void should_service_present() { Assert.assertNotNull(businessGroupDao); } - + @Test public void createBusinessGroup() { BusinessGroup group = businessGroupDao.createAndPersist(null, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); @@ -103,14 +109,14 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertFalse(group.getWaitingListEnabled()); Assert.assertFalse(group.getAutoCloseRanksEnabled()); } - + @Test public void loadBusinessGroupStandard() { BusinessGroup group = businessGroupDao.createAndPersist(null, "gdbo", "gdbo-desc", -1, -1, false, false, false, false, false); dbInstance.commitAndCloseSession(); - + BusinessGroup reloadedGroup = businessGroupDao.load(group.getKey()); - + Assert.assertNotNull(reloadedGroup); Assert.assertNull(reloadedGroup.getMinParticipants()); Assert.assertNull(reloadedGroup.getMaxParticipants()); @@ -123,13 +129,13 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertFalse(reloadedGroup.getWaitingListEnabled()); Assert.assertFalse(reloadedGroup.getAutoCloseRanksEnabled()); } - + @Test public void loadBusinessGroup() { //create business group BusinessGroup group = businessGroupDao.createAndPersist(null, "gdco", "gdco-desc", 0, 10, true, true, false, false, false); dbInstance.commitAndCloseSession(); - + BusinessGroup reloadedGroup = businessGroupDao.load(group.getKey()); //check the saved values Assert.assertNotNull(reloadedGroup); @@ -145,17 +151,17 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(reloadedGroup.getWaitingListEnabled()); Assert.assertTrue(reloadedGroup.getAutoCloseRanksEnabled()); } - + @Test public void loadBusinessGroup_fetch() { //create business group BusinessGroup group = businessGroupDao.createAndPersist(null, "gd-fetch", "gd-fetch-desc", 0, 10, true, true, false, false, false); dbInstance.commitAndCloseSession(); - + BusinessGroup reloadedGroup = businessGroupDao.load(group.getKey()); Assert.assertNotNull(reloadedGroup); dbInstance.commitAndCloseSession(); - + //check lazy Group baseGroup = reloadedGroup.getBaseGroup(); Assert.assertNotNull(baseGroup); @@ -164,20 +170,20 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNotNull(resource); Assert.assertNotNull(resource.getKey()); } - + @Test public void loadBusinessGroup_forUpdate() { //create a group BusinessGroup group = businessGroupDao.createAndPersist(null, "gdco", "gdco-desc", 0, 10, true, true, false, false, false); dbInstance.commitAndCloseSession(); - + //load an lock BusinessGroup groupForUpdate = businessGroupDao.loadForUpdate(group.getKey()); Assert.assertNotNull(groupForUpdate); Assert.assertEquals(group, groupForUpdate); dbInstance.commit();//release lock } - + @Test public void loadBusinessGroup_forUpdate_notFound() { //load and lock an inexistent group @@ -185,40 +191,40 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNull(groupForUpdate); dbInstance.commit();//release lock } - + @Test public void loadBusinessGroupWithOwner() { Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("bdao-1-" + UUID.randomUUID().toString()); dbInstance.commitAndCloseSession(); - + BusinessGroup group = businessGroupDao.createAndPersist(owner, "gddo", "gddo-desc", 0, 10, true, true, false, false, false); dbInstance.commitAndCloseSession(); - + BusinessGroup reloadedGroup = businessGroupDao.load(group.getKey()); //check if the owner is in the owner security group Assert.assertNotNull(reloadedGroup); boolean isOwner = businessGroupRelationDao.hasRole(owner, reloadedGroup, GroupRoles.coach.name()); Assert.assertTrue(isOwner); } - + @Test public void loadBusinessGroupsByIds() { Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("bdao-2-" + UUID.randomUUID().toString()); BusinessGroup group1 = businessGroupDao.createAndPersist(owner, "gdeo", "gdeo-desc", 0, 10, true, true, false, false, false); BusinessGroup group2 = businessGroupDao.createAndPersist(owner, "gdfo", "gdfo-desc", 0, 10, true, true, false, false, false); dbInstance.commitAndCloseSession(); - + //check if the method is robust against empty list fo keys List<BusinessGroup> groups1 = businessGroupDao.load(Collections.<Long>emptyList()); Assert.assertNotNull(groups1); Assert.assertEquals(0, groups1.size()); - + //check load 1 group List<BusinessGroup> groups2 = businessGroupDao.load(Collections.singletonList(group1.getKey())); Assert.assertNotNull(groups2); Assert.assertEquals(1, groups2.size()); Assert.assertEquals(group1, groups2.get(0)); - + //check load 2 groups List<Long> groupKeys = new ArrayList<Long>(2); groupKeys.add(group1.getKey()); @@ -229,25 +235,25 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(groups3.contains(group1)); Assert.assertTrue(groups3.contains(group2)); } - + @Test public void loadShortBusinessGroupsByKeys() { BusinessGroup group1 = businessGroupDao.createAndPersist(null, "shorty-1", "shorty-1-desc", 0, 10, true, true, false, false, false); BusinessGroup group2 = businessGroupDao.createAndPersist(null, "shorty-2", "shorty-2-desc", 0, 10, true, true, false, false, false); dbInstance.commitAndCloseSession(); - + //check if the method is robust against empty list fo keys List<BusinessGroupShort> groups1 = businessGroupDao.loadShort(Collections.<Long>emptyList()); Assert.assertNotNull(groups1); Assert.assertEquals(0, groups1.size()); - + //check load 1 group List<BusinessGroupShort> groups2 = businessGroupDao.loadShort(Collections.singletonList(group1.getKey())); Assert.assertNotNull(groups2); Assert.assertEquals(1, groups2.size()); Assert.assertEquals(group1.getKey(), groups2.get(0).getKey()); Assert.assertEquals(group1.getName(), groups2.get(0).getName()); - + //check load 2 groups List<Long> groupKeys = new ArrayList<Long>(2); groupKeys.add(group1.getKey()); @@ -273,14 +279,14 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNotNull(loadDescription); Assert.assertEquals(description, loadDescription); } - + @Test public void loadAllBusinessGroups() { Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("bdao-3-" + UUID.randomUUID().toString()); BusinessGroup group1 = businessGroupDao.createAndPersist(owner, "gdgo", "gdgo-desc", 0, 10, true, true, false, false, false); BusinessGroup group2 = businessGroupDao.createAndPersist(owner, "gdho", "gdho-desc", 0, 10, true, true, false, false, false); dbInstance.commitAndCloseSession(); - + //load all business groups List<BusinessGroup> allGroups = businessGroupDao.loadAll(); Assert.assertNotNull(allGroups); @@ -288,14 +294,14 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(allGroups.contains(group1)); Assert.assertTrue(allGroups.contains(group2)); } - + @Test public void mergeBusinessGroup() { //create a business group Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("bdao-3-" + UUID.randomUUID().toString()); BusinessGroup group = businessGroupDao.createAndPersist(owner, "gdho", "gdho-desc", 0, 10, true, true, false, false, false); dbInstance.commitAndCloseSession(); - + //delete a business group group.setAutoCloseRanksEnabled(false); group.setName("gdho-2"); @@ -306,9 +312,9 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertEquals(group, mergedGroup); Assert.assertEquals("gdho-2", mergedGroup.getName()); Assert.assertEquals(Boolean.FALSE, mergedGroup.getAutoCloseRanksEnabled()); - + dbInstance.commitAndCloseSession(); - + //reload the merged group and check values BusinessGroup reloadedGroup = businessGroupDao.load(group.getKey()); Assert.assertNotNull(reloadedGroup); @@ -316,14 +322,14 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertEquals("gdho-2", reloadedGroup.getName()); Assert.assertEquals(Boolean.FALSE, reloadedGroup.getAutoCloseRanksEnabled()); } - + @Test public void updateBusinessGroup() { //create a business group Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("bdao-4-" + UUID.randomUUID().toString()); BusinessGroup group = businessGroupDao.createAndPersist(owner, "gdio", "gdio-desc", 1, 10, true, true, false, false, false); dbInstance.commitAndCloseSession(); - + //delete a business group group.setWaitingListEnabled(false); group.setDescription("gdio-2-desc"); @@ -335,9 +341,9 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertEquals("gdio-2-desc", updatedGroup.getDescription()); Assert.assertEquals(Boolean.FALSE, updatedGroup.getWaitingListEnabled()); Assert.assertTrue(updatedGroup.equals(group)); - + dbInstance.commitAndCloseSession(); - + //reload the merged group and check values BusinessGroup reloadedGroup = businessGroupDao.load(group.getKey()); Assert.assertNotNull(reloadedGroup); @@ -345,7 +351,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertEquals("gdio-2-desc", reloadedGroup.getDescription()); Assert.assertEquals(Boolean.FALSE, reloadedGroup.getWaitingListEnabled()); } - + @Test public void findBusinessGroupsWithWaitingListAttendedBy() { //3 identities @@ -358,7 +364,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { BusinessGroup group2 = businessGroupDao.createAndPersist(null, "gdmo", "gdmo-desc", 0, 5, true, false, false, false, false); BusinessGroup group3 = businessGroupDao.createAndPersist(null, "gdno", "gdno-desc", 0, 5, true, false, false, false, false); dbInstance.commitAndCloseSession(); - + //id1 -> group 1 and 2 businessGroupRelationDao.addRole(id1, group1, GroupRoles.waiting.name()); businessGroupRelationDao.addRole(id1, group2, GroupRoles.waiting.name()); @@ -382,7 +388,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNotNull(groupOfId3); Assert.assertTrue(groupOfId3.isEmpty()); } - + @Test public void testVisibilityOfSecurityGroups() { //create 3 groups @@ -390,21 +396,21 @@ public class BusinessGroupDAOTest extends OlatTestCase { BusinessGroup group2 = businessGroupDao.createAndPersist(null, "gdso", "gdso-desc", 0, 5, true, false, false, true, false); BusinessGroup group3 = businessGroupDao.createAndPersist(null, "gdto", "gdto-desc", 0, 5, true, false, false, false, true); dbInstance.commitAndCloseSession(); - + //check the value Assert.assertTrue(group1.isOwnersVisibleIntern()); Assert.assertTrue(group1.isParticipantsVisibleIntern()); Assert.assertFalse(group1.isWaitingListVisibleIntern()); - + Assert.assertFalse(group2.isOwnersVisibleIntern()); Assert.assertTrue(group2.isParticipantsVisibleIntern()); Assert.assertFalse(group2.isWaitingListVisibleIntern()); - + Assert.assertFalse(group3.isOwnersVisibleIntern()); Assert.assertFalse(group3.isParticipantsVisibleIntern()); Assert.assertTrue(group3.isWaitingListVisibleIntern()); } - + @Test public void findBusinessGroups() { Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search"); @@ -412,7 +418,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { BusinessGroup group2 = businessGroupDao.createAndPersist(null, "gdvo", "gdvo-desc", 0, 5, true, false, true, false, false); dbInstance.commitAndCloseSession(); - SearchBusinessGroupParams params = new SearchBusinessGroupParams(); + SearchBusinessGroupParams params = new SearchBusinessGroupParams(); List<BusinessGroup> groups = businessGroupDao.findBusinessGroups(params, null, 0, -1); Assert.assertNotNull(groups); Assert.assertTrue(groups.size() >= 2); @@ -429,11 +435,11 @@ public class BusinessGroupDAOTest extends OlatTestCase { List<StatisticsBusinessGroupRow> groupToSelect = businessGroupDao.searchBusinessGroupsForSelection(searchParams, identity); Assert.assertNotNull(groupToSelect); Assert.assertTrue(groupToSelect.size() >= 2); - + List<OpenBusinessGroupRow> openGroups = businessGroupDao.searchPublishedBusinessGroups(searchParams, identity); Assert.assertNotNull(openGroups); } - + @Test public void findBusinessGroupsByExactName() { String exactName = UUID.randomUUID().toString(); @@ -451,7 +457,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertFalse(groups.contains(group2)); Assert.assertFalse(groups.contains(group3)); } - + @Test public void findBusinessGroupsByName() { String marker = UUID.randomUUID().toString(); @@ -469,7 +475,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(groups.contains(group1)); Assert.assertTrue(groups.contains(group2)); Assert.assertFalse(groups.contains(group3)); - + //check the same with the views BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams(); searchParams.setName(marker); @@ -480,7 +486,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(contains(groupViews, group2)); Assert.assertFalse(contains(groupViews, group3)); } - + @Test public void findBusinessGroupsByNameFuzzy() { String marker = UUID.randomUUID().toString(); @@ -498,7 +504,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(groups.contains(group1)); Assert.assertTrue(groups.contains(group2)); Assert.assertTrue(groups.contains(group3)); - + //check the same with the views BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams(); searchParams.setName("*" + marker + "*"); @@ -509,7 +515,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(contains(groupViews, group2)); Assert.assertTrue(contains(groupViews, group3)); } - + @Test public void findBusinessGroupsByDescription() { String marker = UUID.randomUUID().toString(); @@ -528,7 +534,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(groups.contains(group1)); Assert.assertFalse(groups.contains(group2)); Assert.assertFalse(groups.contains(group3)); - + //check find business group BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams(); @@ -540,7 +546,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertFalse(contains(groupViews, group2)); Assert.assertFalse(contains(groupViews, group3)); } - + @Test public void findBusinessGroupsByDescriptionFuzzy() { String marker = UUID.randomUUID().toString(); @@ -558,7 +564,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(groups.contains(group1)); Assert.assertTrue(groups.contains(group2)); Assert.assertTrue(groups.contains(group3)); - + //check same search with the views BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams(); @@ -570,7 +576,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(contains(groupViews, group2)); Assert.assertTrue(contains(groupViews, group3)); } - + @Test public void findBusinessGroupsByNameOrDesc() { String marker = UUID.randomUUID().toString(); @@ -588,7 +594,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(groups.contains(group1)); Assert.assertFalse(groups.contains(group2)); Assert.assertTrue(groups.contains(group3)); - + //check the same search with the views BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams(); searchParams.setNameOrDesc(marker); @@ -599,7 +605,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertFalse(contains(groupViews, group2)); Assert.assertTrue(contains(groupViews, group3)); } - + @Test public void findBusinessGroupsByNameOrDescFuzzy() { String marker = UUID.randomUUID().toString(); @@ -617,7 +623,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(groups.contains(group1)); Assert.assertTrue(groups.contains(group2)); Assert.assertTrue(groups.contains(group3)); - + //check the same search with the views BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams(); searchParams.setNameOrDesc("*" + marker + "*"); @@ -628,7 +634,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(contains(groupViews, group2)); Assert.assertTrue(contains(groupViews, group3)); } - + @Test public void findBusinessGroupsByOwner() { //5 identities @@ -641,7 +647,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { BusinessGroup group2 = businessGroupDao.createAndPersist(id2, "fingbgown-2", "fingbgown-2-desc", 0, 5, true, false, true, false, false); BusinessGroup group3 = businessGroupDao.createAndPersist(id3, "fingbgown-3", "fingbgown-3-desc", 0, 5, true, false, true, false, false); dbInstance.commitAndCloseSession(); - + //check the same with the views BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams(); searchParams.setOwnerName(marker); @@ -652,19 +658,19 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertFalse(contains(groupViews, group2)); Assert.assertTrue(contains(groupViews, group3)); } - + @Test public void findBusinessGroupsByOwnerFuzzy() { String marker = UUID.randomUUID().toString(); Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser(marker); Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("ddao-2-" + marker.toUpperCase()); Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser(marker + "-ddao-3-"); - + BusinessGroup group1 = businessGroupDao.createAndPersist(id1, "fingbg-own-1-1", "fingbg-own-1-1-desc", 0, 5, true, false, true, false, false); BusinessGroup group2 = businessGroupDao.createAndPersist(id2, "fingbg-own-1-2", "fingbg-own-1-2-desc", 0, 5, true, false, true, false, false); BusinessGroup group3 = businessGroupDao.createAndPersist(id3, "fingbg-own-1-3", "fingbg-own-1-3-desc", 0, 5, true, false, true, false, false); dbInstance.commitAndCloseSession(); - + //check the same with the views BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams(); searchParams.setOwnerName("*" + marker + "*"); @@ -675,27 +681,27 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(contains(groupViews, group2)); Assert.assertTrue(contains(groupViews, group3)); } - + @Test public void findBusinessGroupWithAuthorConnection() { Identity author = JunitTestHelper.createAndPersistIdentityAsUser("bdao-5-" + UUID.randomUUID().toString()); RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry(); repositoryEntryRelationDao.addRole(author, re, GroupRoles.owner.name()); - + BusinessGroup group1 = businessGroupDao.createAndPersist(null, "gdlo", "gdlo-desc", 0, 5, true, false, false, false, false); BusinessGroup group2 = businessGroupDao.createAndPersist(author, "gdmo", "gdmo-desc", 0, 5, true, false, false, false, false); BusinessGroup group3 = businessGroupDao.createAndPersist(author, "gdmo", "gdmo-desc", 0, 5, true, false, false, false, false); businessGroupRelationDao.addRelationToResource(group1, re); businessGroupRelationDao.addRelationToResource(group3, re); dbInstance.commitAndCloseSession(); - - //check + + //check BusinessGroupQueryParams params = new BusinessGroupQueryParams(); params.setAuthorConnection(true); List<StatisticsBusinessGroupRow> groups = businessGroupDao.searchBusinessGroupsForSelection(params, author); Assert.assertNotNull(groups); Assert.assertEquals(2, groups.size()); - + Set<Long> retrievedGroupkey = new HashSet<Long>(); for(StatisticsBusinessGroupRow group:groups) { retrievedGroupkey.add(group.getKey()); @@ -704,7 +710,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(retrievedGroupkey.contains(group3.getKey())); Assert.assertFalse(retrievedGroupkey.contains(group2.getKey())); } - + @Test public void findBusinessGroupsByIdentity() { Identity id = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-" + UUID.randomUUID().toString()); @@ -725,7 +731,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNotNull(ownedGroups); Assert.assertEquals(1, ownedGroups.size()); Assert.assertTrue(ownedGroups.contains(group1)); - + //check attendee SearchBusinessGroupParams paramsAttendee = new SearchBusinessGroupParams(); paramsAttendee.setIdentity(id); @@ -743,7 +749,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNotNull(waitingGroups); Assert.assertEquals(1, waitingGroups.size()); Assert.assertTrue(waitingGroups.contains(group3)); - + //check all SearchBusinessGroupParams paramsAll = new SearchBusinessGroupParams(); paramsAll.setIdentity(id); @@ -756,7 +762,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(allGroups.contains(group1)); Assert.assertTrue(allGroups.contains(group2)); Assert.assertTrue(allGroups.contains(group3)); - + //The same tests with the views //check owner on views BusinessGroupQueryParams queryParamsOwner = new BusinessGroupQueryParams(); @@ -765,7 +771,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNotNull(ownedGroupViews); Assert.assertEquals(1, ownedGroupViews.size()); Assert.assertTrue(contains(ownedGroupViews, group1)); - + //check attendee on views BusinessGroupQueryParams queryParamsAttendee = new BusinessGroupQueryParams(); queryParamsAttendee.setAttendee(true); @@ -781,7 +787,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNotNull(waitingGroupViews); Assert.assertEquals(1, waitingGroupViews.size()); Assert.assertTrue(contains(waitingGroupViews, group3)); - + //check all on views BusinessGroupQueryParams queryParamsAll = new BusinessGroupQueryParams(); queryParamsAll.setOwner(true); @@ -794,7 +800,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(contains(allGroupViews, group2)); Assert.assertTrue(contains(allGroupViews, group3)); } - + @Test public void findBusinessGroupsByRepositoryEntry() { //create a repository entry with a relation to a group @@ -816,7 +822,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertEquals(1, groupViews.size()); Assert.assertEquals(group.getKey(), groupViews.get(0).getKey()); } - + @Test public void findBusinessGroupsByCourseTitle() { @@ -839,7 +845,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertEquals(1, groupViews.size()); Assert.assertEquals(group.getKey(), groupViews.get(0).getKey()); } - + @Test public void findManagedGroups() { //create a managed group with an external ID @@ -859,7 +865,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(managedGroups.size() >= 1); Assert.assertTrue(managedGroups.contains(managedGroup)); Assert.assertFalse(managedGroups.contains(freeGroup)); - + //search free group SearchBusinessGroupParams paramsAll = new SearchBusinessGroupParams(); paramsAll.setManaged(Boolean.FALSE); @@ -869,8 +875,8 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(freeGroups.contains(freeGroup)); Assert.assertFalse(freeGroups.contains(managedGroup)); } - - + + @Test public void findGroupByExternalId() { //create a managed group with an external ID @@ -879,7 +885,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { BusinessGroup group = businessGroupDao.createAndPersist(null, "managed-grp-2", "managed-grp-2-desc", externalId, managedFlags, 0, 5, true, false, true, false, false); dbInstance.commitAndCloseSession(); - + //search SearchBusinessGroupParams paramsAll = new SearchBusinessGroupParams(); paramsAll.setExternalId(externalId); @@ -898,9 +904,15 @@ public class BusinessGroupDAOTest extends OlatTestCase { Offer offer = acService.createOffer(group.getResource(), "TestBGWorkflow"); assertNotNull(offer); offer = acService.save(offer); - + + acMethodManager.enableMethod(TokenAccessMethod.class, true); + List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); + AccessMethod method = methods.get(0); + OfferAccess access = acMethodManager.createOfferAccess(offer, method); + acMethodManager.save(access); + dbInstance.commitAndCloseSession(); - + //retrieve the offer //check the search with the views BusinessGroupQueryParams queryAllParams = new BusinessGroupQueryParams(); @@ -909,7 +921,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNotNull(accessGroupViews); Assert.assertTrue(accessGroupViews.size() >= 1); Assert.assertTrue(contains(accessGroupViews, group)); - + for(OpenBusinessGroupRow accessGroup:accessGroupViews) { OLATResource resource = resourceManager.findResourceById(accessGroup.getResourceKey()); List<Offer> offers = acService.findOfferByResource(resource, true, new Date()); @@ -917,7 +929,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertFalse(offers.isEmpty()); } } - + @Test public void findPublicGroupsLimitedDate() { //create a group with an access control limited by a valid date @@ -934,6 +946,12 @@ public class BusinessGroupDAOTest extends OlatTestCase { assertNotNull(offer); offer = acService.save(offer); + acMethodManager.enableMethod(TokenAccessMethod.class, true); + List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); + AccessMethod method = methods.get(0); + OfferAccess access = acMethodManager.createOfferAccess(offer, method); + acMethodManager.save(access); + //create a group with an access control limited by dates in the past BusinessGroup oldGroup = businessGroupDao.createAndPersist(null, "access-grp-3", "access-grp-3-desc", 0, 5, true, false, true, false, false); //create and save an offer @@ -945,8 +963,11 @@ public class BusinessGroupDAOTest extends OlatTestCase { assertNotNull(oldOffer); oldOffer = acService.save(oldOffer); + OfferAccess oldAccess = acMethodManager.createOfferAccess(oldOffer, method); + acMethodManager.save(oldAccess); + dbInstance.commitAndCloseSession(); - + //retrieve the offer BusinessGroupQueryParams paramsAll = new BusinessGroupQueryParams(); paramsAll.setPublicGroups(Boolean.TRUE); @@ -955,7 +976,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(accessGroups.size() >= 1); Assert.assertTrue(contains(accessGroups, groupVisible)); Assert.assertFalse(contains(accessGroups, oldGroup)); - } + } @Test public void findBusinessGroupsWithResources() { @@ -985,7 +1006,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertFalse(groupViewWithout.isEmpty()); Assert.assertTrue(contains(groupViewWithout, group2)); } - + @Test public void findMarkedBusinessGroup() { Identity marker = JunitTestHelper.createAndPersistIdentityAsUser("marker-" + UUID.randomUUID().toString()); @@ -994,7 +1015,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { BusinessGroup group2 = businessGroupDao.createAndPersist(marker, "marked-grp-2", "marked-grp-2-desc", 0, 5, true, false, true, false, false); markManager.setMark(group1.getResource(), marker, null, "[BusinessGroup:" + group1.getKey() + "]"); dbInstance.commitAndCloseSession(); - + //check the search with the views //check marked BusinessGroupQueryParams queryMarkedParams = new BusinessGroupQueryParams(); @@ -1017,7 +1038,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { markManager.setMark(group1.getResource(), marker1, null, "[BusinessGroup:" + group1.getKey() + "]"); markManager.setMark(group2.getResource(), marker2, null, "[BusinessGroup:" + group2.getKey() + "]"); dbInstance.commitAndCloseSession(); - + //check the search with views //check marked BusinessGroupQueryParams queryParamsMarker1 = new BusinessGroupQueryParams(); @@ -1027,14 +1048,14 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertEquals(1, markedGroupViews.size()); Assert.assertTrue(contains(markedGroupViews, group1)); } - + @Test public void findBusinessGroupsHeadless() { Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("head-1-" + UUID.randomUUID().toString()); BusinessGroup headlessGroup = businessGroupDao.createAndPersist(null, "headless-grp", "headless-grp-desc", 0, 5, true, false, true, false, false); BusinessGroup headedGroup = businessGroupDao.createAndPersist(owner, "headed-grp", "headed-grp-desc", 0, 5, true, false, true, false, false); dbInstance.commitAndCloseSession(); - + //check marked BusinessGroupQueryParams headlessParams = new BusinessGroupQueryParams(); headlessParams.setHeadless(true); @@ -1044,7 +1065,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(contains(groups, headlessGroup)); Assert.assertFalse(contains(groups, headedGroup)); } - + @Test public void findBusinessGroups_my() { Identity id = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-" + UUID.randomUUID().toString()); @@ -1065,7 +1086,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertTrue(originalKeys.contains(group2.getKey())); Assert.assertFalse(originalKeys.contains(group3.getKey())); } - + @Test public void isIdentityInBusinessGroups() { Identity id = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-" + UUID.randomUUID().toString()); @@ -1077,7 +1098,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { businessGroupRelationDao.addRole(id, group2, GroupRoles.participant.name()); businessGroupRelationDao.addRole(id, group3, GroupRoles.waiting.name()); dbInstance.commitAndCloseSession(); - + List<BusinessGroup> groups = new ArrayList<BusinessGroup>(); groups.add(group1); groups.add(group2); @@ -1089,20 +1110,20 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertEquals(2, groupKeysA.size()); Assert.assertTrue(groupKeysA.contains(group1.getKey())); Assert.assertTrue(groupKeysA.contains(group2.getKey())); - - //check owner + + //check owner List<Long> groupKeysB = businessGroupDao.isIdentityInBusinessGroups(id, true, false, false, groups); Assert.assertNotNull(groupKeysB); Assert.assertEquals(1, groupKeysB.size()); Assert.assertTrue(groupKeysB.contains(group1.getKey())); - //check attendee + //check attendee List<Long> groupKeysC = businessGroupDao.isIdentityInBusinessGroups(id, false, true, false, groups); Assert.assertNotNull(groupKeysC); Assert.assertEquals(1, groupKeysC.size()); Assert.assertTrue(groupKeysC.contains(group2.getKey())); } - + @Test public void getMembershipInfoInBusinessGroups() { Identity id = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-" + UUID.randomUUID().toString()); @@ -1114,7 +1135,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { businessGroupRelationDao.addRole(id, group2, GroupRoles.participant.name()); businessGroupRelationDao.addRole(id, group3, GroupRoles.waiting.name()); dbInstance.commitAndCloseSession(); - + List<Long> groupKeys = new ArrayList<Long>(); groupKeys.add(group1.getKey()); groupKeys.add(group2.getKey()); @@ -1126,7 +1147,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { List<BusinessGroupMembershipViewImpl> memberships = businessGroupDao.getMembershipInfoInBusinessGroups(groupKeys, id); Assert.assertNotNull(memberships); Assert.assertEquals(3, memberships.size()); - + int found = 0; for(BusinessGroupMembershipViewImpl membership:memberships) { Assert.assertNotNull(membership.getIdentityKey()); @@ -1144,7 +1165,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { } Assert.assertEquals(3, found); } - + @Test public void getBusinessGroupsMembership() { Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-rev-1" + UUID.randomUUID().toString()); @@ -1159,7 +1180,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { businessGroupRelationDao.addRole(id2, group2, GroupRoles.participant.name()); businessGroupRelationDao.addRole(id2, group3, GroupRoles.participant.name()); dbInstance.commitAndCloseSession(); - + List<BusinessGroup> groups = new ArrayList<BusinessGroup>(); groups.add(group1); groups.add(group2); @@ -1202,14 +1223,14 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertEquals("Participants", 3, foundPart); Assert.assertEquals("Waiting", 1, foundWait); } - - + + @Test public void getMembershipInfoInBusinessGroupsWithoutIdentityParam() { Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-" + UUID.randomUUID().toString()); Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-" + UUID.randomUUID().toString()); Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-" + UUID.randomUUID().toString()); - + BusinessGroup group1 = businessGroupDao.createAndPersist(id1, "is-in-grp-1", "is-in-grp-1-desc", 0, 5, true, false, true, false, false); BusinessGroup group2 = businessGroupDao.createAndPersist(id2, "is-in-grp-2", "is-in-grp-2-desc", 0, 5, true, false, true, false, false); BusinessGroup group3 = businessGroupDao.createAndPersist(null, "is-in-grp-3", "is-in-grp-3-desc", 0, 5, true, false, true, false, false); @@ -1221,7 +1242,7 @@ public class BusinessGroupDAOTest extends OlatTestCase { businessGroupRelationDao.addRole(id3, group2, GroupRoles.waiting.name()); businessGroupRelationDao.addRole(id3, group3, GroupRoles.participant.name()); dbInstance.commitAndCloseSession(); - + List<Long> groupKeys = new ArrayList<Long>(); groupKeys.add(group1.getKey()); groupKeys.add(group2.getKey()); @@ -1237,12 +1258,12 @@ public class BusinessGroupDAOTest extends OlatTestCase { Assert.assertNotNull(membership.getLastModified()); } } - + private boolean contains(List<? extends BusinessGroupRef> rows, BusinessGroup group) { if(rows != null && !rows.isEmpty()) { for(BusinessGroupRef row:rows) { if(row.getKey().equals(group.getKey())) { - return true; + return true; } } } diff --git a/src/test/java/org/olat/ims/qti/QTIResultManagerTest.java b/src/test/java/org/olat/ims/qti/QTIResultManagerTest.java index 4d2e36e30f66543aa7e548d1a301e8dbd69d7579..c7ce9871ffab7d85989ed64d43e1f8858e945c43 100644 --- a/src/test/java/org/olat/ims/qti/QTIResultManagerTest.java +++ b/src/test/java/org/olat/ims/qti/QTIResultManagerTest.java @@ -355,9 +355,6 @@ public class QTIResultManagerTest extends OlatTestCase { List<QTIResultSet> sets = qtiResultManager.getResultSets(re1.getOlatResource().getResourceableId(), resSubPath, re1.getKey(), null); Assert.assertNotNull(sets); Assert.assertEquals(0, sets.size()); - Assert.assertFalse(sets.contains(result1_1a)); - Assert.assertFalse(sets.contains(result1_1b)); - Assert.assertFalse(sets.contains(result2_1)); List<QTIResultSet> setRe2s = qtiResultManager.getResultSets(re2.getOlatResource().getResourceableId(), resSubPath, re2.getKey(), null); Assert.assertNotNull(setRe2s); @@ -368,6 +365,9 @@ public class QTIResultManagerTest extends OlatTestCase { List<QTIResult> results = qtiResultManager.selectResults(re1.getOlatResource().getResourceableId(), resSubPath, re1.getKey(), null, 3); Assert.assertNotNull(results); Assert.assertEquals(0, results.size()); + Assert.assertFalse(results.contains(result1_1a)); + Assert.assertFalse(results.contains(result1_1b)); + Assert.assertFalse(results.contains(result2_1)); List<QTIResult> resultsRe2 = qtiResultManager.selectResults(re2.getOlatResource().getResourceableId(), resSubPath, re2.getKey(), null, 3); Assert.assertNotNull(resultsRe2); diff --git a/src/test/java/org/olat/ims/qti/questionimport/CSVToQuestionConverterTest.java b/src/test/java/org/olat/ims/qti/questionimport/CSVToQuestionConverterTest.java index a7c9c090b244a365592ef195aba650ffa5c7c5a0..107f36257f73e7b19f0a9f3964d14645b87e4f20 100644 --- a/src/test/java/org/olat/ims/qti/questionimport/CSVToQuestionConverterTest.java +++ b/src/test/java/org/olat/ims/qti/questionimport/CSVToQuestionConverterTest.java @@ -55,7 +55,7 @@ public class CSVToQuestionConverterTest { URL importTxtUrl = CSVToQuestionConverterTest.class.getResource("question_import_mc.txt"); Assert.assertNotNull(importTxtUrl); File importTxt = new File(importTxtUrl.toURI()); - String input = FileUtils.readFileToString(importTxt); + String input = FileUtils.readFileToString(importTxt, "UTF-8"); Translator translator = new KeyTranslator(Locale.ENGLISH); ImportOptions options = new ImportOptions(); @@ -118,7 +118,7 @@ public class CSVToQuestionConverterTest { URL importTxtUrl = CSVToQuestionConverterTest.class.getResource("question_import_fib.txt"); Assert.assertNotNull(importTxtUrl); File importTxt = new File(importTxtUrl.toURI()); - String input = FileUtils.readFileToString(importTxt); + String input = FileUtils.readFileToString(importTxt, "UTF-8"); Translator translator = new KeyTranslator(Locale.ENGLISH); ImportOptions options = new ImportOptions(); @@ -170,7 +170,7 @@ public class CSVToQuestionConverterTest { URL importTxtUrl = CSVToQuestionConverterTest.class.getResource("question_import_fib_en_metadata.txt"); Assert.assertNotNull(importTxtUrl); File importTxt = new File(importTxtUrl.toURI()); - String input = FileUtils.readFileToString(importTxt); + String input = FileUtils.readFileToString(importTxt, "UTF-8"); Translator translator = new KeyTranslator(Locale.ENGLISH); ImportOptions options = new ImportOptions(); diff --git a/src/test/java/org/olat/ims/qti21/model/xml/AssessmentItemCheckerTest.java b/src/test/java/org/olat/ims/qti21/model/xml/AssessmentItemCheckerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0eb4816b366503ee57b5972b8670c40bd455a4bd --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/AssessmentItemCheckerTest.java @@ -0,0 +1,101 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.model.xml; + +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Paths; + +import org.junit.Assert; +import org.junit.Test; +import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; + +import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; +import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; +import uk.ac.ed.ph.jqtiplus.node.item.template.declaration.TemplateDeclaration; +import uk.ac.ed.ph.jqtiplus.reading.AssessmentObjectXmlLoader; +import uk.ac.ed.ph.jqtiplus.reading.QtiXmlReader; +import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; +import uk.ac.ed.ph.jqtiplus.types.Identifier; +import uk.ac.ed.ph.jqtiplus.value.BaseType; +import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; + +/** + * Use some templates of QtiWorks sets. + * + * Initial date: 5 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AssessmentItemCheckerTest { + + @Test + public void checkAndCorrect_wrongType() throws URISyntaxException { + URL itemUrl = OnyxToAssessmentItemBuilderTest.class.getResource("resources/onyx/set-correct-response-wrong-type-5-11.xml"); + AssessmentItem assessmentItem = loadAssessmentItem(itemUrl); + boolean ok = AssessmentItemChecker.checkAndCorrect(assessmentItem); + Assert.assertFalse(ok); + + TemplateDeclaration solutionDeclaration = assessmentItem.getTemplateDeclaration(Identifier.assumedLegal("solution")); + Assert.assertEquals(BaseType.FLOAT, solutionDeclaration.getBaseType()); + } + + @Test + public void checkAndCorrect_rightType() throws URISyntaxException { + URL itemUrl = OnyxToAssessmentItemBuilderTest.class.getResource("resources/umpc/addition.xml"); + AssessmentItem assessmentItem = loadAssessmentItem(itemUrl); + boolean ok = AssessmentItemChecker.checkAndCorrect(assessmentItem); + Assert.assertTrue(ok); + + TemplateDeclaration solutionDeclaration = assessmentItem.getTemplateDeclaration(Identifier.assumedLegal("SOLUTION1")); + Assert.assertEquals(BaseType.FLOAT, solutionDeclaration.getBaseType()); + } + + @Test + public void checkAndCorrect_notTemplateDeclaration() throws URISyntaxException { + URL itemUrl = OnyxToAssessmentItemBuilderTest.class.getResource("resources/ims/template_image.xml"); + AssessmentItem assessmentItem = loadAssessmentItem(itemUrl); + boolean ok = AssessmentItemChecker.checkAndCorrect(assessmentItem); + Assert.assertTrue(ok); + + TemplateDeclaration templateDeclaration = assessmentItem.getTemplateDeclaration(Identifier.assumedLegal("SOLUTION1")); + Assert.assertNull(templateDeclaration); + } + + @Test + public void checkAndCorrect_hottextOpenOLAT() throws URISyntaxException { + URL itemUrl = OnyxToAssessmentItemBuilderTest.class.getResource("resources/openolat/hottext-score-all-11-4-0.xml"); + AssessmentItem assessmentItem = loadAssessmentItem(itemUrl); + boolean ok = AssessmentItemChecker.checkAndCorrect(assessmentItem); + Assert.assertTrue(ok); + + TemplateDeclaration templateDeclaration = assessmentItem.getTemplateDeclaration(Identifier.assumedLegal("SOLUTION1")); + Assert.assertNull(templateDeclaration); + } + + private AssessmentItem loadAssessmentItem(URL itemUrl) throws URISyntaxException { + QtiXmlReader qtiXmlReader = new QtiXmlReader(new JqtiExtensionManager()); + ResourceLocator fileResourceLocator = new PathResourceLocator(Paths.get(itemUrl.toURI())); + AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, fileResourceLocator); + ResolvedAssessmentItem item = assessmentObjectXmlLoader.loadAndResolveAssessmentItem(itemUrl.toURI()); + return item.getItemLookup().getRootNodeHolder().getRootNode(); + } + +} diff --git a/src/test/java/org/olat/ims/qti21/model/xml/Onyx38ToQtiWorksAssessementItemsTest.java b/src/test/java/org/olat/ims/qti21/model/xml/Onyx38ToQtiWorksAssessementItemsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..63618431bcb7e3fb63814fb248019f9645eb39e3 --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/Onyx38ToQtiWorksAssessementItemsTest.java @@ -0,0 +1,142 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.model.xml; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.Collection; +import java.util.UUID; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.FileUtils; +import org.olat.core.util.WebappHelper; +import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; +import org.xml.sax.SAXException; +import org.xml.sax.ext.DefaultHandler2; + +import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; +import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; +import uk.ac.ed.ph.jqtiplus.provision.BadResourceException; +import uk.ac.ed.ph.jqtiplus.reading.AssessmentObjectXmlLoader; +import uk.ac.ed.ph.jqtiplus.reading.QtiXmlReader; +import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; +import uk.ac.ed.ph.jqtiplus.validation.ItemValidationResult; +import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; + +/** + * Only to play with + * + * + * Initial date: 25.06.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@RunWith(Parameterized.class) +public class Onyx38ToQtiWorksAssessementItemsTest { + + private static final OLog log = Tracing.createLoggerFor(Onyx38ToQtiWorksAssessementItemsTest.class); + + @Parameters + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] { + { "Auswahlaufgabe_1509468352.xml" }, + { "Hotspotaufgabe_478898401.xml" }, + { "Task_1597435347.xml" }, + { "text-entry-b-3-8.xml" }, + { "extended-text-e-3-7.xml" }, + { "extended-text-b-3-7.xml" }, + { "extended-text-c-3-7.xml" }, + { "extended-text-3-7.xml" }, + { "text-entry-3-8.xml" }, + { "extended-text-d-3-7.xml" } + }); + } + + private String xmlFilename; + + public Onyx38ToQtiWorksAssessementItemsTest(String xmlFilename) { + this.xmlFilename = xmlFilename; + } + + @Test + public void fixItem() + throws IOException, XMLStreamException, SAXException, ParserConfigurationException, URISyntaxException { + URL xmlUrl = Onyx38ToQtiWorksAssessementItemsTest.class.getResource("resources/onyx/" + xmlFilename); + File xmlFile = new File(xmlUrl.toURI()); + File tmpDir = new File(WebappHelper.getTmpDir(), "onyx" + UUID.randomUUID()); + tmpDir.mkdirs(); + + File outputFile = new File(tmpDir, "text.xml"); + try(InputStream in = Files.newInputStream(xmlFile.toPath()); + Writer out = Files.newBufferedWriter(outputFile.toPath(), Charset.forName("UTF-8"))) { + XMLOutputFactory xof = XMLOutputFactory.newInstance(); + XMLStreamWriter xtw = xof.createXMLStreamWriter(out); + + SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); + DefaultHandler2 myHandler = new Onyx38ToQtiWorksHandler(xtw); + saxParser.setProperty("http://xml.org/sax/properties/lexical-handler", myHandler); + saxParser.parse(in, myHandler); + } catch(Exception e1) { + log.error("", e1); + throw e1; + } + + QtiXmlReader qtiXmlReader = new QtiXmlReader(new JqtiExtensionManager()); + ResourceLocator fileResourceLocator = new PathResourceLocator(outputFile.toPath()); + AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, fileResourceLocator); + ResolvedAssessmentItem resolvedAssessmentItem = assessmentObjectXmlLoader.loadAndResolveAssessmentItem(outputFile.toURI()); + Assert.assertNotNull(resolvedAssessmentItem); + AssessmentItem assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful(); + + + // validation is only + ItemValidationResult itemResult = assessmentObjectXmlLoader.loadResolveAndValidateItem(outputFile.toURI()); + BadResourceException e = itemResult.getResolvedAssessmentItem().getItemLookup().getBadResourceException(); + if(e != null) { + StringBuilder err = new StringBuilder(); + BadRessourceHelper.extractMessage(e, err); + log.error(err.toString()); + } + FileUtils.deleteDirsAndFiles(tmpDir.toPath()); + + Assert.assertNotNull(assessmentItem); + Assert.assertFalse(BadRessourceHelper.hasFatalErrors(e)); + } +} diff --git a/src/test/java/org/olat/ims/qti21/model/xml/OnyxToAssessmentItemBuilderTest.java b/src/test/java/org/olat/ims/qti21/model/xml/OnyxToAssessmentItemBuilderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6260a5385b845f0f2f5d18d689948b7d9d821491 --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/OnyxToAssessmentItemBuilderTest.java @@ -0,0 +1,100 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ims.qti21.model.xml; + +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Paths; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; +import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuilder.ScoreEvaluation; +import org.olat.ims.qti21.model.xml.interactions.SingleChoiceAssessmentItemBuilder; + +import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; +import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; +import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.SimpleChoice; +import uk.ac.ed.ph.jqtiplus.reading.AssessmentObjectXmlLoader; +import uk.ac.ed.ph.jqtiplus.reading.QtiXmlReader; +import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; +import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; +import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; + +/** + * + * Initial date: 29 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class OnyxToAssessmentItemBuilderTest { + + @Test + public void extractsingleChoiceWithFeedbacks() throws URISyntaxException { + URL itemUrl = OnyxToAssessmentItemBuilderTest.class.getResource("resources/onyx/single-choice-1-with-feedbacks_5-11.xml"); + AssessmentItem assessmentItem = loadAssessmentItem(itemUrl); + + QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); + SingleChoiceAssessmentItemBuilder itemBuilder = new SingleChoiceAssessmentItemBuilder(assessmentItem, qtiSerializer); + + //correct answer + List<SimpleChoice> choices = itemBuilder.getChoices(); + Assert.assertNotNull(choices); + SimpleChoice choice = choices.get(3); + Assert.assertTrue(itemBuilder.isCorrect(choice)); + + //scoring + Assert.assertEquals(ScoreEvaluation.allCorrectAnswers, itemBuilder.getScoreEvaluationMode()); + ScoreBuilder maxScoreBuilder = itemBuilder.getMaxScoreBuilder(); + Assert.assertEquals(4.0d, maxScoreBuilder.getScore(), 0.00001d); + + // check standard feedback + ModalFeedbackBuilder correctFeedback = itemBuilder.getCorrectFeedback(); + Assert.assertNotNull(correctFeedback); + Assert.assertTrue(correctFeedback.isCorrectRule()); + Assert.assertEquals("<p>Richtig Text</p>", correctFeedback.getText()); + + ModalFeedbackBuilder incorrectFeedback = itemBuilder.getIncorrectFeedback(); + Assert.assertNotNull(incorrectFeedback); + Assert.assertTrue(incorrectFeedback.isIncorrectRule()); + Assert.assertEquals("<p>Falsch Text</p>", incorrectFeedback.getText()); + } + + @Test + public void extractSingleChoiceWithExpertConditionFeedbacks() throws URISyntaxException { + URL itemUrl = OnyxToAssessmentItemBuilderTest.class.getResource("resources/onyx/sc-expert-conditions-feedback.xml"); + AssessmentItem assessmentItem = loadAssessmentItem(itemUrl); + + QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); + SingleChoiceAssessmentItemBuilder itemBuilder = new SingleChoiceAssessmentItemBuilder(assessmentItem, qtiSerializer); + List<ModalFeedbackBuilder> feedbackBuilders = itemBuilder.getAdditionalFeedbackBuilders(); + System.out.println(feedbackBuilders); + } + + private AssessmentItem loadAssessmentItem(URL itemUrl) throws URISyntaxException { + QtiXmlReader qtiXmlReader = new QtiXmlReader(new JqtiExtensionManager()); + ResourceLocator fileResourceLocator = new PathResourceLocator(Paths.get(itemUrl.toURI())); + AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, fileResourceLocator); + ResolvedAssessmentItem item = assessmentObjectXmlLoader.loadAndResolveAssessmentItem(itemUrl.toURI()); + return item.getItemLookup().getRootNodeHolder().getRootNode(); + } + +} diff --git a/src/test/java/org/olat/ims/qti21/model/xml/OnyxToQtiWorksAssessementItemsTest.java b/src/test/java/org/olat/ims/qti21/model/xml/OnyxToQtiWorksAssessementItemsTest.java index 4f717dacfc0ecf0cfebd99ad082bda686d69a888..2a61e7d11c369647ead29983f7da7f2578816d18 100644 --- a/src/test/java/org/olat/ims/qti21/model/xml/OnyxToQtiWorksAssessementItemsTest.java +++ b/src/test/java/org/olat/ims/qti21/model/xml/OnyxToQtiWorksAssessementItemsTest.java @@ -76,24 +76,17 @@ public class OnyxToQtiWorksAssessementItemsTest { @Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][] { - { "Auswahlaufgabe_1509468352.xml" }, - { "Hotspotaufgabe_478898401.xml" }, - { "Task_1597435347.xml" }, - { "text-entry-b-3-8.xml" }, - { "extended-text-e-3.7.xml" }, - { "extended-text-b-3-7.xml" }, - { "extended-text-c-3-7.xml" }, - { "extended-text-3-7.xml" }, - { "text-entry-3-8.xml" }, - { "extended-text-d-3-7.xml" } + { "match-with-latex-5-11.xml", new QTI21Infos() } }); } private String xmlFilename; + private QTI21Infos infos; - public OnyxToQtiWorksAssessementItemsTest(String xmlFilename) { - this.xmlFilename = xmlFilename; - } + public OnyxToQtiWorksAssessementItemsTest(String xmlFilename, QTI21Infos infos) { + this.xmlFilename = xmlFilename; + this.infos = infos; + } @Test public void fixItem() @@ -110,7 +103,7 @@ public class OnyxToQtiWorksAssessementItemsTest { XMLStreamWriter xtw = xof.createXMLStreamWriter(out); SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); - DefaultHandler2 myHandler = new Onyx38ToQtiWorksHandler(xtw); + DefaultHandler2 myHandler = new OnyxToQtiWorksHandler(xtw, infos); saxParser.setProperty("http://xml.org/sax/properties/lexical-handler", myHandler); saxParser.parse(in, myHandler); } catch(Exception e1) { @@ -124,8 +117,7 @@ public class OnyxToQtiWorksAssessementItemsTest { ResolvedAssessmentItem resolvedAssessmentItem = assessmentObjectXmlLoader.loadAndResolveAssessmentItem(outputFile.toURI()); Assert.assertNotNull(resolvedAssessmentItem); AssessmentItem assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful(); - - + // validation is only ItemValidationResult itemResult = assessmentObjectXmlLoader.loadResolveAndValidateItem(outputFile.toURI()); BadResourceException e = itemResult.getResolvedAssessmentItem().getItemLookup().getBadResourceException(); diff --git a/src/test/java/org/olat/ims/qti21/model/xml/QTI21ExplorerHandlerTest.java b/src/test/java/org/olat/ims/qti21/model/xml/QTI21ExplorerHandlerTest.java index eb428955898bc4d5035383a9a3dfcbcdc08f409a..068bad69e69bf481f39e7f6bc9f77541232ab04e 100644 --- a/src/test/java/org/olat/ims/qti21/model/xml/QTI21ExplorerHandlerTest.java +++ b/src/test/java/org/olat/ims/qti21/model/xml/QTI21ExplorerHandlerTest.java @@ -56,8 +56,9 @@ public class QTI21ExplorerHandlerTest { { "resources/onyx/extended-text-3-7.xml", "Onyx Editor", "3.7.2" }, { "resources/onyx/extended-text-b-3-7.xml", "Onyx Editor", "3.7.2" }, { "resources/onyx/extended-text-c-3-7.xml", "Onyx Editor", "3.7.2" }, - { "resources/onyx/extended-text-e-3.7.xml", "Onyx Editor", "3.7.2" }, + { "resources/onyx/extended-text-e-3-7.xml", "Onyx Editor", "3.7.2" }, { "resources/onyx/imsmanifest-5-1.xml", "ONYX Editor", "5.10.3" }, + { "resources/onyx/imsmanifest-test-5-11.xml", "ONYX Editor", "5.11.1a" }, { "resources/openolat/essay3c2454b4c4dbd64347ea9df54cd.xml", "OpenOLAT", "11.3a" }, { "resources/openolat/multiple-choice-score-all-11-2-3.xml", "OpenOLAT", "11.2.2" } }); @@ -75,7 +76,7 @@ public class QTI21ExplorerHandlerTest { @Test public void exploreAndGetInfos() throws Exception { - URL xmlUrl = OnyxToQtiWorksAssessementItemsTest.class.getResource(xmlFilename); + URL xmlUrl = QTI21ExplorerHandlerTest.class.getResource(xmlFilename); File xmlFile = new File(xmlUrl.toURI()); try(InputStream in = Files.newInputStream(xmlFile.toPath())) { SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); diff --git a/src/test/java/org/olat/ims/qti21/model/xml/SingleChoiceAssessmentItemBuilderTest.java b/src/test/java/org/olat/ims/qti21/model/xml/SingleChoiceAssessmentItemBuilderTest.java index 5ab1e0b0f9a42375bf48afbb932fbd6e7f593a88..b44041ecfef1cde6b5e6d379255e6c0b56f98d7a 100644 --- a/src/test/java/org/olat/ims/qti21/model/xml/SingleChoiceAssessmentItemBuilderTest.java +++ b/src/test/java/org/olat/ims/qti21/model/xml/SingleChoiceAssessmentItemBuilderTest.java @@ -19,15 +19,26 @@ */ package org.olat.ims.qti21.model.xml; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.UUID; import org.junit.Assert; import org.junit.Test; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.FileUtils; +import org.olat.core.util.WebappHelper; import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; +import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuilder.ScoreEvaluation; import org.olat.ims.qti21.model.xml.interactions.SingleChoiceAssessmentItemBuilder; @@ -39,8 +50,13 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.SimpleChoice; import uk.ac.ed.ph.jqtiplus.reading.AssessmentObjectXmlLoader; import uk.ac.ed.ph.jqtiplus.reading.QtiXmlReader; import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; +import uk.ac.ed.ph.jqtiplus.running.ItemSessionController; import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; import uk.ac.ed.ph.jqtiplus.types.Identifier; +import uk.ac.ed.ph.jqtiplus.types.ResponseData; +import uk.ac.ed.ph.jqtiplus.types.StringResponseData; +import uk.ac.ed.ph.jqtiplus.value.FloatValue; +import uk.ac.ed.ph.jqtiplus.value.Value; import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; /** @@ -51,6 +67,8 @@ import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; */ public class SingleChoiceAssessmentItemBuilderTest { + private static final OLog log = Tracing.createLoggerFor(SingleChoiceAssessmentItemBuilderTest.class); + /** * Check if a bare bone multiple choice created with our builder make a valid assessmentItem. * @@ -92,6 +110,55 @@ public class SingleChoiceAssessmentItemBuilderTest { Assert.assertEquals(ScoreEvaluation.allCorrectAnswers, itemBuilder.getScoreEvaluationMode()); } + @Test + public void createSingleAssessmentItem_allCorrectAnswers() throws IOException { + QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); + SingleChoiceAssessmentItemBuilder itemBuilder = new SingleChoiceAssessmentItemBuilder("Single choice", "Single choice", qtiSerializer); + itemBuilder.setQuestion("<p>Hello</p>"); + + ChoiceInteraction interaction = itemBuilder.getChoiceInteraction(); + SimpleChoice choice1 = AssessmentItemFactory.createSimpleChoice(interaction, "One", "sc"); + SimpleChoice choice2 = AssessmentItemFactory.createSimpleChoice(interaction, "Two", "sc"); + SimpleChoice choice3 = AssessmentItemFactory.createSimpleChoice(interaction, "Three", "sc"); + + List<SimpleChoice> choiceList = new ArrayList<>(); + choiceList.add(choice1); + choiceList.add(choice2); + choiceList.add(choice3); + itemBuilder.setSimpleChoices(choiceList); + itemBuilder.setCorrectAnswer(choice2.getIdentifier()); + itemBuilder.setMaxScore(3.0d); + itemBuilder.setScoreEvaluationMode(ScoreEvaluation.allCorrectAnswers); + itemBuilder.build(); + + File itemFile = new File(WebappHelper.getTmpDir(), "scAssessmentItem" + UUID.randomUUID() + ".xml"); + try(FileOutputStream out = new FileOutputStream(itemFile)) { + qtiSerializer.serializeJqtiObject(itemBuilder.getAssessmentItem(), out); + } catch(Exception e) { + log.error("", e); + } + + {// correct answers + Map<Identifier, ResponseData> responseMap = new HashMap<>(); + Identifier responseIdentifier = itemBuilder.getInteraction().getResponseIdentifier(); + responseMap.put(responseIdentifier, new StringResponseData(choice2.getIdentifier().toString())); + ItemSessionController itemSessionController = RunningItemHelper.run(itemFile, responseMap); + Value score = itemSessionController.getItemSessionState().getOutcomeValue(QTI21Constants.SCORE_IDENTIFIER); + Assert.assertEquals(new FloatValue(3.0d), score); + } + + {// wrong answer + Map<Identifier, ResponseData> responseMap = new HashMap<>(); + Identifier responseIdentifier = itemBuilder.getInteraction().getResponseIdentifier(); + responseMap.put(responseIdentifier, new StringResponseData(choice3.getIdentifier().toString())); + ItemSessionController itemSessionController = RunningItemHelper.run(itemFile, responseMap); + Value score = itemSessionController.getItemSessionState().getOutcomeValue(QTI21Constants.SCORE_IDENTIFIER); + Assert.assertEquals(new FloatValue(0.0d), score); + } + + FileUtils.deleteDirsAndFiles(itemFile.toPath()); + } + private AssessmentItem loadAssessmentItem(URL itemUrl) throws URISyntaxException { QtiXmlReader qtiXmlReader = new QtiXmlReader(new JqtiExtensionManager()); ResourceLocator fileResourceLocator = new PathResourceLocator(Paths.get(itemUrl.toURI())); diff --git a/src/test/java/org/olat/ims/qti21/model/xml/resources/ims/template_image.xml b/src/test/java/org/olat/ims/qti21/model/xml/resources/ims/template_image.xml new file mode 100644 index 0000000000000000000000000000000000000000..b8e7328d7494e131f1bfcb4a260bfb24391fd5d2 --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/resources/ims/template_image.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/imsqti_v2p1.xsd" + identifier="template" title="Transportation" adaptive="false" timeDependent="false"> + <!-- Thanks to Mark Stickley for the excellent images! --> + <responseDeclaration identifier="RESPONSE" cardinality="single" baseType="integer"/> + <outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"/> + <templateDeclaration identifier="TRANSPORT" cardinality="single" baseType="identifier" + mathVariable="false" paramVariable="false"/> + <templateDeclaration identifier="SPEED" cardinality="single" baseType="integer" + mathVariable="false" paramVariable="false"/> + <templateProcessing> + <setTemplateValue identifier="TRANSPORT"> + <random> + <multiple> + <baseValue baseType="identifier">plane</baseValue> + <baseValue baseType="identifier">train</baseValue> + <baseValue baseType="identifier">bus</baseValue> + </multiple> + </random> + </setTemplateValue> + <templateCondition> + <templateIf> + <match> + <variable identifier="TRANSPORT"/> + <baseValue baseType="identifier">plane</baseValue> + </match> + <setTemplateValue identifier="SPEED"> + <baseValue baseType="integer">600</baseValue> + </setTemplateValue> + </templateIf> + <templateElseIf> + <match> + <variable identifier="TRANSPORT"/> + <baseValue baseType="identifier">train</baseValue> + </match> + <setTemplateValue identifier="SPEED"> + <baseValue baseType="integer">200</baseValue> + </setTemplateValue> + </templateElseIf> + <templateElse> + <setTemplateValue identifier="SPEED"> + <baseValue baseType="integer">50</baseValue> + </setTemplateValue> + </templateElse> + </templateCondition> + <setCorrectResponse identifier="RESPONSE"> + <product> + <baseValue baseType="integer">3</baseValue> + <variable identifier="SPEED"/> + </product> + </setCorrectResponse> + </templateProcessing> + <itemBody> + <h1>Mick's Travels</h1> + <p> + <templateInline templateIdentifier="TRANSPORT" showHide="show" identifier="plane"> + <img src="images/plane.png" alt="Picture of a plane."/> + </templateInline> + <templateInline templateIdentifier="TRANSPORT" showHide="show" identifier="train"> + <img src="images/train.png" alt="Picture of a train"/> + </templateInline> + <templateInline templateIdentifier="TRANSPORT" showHide="show" identifier="bus"> + <img src="images/bus.png" alt="Picture of a bus"/> + </templateInline> + </p> + <p>Mick travels at an average speed of <printedVariable identifier="SPEED"/> km/h.</p> + <p>How far does he travel in 3 hours? <textEntryInteraction responseIdentifier="RESPONSE" + expectedLength="8"/> km.</p> + </itemBody> + <responseProcessing + template="http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct"/> +</assessmentItem> diff --git a/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/extended-text-e-3.7.xml b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/extended-text-e-3-7.xml similarity index 100% rename from src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/extended-text-e-3.7.xml rename to src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/extended-text-e-3-7.xml diff --git a/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/imsmanifest-test-5-11.xml b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/imsmanifest-test-5-11.xml new file mode 100644 index 0000000000000000000000000000000000000000..4f1d2db32b0cf2101375e6bbfe8551182c71edf3 --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/imsmanifest-test-5-11.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/qtiv2p1_imscpv1p2_v1p0.xsd http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/imsqti_v2p1p1.xsd http://www.imsglobal.org/xsd/imsqti_metadata_v2p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/imsqti_metadata_v2p1p1.xsd http://ltsc.ieee.org/xsd/LOM http://www.imsglobal.org/xsd/imsmd_loose_v1p3p2.xsd http://www.w3.org/1998/Math/MathML http://www.w3.org/Math/XMLSchema/mathml2/mathml2.xsd" identifier="NeuerTest_1020014589_manifest"><metadata ><schema>QTIv2.1 Package</schema><schemaversion>1.0.0</schemaversion></metadata><organizations /><resources ><resource identifier="NeuerTest_1020014589" type="imsqti_test_xmlv2p1" href="NeuerTest_1020014589.xml"><metadata><lom xmlns="http://ltsc.ieee.org/xsd/LOM"><general ><identifier><entry>NeuerTest_1020014589</entry></identifier><title><string language="de">SR Test</string></title><description><string language="de"><p>SR Test</p></string></description></general><lifeCycle ><contribute><date><dateTime>2017-09-04T20:38:40</dateTime></date><role><source>LOMv1.0</source><value>author</value></role><entity>BEGIN:VCARD
 +VERSION:4.0
 +N;LANGUAGE=de:Test;Onyx;;;
 +FN:Onyx Test
 +EMAIL:angela.peetz@onyxtest.de
 +PRODID:ONYX Editor 5.11.1a
 +END:VCARD
 +</entity></contribute></lifeCycle></lom></metadata><file href="NeuerTest_1020014589.xml" /><dependency identifierref="NeueAufgabe_1541658844" /><dependency identifierref="id399c345f_809f_4ba0_95ea_8108a7e2c9d4" /><dependency identifierref="idbb79de4d_62fc_4375_b595_fd60165edca0" /><dependency identifierref="idc3ce08e7_68e6_4668_80c7_e1bb6220668a" /></resource><resource identifier="NeueAufgabe_1541658844" type="imsqti_item_xmlv2p1" href="NeueAufgabe_1541658844.xml"><file href="NeueAufgabe_1541658844.xml" /></resource><resource identifier="id399c345f_809f_4ba0_95ea_8108a7e2c9d4" type="imsqti_item_xmlv2p1" href="id399c345f-809f-4ba0-95ea-8108a7e2c9d4.xml"><file href="id399c345f-809f-4ba0-95ea-8108a7e2c9d4.xml" /></resource><resource identifier="idbb79de4d_62fc_4375_b595_fd60165edca0" type="imsqti_item_xmlv2p1" href="idbb79de4d-62fc-4375-b595-fd60165edca0.xml"><file href="idbb79de4d-62fc-4375-b595-fd60165edca0.xml" /></resource><resource identifier="idc3ce08e7_68e6_4668_80c7_e1bb6220668a" type="imsqti_item_xmlv2p1" href="idc3ce08e7-68e6-4668-80c7-e1bb6220668a.xml"><file href="idc3ce08e7-68e6-4668-80c7-e1bb6220668a.xml" /></resource></resources></manifest> diff --git a/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/match-with-latex-5-11.xml b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/match-with-latex-5-11.xml new file mode 100644 index 0000000000000000000000000000000000000000..b688098fe529de8ae110ce612486604601576121 --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/match-with-latex-5-11.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/imsqti_v2p1p1.xsd" identifier="SynchronisationvonTransitionssystemen3_1306159582" title="0205 Synchronisation von Transitionssystemen (3)" adaptive="false" timeDependent="false"><responseDeclaration identifier="RESPONSE_1" cardinality="multiple" baseType="directedPair"><correctResponse><value>idbebf321a-7acd-4e07-a114-df5e9b790ea3 id186a2c19-4bd8-4c24-8011-26e88e3f96f9</value><value>id1f7d62a0-6e6b-40b2-a2a1-77db3f036320 id112ea72d-ad0c-4378-8ea0-ee8379299749</value><value>id7ad332b2-b5c4-42aa-9173-03dda7e10d44 id94c4451b-5c94-49bc-bbe6-a15cda1de518</value></correctResponse></responseDeclaration><outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"><defaultValue><value>0</value></defaultValue></outcomeDeclaration><outcomeDeclaration identifier="MAXSCORE" cardinality="single" baseType="float"><defaultValue><value>1</value></defaultValue></outcomeDeclaration><outcomeDeclaration identifier="FEEDBACKBASIC" cardinality="single" baseType="identifier"><defaultValue><value>empty</value></defaultValue></outcomeDeclaration><itemBody ><p>Die Transitionsrelation \( tr_3 \) eines Produkttransitionssystems wird durch die Regeln \( Sy1 \), \( Sy2 \), \( Sy3 \) definiert. Ordnen Sie der jeweiligen Prämisse die richtige Konklusion zu.</p><matchInteraction responseIdentifier="RESPONSE_1" shuffle="true" maxAssociations="0"><simpleMatchSet><simpleAssociableChoice identifier="idbebf321a-7acd-4e07-a114-df5e9b790ea3" fixed="false" matchMax="1"><p>\( s_1 \overset{a_1}{\rightarrow}_1 s_2, \quad a_1 \notin pr_1(Sync), \quad r \in S_2 \)</p></simpleAssociableChoice><simpleAssociableChoice identifier="id1f7d62a0-6e6b-40b2-a2a1-77db3f036320" fixed="false" matchMax="1"><p>\( r_1 \overset{a_2}{\rightarrow}_2 r_2, \quad a_2 \notin pr_2(Sync), \quad s \in S_1 \)</p></simpleAssociableChoice><simpleAssociableChoice identifier="id7ad332b2-b5c4-42aa-9173-03dda7e10d44" fixed="false" matchMax="1"><p>\( s_1 \overset{a_1}{\rightarrow}_1 s_2, \quad r_1 \overset{a_2}{\rightarrow}_2 r_2, \quad (a_1,a_2) \in Sync \)</p></simpleAssociableChoice></simpleMatchSet><simpleMatchSet><simpleAssociableChoice identifier="id186a2c19-4bd8-4c24-8011-26e88e3f96f9" fixed="false" matchMax="1"><p>\( (s_1,r) \overset{a_1}{\rightarrow}_3 (s_2,r) \)</p></simpleAssociableChoice><simpleAssociableChoice identifier="id112ea72d-ad0c-4378-8ea0-ee8379299749" fixed="false" matchMax="1"><p>\( (s,r_1) \overset{a_2}{\rightarrow}_3 (s,r_2) \)</p></simpleAssociableChoice><simpleAssociableChoice identifier="id94c4451b-5c94-49bc-bbe6-a15cda1de518" fixed="false" matchMax="1"><p>\( (s_1,r_1) \overset{(a_1,a_2)}{\rightarrow}_3 (s_2,r_2) \)</p></simpleAssociableChoice></simpleMatchSet></matchInteraction></itemBody><responseProcessing><responseCondition><responseIf><isNull><variable identifier="RESPONSE_1" /></isNull><setOutcomeValue identifier="FEEDBACKBASIC"><baseValue baseType="identifier">empty</baseValue></setOutcomeValue></responseIf><responseElseIf><match><variable identifier="RESPONSE_1" /><correct identifier="RESPONSE_1" /></match><setOutcomeValue identifier="SCORE"><sum><variable identifier="SCORE" /><variable identifier="MAXSCORE" /></sum></setOutcomeValue><setOutcomeValue identifier="FEEDBACKBASIC"><baseValue baseType="identifier">correct</baseValue></setOutcomeValue></responseElseIf><responseElse><setOutcomeValue identifier="FEEDBACKBASIC"><baseValue baseType="identifier">incorrect</baseValue></setOutcomeValue></responseElse></responseCondition></responseProcessing></assessmentItem> diff --git a/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/sc-expert-conditions-feedback.xml b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/sc-expert-conditions-feedback.xml new file mode 100644 index 0000000000000000000000000000000000000000..5100b565decfaa6f987c70daaf79efbf73b70fb0 --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/sc-expert-conditions-feedback.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/imsqti_v2p1p1.xsd http://www.w3.org/1998/Math/MathML http://www.w3.org/Math/XMLSchema/mathml2/mathml2.xsd" identifier="id4b021217-8b36-48c2-be1a-e34db042360c" title="New question" adaptive="false" timeDependent="false"><responseDeclaration identifier="RESPONSE_1" cardinality="single" baseType="identifier"><correctResponse><value>idde2a6e88-a36c-4f64-90f5-e70b7f04ae40</value></correctResponse></responseDeclaration><outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"><defaultValue><value>0</value></defaultValue></outcomeDeclaration><outcomeDeclaration identifier="MAXSCORE" cardinality="single" baseType="float"><defaultValue><value>1</value></defaultValue></outcomeDeclaration><outcomeDeclaration identifier="FEEDBACKBASIC" cardinality="single" baseType="identifier"><defaultValue><value>empty</value></defaultValue></outcomeDeclaration><outcomeDeclaration identifier="MINSCORE" cardinality="single" baseType="float" view="testConstructor"><defaultValue><value>0</value></defaultValue></outcomeDeclaration><outcomeDeclaration identifier="FEEDBACKMODAL" cardinality="multiple" baseType="identifier" view="testConstructor" /><templateDeclaration identifier="testVar" cardinality="single" baseType="integer" /><templateProcessing><setTemplateValue identifier="testVar"><randomInteger min="1" max="15" /></setTemplateValue></templateProcessing><itemBody ><choiceInteraction responseIdentifier="RESPONSE_1" shuffle="true" maxChoices="1"><simpleChoice identifier="idde2a6e88-a36c-4f64-90f5-e70b7f04ae40"><p>New answer</p></simpleChoice></choiceInteraction></itemBody><responseProcessing><responseCondition><responseIf><isNull><variable identifier="RESPONSE_1" /></isNull><setOutcomeValue identifier="FEEDBACKBASIC"><baseValue baseType="identifier">empty</baseValue></setOutcomeValue></responseIf><responseElseIf><match><variable identifier="RESPONSE_1" /><correct identifier="RESPONSE_1" /></match><setOutcomeValue identifier="SCORE"><sum><variable identifier="SCORE" /><variable identifier="MAXSCORE" /></sum></setOutcomeValue><setOutcomeValue identifier="FEEDBACKBASIC"><baseValue baseType="identifier">correct</baseValue></setOutcomeValue></responseElseIf><responseElse><setOutcomeValue identifier="FEEDBACKBASIC"><baseValue baseType="identifier">incorrect</baseValue></setOutcomeValue></responseElse></responseCondition><responseCondition><responseIf><and><gt><variable identifier="SCORE" /><baseValue baseType="float">0</baseValue></gt><equal toleranceMode="exact"><variable identifier="numAttempts" /><baseValue baseType="integer">0</baseValue></equal><match><baseValue baseType="identifier">idde2a6e88-a36c-4f64-90f5-e70b7f04ae40</baseValue><variable identifier="RESPONSE_1" /></match><not><match><baseValue baseType="identifier">idde2a6e88-a36c-4f64-90f5-e70b7f04ae40</baseValue><variable identifier="RESPONSE_1" /></match></not></and><setOutcomeValue identifier="FEEDBACKMODAL"><multiple><variable identifier="FEEDBACKMODAL" /><baseValue baseType="identifier">Feedback12912883</baseValue></multiple></setOutcomeValue></responseIf></responseCondition><responseCondition><responseIf><gt><variable identifier="SCORE" /><variable identifier="MAXSCORE" /></gt><setOutcomeValue identifier="SCORE"><variable identifier="MAXSCORE" /></setOutcomeValue></responseIf></responseCondition><responseCondition><responseIf><lt><variable identifier="SCORE" /><variable identifier="MINSCORE" /></lt><setOutcomeValue identifier="SCORE"><variable identifier="MINSCORE" /></setOutcomeValue></responseIf></responseCondition></responseProcessing><modalFeedback identifier="Feedback12912883" outcomeIdentifier="FEEDBACKMODAL" showHide="show" title="Attempts 1"><p>Attempts 1 feedback</p></modalFeedback></assessmentItem> diff --git a/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/set-correct-response-wrong-type-5-11.xml b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/set-correct-response-wrong-type-5-11.xml new file mode 100644 index 0000000000000000000000000000000000000000..a708a8886a9f9708d7d828633e68ee29dad77820 --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/set-correct-response-wrong-type-5-11.xml @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="UTF-8"?> +<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/imsqti_v2p1p1.xsd http://www.w3.org/1998/Math/MathML http://www.w3.org/Math/XMLSchema/mathml2/mathml2.xsd" identifier="idbad91fb5-fe3f-4adf-a0a7-088a7d0bad73" title="XML-Berechnung-ONYX" adaptive="false" timeDependent="false"> + <responseDeclaration identifier="RESPONSE" cardinality="single" baseType="float"> + <correctResponse> + <value> + 0 + </value> + </correctResponse> + </responseDeclaration> + <outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"> + <defaultValue> + <value> + 0 + </value> + </defaultValue> + </outcomeDeclaration> + <outcomeDeclaration identifier="MAXSCORE" cardinality="single" baseType="float"> + <defaultValue> + <value> + 1 + </value> + </defaultValue> + </outcomeDeclaration> + <outcomeDeclaration identifier="FEEDBACKBASIC" cardinality="single" baseType="identifier" view="testConstructor"> + <defaultValue> + <value> + empty + </value> + </defaultValue> + </outcomeDeclaration> + <outcomeDeclaration identifier="FEEDBACKMODAL" cardinality="multiple" baseType="identifier" view="testConstructor" /> + <templateDeclaration identifier="var1" cardinality="single" baseType="integer" /> + <templateDeclaration identifier="var2" cardinality="single" baseType="integer" /> + <templateDeclaration identifier="solution" cardinality="single" baseType="integer" /> + <templateProcessing> + <setTemplateValue identifier="var1"> + <randomInteger min="1" max="10" /> + </setTemplateValue> + <setTemplateValue identifier="var2"> + <randomInteger min="1" max="10" /> + </setTemplateValue> + <setTemplateValue identifier="solution"> + <customOperator definition="MAXIMA" value="float($(1)+$(2));"> + <variable identifier="var1" /><variable identifier="var2" /> + </customOperator> + </setTemplateValue> + <setCorrectResponse identifier="RESPONSE"> + <variable identifier="solution" /> + </setCorrectResponse> + </templateProcessing> + <itemBody> + <p> + Berechnen Sie: 4+5 = <textEntryInteraction responseIdentifier="RESPONSE" /> + </p> + </itemBody> + <responseProcessing> + <responseCondition> + <responseIf> + <equal toleranceMode="exact"> + <variable identifier="RESPONSE" /><correct identifier="RESPONSE" /> + </equal> + <setOutcomeValue identifier="SCORE"> + <sum> + <variable identifier="SCORE" /> + <baseValue baseType="float"> + 1 + </baseValue> + </sum> + </setOutcomeValue> + </responseIf> + </responseCondition> + <responseCondition> + <responseIf> + <not> + <isNull> + <variable identifier="RESPONSE" /> + </isNull> + </not> + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier"> + incorrect + </baseValue> + </setOutcomeValue> + </responseIf> + </responseCondition> + <responseCondition> + <responseIf> + <and> + <not> + <match> + <variable identifier="FEEDBACKBASIC" /> + <baseValue baseType="identifier"> + empty + </baseValue> + </match> + </not> + <equal toleranceMode="exact"> + <variable identifier="SCORE" /><variable identifier="MAXSCORE" /> + </equal> + </and> + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier"> + correct + </baseValue> + </setOutcomeValue> + </responseIf> + </responseCondition> + <responseCondition> + <responseIf> + <and> + <match> + <baseValue baseType="identifier"> + correct + </baseValue> + <variable identifier="FEEDBACKBASIC" /> + </match> + </and> + <setOutcomeValue identifier="FEEDBACKMODAL"> + <multiple> + <variable identifier="FEEDBACKMODAL" /> + <baseValue baseType="identifier"> + Feedback1365540989 + </baseValue> + </multiple> + </setOutcomeValue> + </responseIf> + </responseCondition> + <responseCondition> + <responseIf> + <and> + <match> + <baseValue baseType="identifier"> + incorrect + </baseValue> + <variable identifier="FEEDBACKBASIC" /> + </match> + </and> + <setOutcomeValue identifier="FEEDBACKMODAL"> + <multiple> + <variable identifier="FEEDBACKMODAL" /> + <baseValue baseType="identifier"> + Feedback1212849391 + </baseValue> + </multiple> + </setOutcomeValue> + </responseIf> + </responseCondition> + </responseProcessing> + <modalFeedback identifier="Feedback1365540989" outcomeIdentifier="FEEDBACKMODAL" showHide="show"> + <p> + Winner + </p> + </modalFeedback> + <modalFeedback identifier="Feedback1212849391" outcomeIdentifier="FEEDBACKMODAL" showHide="show"> + <p> + Looser + </p> + </modalFeedback> +</assessmentItem> diff --git a/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/single-choice-1-with-feedbacks_5-11.xml b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/single-choice-1-with-feedbacks_5-11.xml new file mode 100644 index 0000000000000000000000000000000000000000..ca347ec4a52a2059981035b26c416e8616be1eff --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/resources/onyx/single-choice-1-with-feedbacks_5-11.xml @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="UTF-8"?> +<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/imsqti_v2p1p1.xsd http://www.w3.org/1998/Math/MathML http://www.w3.org/Math/XMLSchema/mathml2/mathml2.xsd" + identifier="id7b3114b3-7b0f-411c-a69e-7243deac0d45" title="Knoten_SC_1" + adaptive="false" timeDependent="false"> + <responseDeclaration identifier="RESPONSE_1" + cardinality="single" baseType="identifier"> + <correctResponse> + <value>idd2ea93f6-3fdd-4308-a7ba-494477fe86f3</value> + </correctResponse> + </responseDeclaration> + <outcomeDeclaration identifier="SCORE" cardinality="single" + baseType="float"> + <defaultValue> + <value>0</value> + </defaultValue> + </outcomeDeclaration> + <outcomeDeclaration identifier="MAXSCORE" + cardinality="single" baseType="float"> + <defaultValue> + <value>4</value> + </defaultValue> + </outcomeDeclaration> + <outcomeDeclaration identifier="FEEDBACKBASIC" + cardinality="single" baseType="identifier"> + <defaultValue> + <value>empty</value> + </defaultValue> + </outcomeDeclaration> + <outcomeDeclaration identifier="FEEDBACKMODAL" + cardinality="multiple" baseType="identifier" view="testConstructor" /> + <itemBody> + <p>Aufgabenstellung - 4 Punkte</p> + <p> + <strong>Fett-Formatiert</strong> + </p> + <p> + <em>Kursiv Formatiert</em> + </p> + <choiceInteraction responseIdentifier="RESPONSE_1" + shuffle="true" maxChoices="1"> + <simpleChoice identifier="idc04c4c0d-5637-41e6-b49c-b915e4061f75"> + <p>Antwort 1 - falsch</p> + </simpleChoice> + <simpleChoice identifier="id941faa89-34ba-47cd-9565-5d17856327c3"> + <p>Antwort 2 - auch falsch</p> + </simpleChoice> + <simpleChoice identifier="iddcb9cdcf-cba4-4bba-b4a1-cc304b733e60"> + <p>Antwort 3 - aber so richtig falsch!</p> + </simpleChoice> + <simpleChoice identifier="idd2ea93f6-3fdd-4308-a7ba-494477fe86f3"> + <p>Antwort 4 - der hier ist richtig. ...vielleicht.</p> + </simpleChoice> + </choiceInteraction> + </itemBody> + <responseProcessing> + <responseCondition> + <responseIf> + <isNull> + <variable identifier="RESPONSE_1" /> + </isNull> + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier">empty</baseValue> + </setOutcomeValue> + </responseIf> + <responseElseIf> + <match> + <variable identifier="RESPONSE_1" /> + <correct identifier="RESPONSE_1" /> + </match> + <setOutcomeValue identifier="SCORE"> + <sum> + <variable identifier="SCORE" /> + <variable identifier="MAXSCORE" /> + </sum> + </setOutcomeValue> + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier">correct</baseValue> + </setOutcomeValue> + </responseElseIf> + <responseElse> + <setOutcomeValue identifier="FEEDBACKBASIC"> + <baseValue baseType="identifier">incorrect</baseValue> + </setOutcomeValue> + </responseElse> + </responseCondition> + <responseCondition> + <responseIf> + <and> + <match> + <baseValue baseType="identifier">correct</baseValue> + <variable identifier="FEEDBACKBASIC" /> + </match> + </and> + <setOutcomeValue identifier="FEEDBACKMODAL"> + <multiple> + <variable identifier="FEEDBACKMODAL" /> + <baseValue baseType="identifier">Feedback387304179</baseValue> + </multiple> + </setOutcomeValue> + </responseIf> + </responseCondition> + <responseCondition> + <responseIf> + <and> + <match> + <baseValue baseType="identifier">incorrect</baseValue> + <variable identifier="FEEDBACKBASIC" /> + </match> + </and> + <setOutcomeValue identifier="FEEDBACKMODAL"> + <multiple> + <variable identifier="FEEDBACKMODAL" /> + <baseValue baseType="identifier">Feedback1195493580</baseValue> + </multiple> + </setOutcomeValue> + </responseIf> + </responseCondition> + </responseProcessing> + <modalFeedback identifier="Feedback387304179" + outcomeIdentifier="FEEDBACKMODAL" showHide="show" title="Feedback - Richtig"> + <p>Richtig Text</p> + </modalFeedback> + <modalFeedback identifier="Feedback1195493580" + outcomeIdentifier="FEEDBACKMODAL" showHide="show" title="Feedback - Falsch"> + <p>Falsch Text</p> + </modalFeedback> +</assessmentItem> diff --git a/src/test/java/org/olat/ims/qti21/model/xml/resources/umpc/addition.xml b/src/test/java/org/olat/ims/qti21/model/xml/resources/umpc/addition.xml new file mode 100644 index 0000000000000000000000000000000000000000..93061c0885595194d30ec5bb9e7ef3bafa7bcce3 --- /dev/null +++ b/src/test/java/org/olat/ims/qti21/model/xml/resources/umpc/addition.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1" +xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/imsqti_v2p1.xsd" +xmlns:m="http://www.w3.org/1998/Math/MathML" +identifier="Template_FIB_001" +title="addition of floating numbers" +adaptive="false" +timeDependent="false"> + +<responseDeclaration identifier="REPONSE1" cardinality="single" baseType="float" /> + +<outcomeDeclaration identifier="FEEDBACK" cardinality="single" baseType="identifier" /> +<outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float" /> + +<templateDeclaration identifier="a" cardinality="single" baseType="float" mathVariable="true" paramVariable="true" /> + +<templateDeclaration identifier="b" cardinality="single" baseType="float" mathVariable="true" paramVariable="true" /> + +<templateDeclaration identifier="SOLUTION1" cardinality="single" baseType="float" mathVariable="true" paramVariable="true" /> + +<templateProcessing> + +<setTemplateValue identifier="a"><divide><truncate><product><randomFloat min="0.0" max="100.0" /><baseValue baseType="integer">100</baseValue></product></truncate><baseValue baseType="integer">100</baseValue></divide></setTemplateValue> +<setTemplateValue identifier="b"><divide><truncate><product><randomFloat min="0.0" max="100.0" /><baseValue baseType="integer">100</baseValue></product></truncate><baseValue baseType="integer">100</baseValue></divide></setTemplateValue> + +<setTemplateValue identifier="SOLUTION1"><divide><round><product><sum><variable identifier="a" /><variable identifier="b" /></sum><baseValue baseType="integer">100</baseValue></product></round><baseValue baseType="integer">100</baseValue></divide></setTemplateValue> + + +<setCorrectResponse identifier="REPONSE1"><variable identifier="SOLUTION1" /></setCorrectResponse> + +</templateProcessing> +<itemBody><div> +<em> + +</em> +<em> + +</em> +Compute: +<m:math><m:mrow><m:mi>a</m:mi><m:mo>+</m:mo><m:mi>b</m:mi></m:mrow><m:mo>=</m:mo></m:math><textEntryInteraction responseIdentifier="REPONSE1" expectedLength="5" /><m:math></m:math> + +</div></itemBody> + +<responseProcessing> +<responseCondition> +<responseIf> +<and> +<equalRounded roundingMode="decimalPlaces" figures="2"><variable identifier="REPONSE1" /><correct identifier="REPONSE1" /> +</equalRounded> +</and> +<setOutcomeValue identifier="FEEDBACK"><baseValue baseType="identifier">_1V</baseValue></setOutcomeValue> +<setOutcomeValue identifier="SCORE"><baseValue baseType="float">10</baseValue></setOutcomeValue> +</responseIf> +<responseElse> +<setOutcomeValue identifier="FEEDBACK"><baseValue baseType="identifier">_0</baseValue></setOutcomeValue> +<setOutcomeValue identifier="SCORE"><baseValue baseType="float">0</baseValue></setOutcomeValue> +</responseElse> +</responseCondition> +</responseProcessing> + +<modalFeedback outcomeIdentifier="FEEDBACK" identifier="_1V" showHide="show"> +Good answer.<br/>Compute: +<m:math><m:mrow><m:mi>a</m:mi><m:mo>+</m:mo><m:mi>b</m:mi></m:mrow><m:mo>=</m:mo><m:mi>SOLUTION1</m:mi></m:math> + +</modalFeedback> +<modalFeedback outcomeIdentifier="FEEDBACK" identifier="_0" showHide="show"> +It is wrong.<br/>Compute: +<m:math><m:mrow><m:mi>a</m:mi><m:mo>+</m:mo><m:mi>b</m:mi></m:mrow><m:mo>=</m:mo><m:mi>SOLUTION1</m:mi></m:math> + +</modalFeedback> +</assessmentItem> diff --git a/src/test/java/org/olat/ims/qti21/pool/QTI12To21ConverterTest.java b/src/test/java/org/olat/ims/qti21/pool/QTI12To21ConverterTest.java index 14bee49afe2988f2082eadf818e3e367e08a2eee..3cf515216f8db87f2b8d6320938b0c907cf3bd09 100644 --- a/src/test/java/org/olat/ims/qti21/pool/QTI12To21ConverterTest.java +++ b/src/test/java/org/olat/ims/qti21/pool/QTI12To21ConverterTest.java @@ -71,7 +71,7 @@ public class QTI12To21ConverterTest { exportDir.mkdirs(); QTI12To21Converter converter = new QTI12To21Converter(exportDir, Locale.ENGLISH); - converter.convert(null, doc); + converter.convert(null, doc, null); int validAssessmentItems = 0; boolean validAssessmentTest = false; diff --git a/src/test/java/org/olat/modules/assessment/manager/AssessmentEntryDAOTest.java b/src/test/java/org/olat/modules/assessment/manager/AssessmentEntryDAOTest.java index 6957815923569a03be5dcc57d7b480b55436f3a1..fc20ce32f2f0710f82ccdebcb4e7102a6f2cedb6 100644 --- a/src/test/java/org/olat/modules/assessment/manager/AssessmentEntryDAOTest.java +++ b/src/test/java/org/olat/modules/assessment/manager/AssessmentEntryDAOTest.java @@ -174,7 +174,7 @@ public class AssessmentEntryDAOTest extends OlatTestCase { RepositoryEntry refEntry = JunitTestHelper.createAndPersistRepositoryEntry(); String subIdent = UUID.randomUUID().toString(); AssessmentEntry nodeAssessmentRef = assessmentEntryDao - .createAssessmentEntry(assessedIdentity, null, entry, subIdent, refEntry, 2.0f, Boolean.TRUE); + .createAssessmentEntry(assessedIdentity, null, entry, subIdent, refEntry, 2.0f, Boolean.TRUE, null, null); dbInstance.commitAndCloseSession(); AssessmentEntry resetedAssessmentRef = assessmentEntryDao @@ -210,11 +210,11 @@ public class AssessmentEntryDAOTest extends OlatTestCase { AssessmentEntry nodeAssessmentId1 = assessmentEntryDao .createAssessmentEntry(assessedIdentity1, null, entry, subIdent, refEntry); AssessmentEntry nodeAssessmentId2 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId3 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId4 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); dbInstance.commitAndCloseSession(); // load with our subIdent above @@ -239,9 +239,9 @@ public class AssessmentEntryDAOTest extends OlatTestCase { String subIdent = UUID.randomUUID().toString(); assessmentEntryDao.createAssessmentEntry(assessedIdentity1, null, entry, subIdent, refEntry); - assessmentEntryDao.createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE); - assessmentEntryDao.createAssessmentEntry(assessedIdentity3, null, entry, null, entry, 3.0f, Boolean.FALSE); - assessmentEntryDao.createAssessmentEntry(assessedIdentity4, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE); + assessmentEntryDao.createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); + assessmentEntryDao.createAssessmentEntry(assessedIdentity3, null, entry, null, entry, 3.0f, Boolean.FALSE, null, null); + assessmentEntryDao.createAssessmentEntry(assessedIdentity4, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); dbInstance.commitAndCloseSession(); // id 1,2,3 are in the entry, but 4 is in an other entry and must not appears in the list @@ -265,11 +265,11 @@ public class AssessmentEntryDAOTest extends OlatTestCase { AssessmentEntry nodeAssessmentId1 = assessmentEntryDao .createAssessmentEntry(assessedIdentity1, null, entry, subIdent, refEntry); AssessmentEntry nodeAssessmentId2 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId3 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId4 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity1, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity1, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); dbInstance.commitAndCloseSession(); // load for identity 1 @@ -321,11 +321,11 @@ public class AssessmentEntryDAOTest extends OlatTestCase { AssessmentEntry nodeAssessmentId1 = assessmentEntryDao .createAssessmentEntry(assessedIdentity1, null, entry, subIdent, refEntry); AssessmentEntry nodeAssessmentId2 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId3 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId4 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity1, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity1, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); dbInstance.commitAndCloseSession(); //load the assessment entries of entry @@ -350,11 +350,11 @@ public class AssessmentEntryDAOTest extends OlatTestCase { AssessmentEntry nodeAssessment1 = assessmentEntryDao .createAssessmentEntry(assessedIdentity1, null, entry, subIdent, refEntry); AssessmentEntry nodeAssessment2 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessment3 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessment4 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity1, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity1, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); dbInstance.commitAndCloseSession(); // delete by reference @@ -389,11 +389,11 @@ public class AssessmentEntryDAOTest extends OlatTestCase { AssessmentEntry nodeAssessment1 = assessmentEntryDao .createAssessmentEntry(assessedIdentity1, null, entry, subIdent, refEntry); AssessmentEntry nodeAssessment2 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessment3 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessment4 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity1, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity1, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); dbInstance.commitAndCloseSession(); // delete by reference @@ -433,17 +433,17 @@ public class AssessmentEntryDAOTest extends OlatTestCase { AssessmentEntry nodeAssessmentId1 = assessmentEntryDao .createAssessmentEntry(assessedIdentity1, null, entry, subIdent, refEntry); AssessmentEntry nodeAssessmentId2 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 0.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, subIdent, refEntry, 0.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId3 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 12.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, entry, null, entry, 12.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId4 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity2, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity2, null, refEntry, subIdent, refEntry, 3.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId5 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity3, null, entry, subIdent, refEntry, 6.0f, Boolean.TRUE); + .createAssessmentEntry(assessedIdentity3, null, entry, subIdent, refEntry, 6.0f, Boolean.TRUE, null, null); AssessmentEntry nodeAssessmentId6 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity4, null, entry, subIdent, refEntry, 1.0f, Boolean.FALSE); + .createAssessmentEntry(assessedIdentity4, null, entry, subIdent, refEntry, 1.0f, Boolean.FALSE, null, null); AssessmentEntry nodeAssessmentId7 = assessmentEntryDao - .createAssessmentEntry(assessedIdentity5, null, entry, subIdent, refEntry, 10.0f, Boolean.TRUE); + .createAssessmentEntry(assessedIdentity5, null, entry, subIdent, refEntry, 10.0f, Boolean.TRUE, null, null); dbInstance.commitAndCloseSession(); // load with our subIdent above List<AssessmentEntry> assessmentEntries = assessmentEntryDao diff --git a/src/test/java/org/olat/modules/card2brain/manager/Card2BrainManagerImplTest.java b/src/test/java/org/olat/modules/card2brain/manager/Card2BrainManagerImplTest.java index 6c75f14834b519f1765c860a28b74c7fda042e0c..3cd9ca55c55faa3a48e21029ec0b62a3269c996b 100644 --- a/src/test/java/org/olat/modules/card2brain/manager/Card2BrainManagerImplTest.java +++ b/src/test/java/org/olat/modules/card2brain/manager/Card2BrainManagerImplTest.java @@ -128,4 +128,33 @@ public class Card2BrainManagerImplTest { assertThat(sut.checkEnterpriseLogin("", "", "")).isNull(); } + @Test + public void parseAliasShouldRemoveUrlStart() { + String alias = "myAlias"; + String url = "https://card2brain.ch/box/" + alias; + + String parsedAlias = sut.parseAlias(url); + + assertThat(parsedAlias).isEqualTo(alias); + } + + @Test + public void parseAliasShouldRemoveUrlEditor() { + String alias = "myAlias"; + String url = "https://card2brain.ch/box/" + alias + "/editor"; + + String parsedAlias = sut.parseAlias(url); + + assertThat(parsedAlias).isEqualTo(alias); + } + + @Test + public void parseAliasShouldReplaceBlanks() { + String aliasWithBlanks = "bread and butter"; + String aliasWithoutBlanks = "bread_and_butter"; + + String parsedAlias = sut.parseAlias(aliasWithBlanks); + + assertThat(parsedAlias).isEqualTo(aliasWithoutBlanks); + } } diff --git a/src/test/java/org/olat/modules/lecture/manager/LectureBlockAuditLogDAOTest.java b/src/test/java/org/olat/modules/lecture/manager/LectureBlockAuditLogDAOTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4b56dfb5517cf958b4998a0adb7a546e7d215bc3 --- /dev/null +++ b/src/test/java/org/olat/modules/lecture/manager/LectureBlockAuditLogDAOTest.java @@ -0,0 +1,142 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.lecture.manager; + +import java.util.Date; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockAuditLog; +import org.olat.repository.RepositoryEntry; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 11 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LectureBlockAuditLogDAOTest extends OlatTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private LectureBlockDAO lectureBlockDao; + @Autowired + private LectureBlockAuditLogDAO lectureBlockAuditLogDao; + + @Test + public void createAuditLog() { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("audit-1-"); + Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("audit-1-"); + lectureBlockAuditLogDao.auditLog(LectureBlockAuditLog.Action.createLectureBlock, "3", "4", "Update absence", null, null,entry, identity, author); + dbInstance.commitAndCloseSession(); + } + + @Test + public void getAuditLog_byIdentity() { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("audit-2-"); + Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("audit-3-"); + lectureBlockAuditLogDao.auditLog(LectureBlockAuditLog.Action.createLectureBlock, "3", "4", "Update absence", null, null,entry, identity, author); + dbInstance.commitAndCloseSession(); + + //load the audit log + List<LectureBlockAuditLog> auditLog = lectureBlockAuditLogDao.getAuditLog(identity); + Assert.assertNotNull(auditLog); + Assert.assertEquals(1, auditLog.size()); + //check the entry + LectureBlockAuditLog logEntry = auditLog.get(0); + Assert.assertEquals(identity.getKey(), logEntry.getIdentityKey()); + Assert.assertEquals(author.getKey(), logEntry.getAuthorKey()); + Assert.assertEquals(entry.getKey(), logEntry.getEntryKey()); + Assert.assertEquals("3", logEntry.getBefore()); + Assert.assertEquals("4", logEntry.getAfter()); + Assert.assertEquals(LectureBlockAuditLog.Action.createLectureBlock.name(), logEntry.getAction()); + } + + @Test + public void getAuditLog_byRepositoryEntry() { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("audit-4-"); + Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("audit-5-"); + lectureBlockAuditLogDao.auditLog(LectureBlockAuditLog.Action.updateAuthorizedAbsence, "Before", "After", "Update absence of course", null, null,entry, identity, author); + dbInstance.commitAndCloseSession(); + + //load the audit log + List<LectureBlockAuditLog> auditLog = lectureBlockAuditLogDao.getAuditLog(entry); + Assert.assertNotNull(auditLog); + Assert.assertEquals(1, auditLog.size()); + //check the entry + LectureBlockAuditLog logEntry = auditLog.get(0); + Assert.assertEquals(identity.getKey(), logEntry.getIdentityKey()); + Assert.assertEquals(author.getKey(), logEntry.getAuthorKey()); + Assert.assertEquals(entry.getKey(), logEntry.getEntryKey()); + Assert.assertEquals("Before", logEntry.getBefore()); + Assert.assertEquals("After", logEntry.getAfter()); + Assert.assertEquals("Update absence of course", logEntry.getMessage()); + Assert.assertEquals(LectureBlockAuditLog.Action.updateAuthorizedAbsence.name(), logEntry.getAction()); + } + + @Test + public void getAuditLog_byLectureBlock() { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + LectureBlock lectureBlock = lectureBlockDao.createLectureBlock(entry); + lectureBlock.setStartDate(new Date()); + lectureBlock.setEndDate(new Date()); + lectureBlock.setTitle("I will be loged"); + lectureBlock = lectureBlockDao.update(lectureBlock); + lectureBlockAuditLogDao.auditLog(LectureBlockAuditLog.Action.autoclose, "Before", "After", "Close the absence of course", lectureBlock, null,entry, null, null); + dbInstance.commitAndCloseSession(); + + //load the audit log + List<LectureBlockAuditLog> auditLog = lectureBlockAuditLogDao.getAuditLog(lectureBlock); + Assert.assertNotNull(auditLog); + Assert.assertEquals(1, auditLog.size()); + //check the entry + LectureBlockAuditLog logEntry = auditLog.get(0); + Assert.assertEquals(entry.getKey(), logEntry.getEntryKey()); + Assert.assertEquals("Before", logEntry.getBefore()); + Assert.assertEquals("After", logEntry.getAfter()); + Assert.assertEquals("Close the absence of course", logEntry.getMessage()); + Assert.assertEquals(LectureBlockAuditLog.Action.autoclose.name(), logEntry.getAction()); + } + + @Test + public void xmlAuditLog() { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + LectureBlock lectureBlock = lectureBlockDao.createLectureBlock(entry); + lectureBlock.setStartDate(new Date()); + lectureBlock.setEndDate(new Date()); + lectureBlock.setTitle("Hello lecturers"); + lectureBlock = lectureBlockDao.update(lectureBlock); + dbInstance.commitAndCloseSession(); + + String xml = lectureBlockAuditLogDao.toXml(lectureBlock); + Assert.assertNotNull(xml); + } +} diff --git a/src/test/java/org/olat/modules/lecture/manager/LectureBlockDAOTest.java b/src/test/java/org/olat/modules/lecture/manager/LectureBlockDAOTest.java index af0ae202794c544631f06a3ecbadfc454283f6a0..dd2cb0e26cd4d4da0c7c5af6a395c59cdf5236bb 100644 --- a/src/test/java/org/olat/modules/lecture/manager/LectureBlockDAOTest.java +++ b/src/test/java/org/olat/modules/lecture/manager/LectureBlockDAOTest.java @@ -42,6 +42,7 @@ import org.olat.modules.lecture.LectureService; import org.olat.modules.lecture.RepositoryEntryLectureConfiguration; import org.olat.modules.lecture.model.LectureBlockImpl; import org.olat.modules.lecture.model.LectureBlockToGroupImpl; +import org.olat.modules.lecture.model.LecturesBlockSearchParameters; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; import org.olat.repository.manager.RepositoryEntryRelationDAO; @@ -130,7 +131,7 @@ public class LectureBlockDAOTest extends OlatTestCase { } @Test - public void getLectureBlocks() { + public void getLectureBlocks_entry() { RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); LectureBlock lectureBlock = lectureBlockDao.createLectureBlock(entry); lectureBlock.setStartDate(new Date()); @@ -146,6 +147,157 @@ public class LectureBlockDAOTest extends OlatTestCase { Assert.assertEquals(lectureBlock, loadedBlock); } + @Test + public void getLectureBlocks_all() { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + LectureBlock lectureBlock = lectureBlockDao.createLectureBlock(entry); + lectureBlock.setStartDate(new Date()); + lectureBlock.setEndDate(new Date()); + lectureBlock.setTitle("Get them all"); + lectureBlock = lectureBlockDao.update(lectureBlock); + dbInstance.commitAndCloseSession(); + + List<LectureBlock> blocks = lectureBlockDao.getLectureBlocks(); + Assert.assertNotNull(blocks); + Assert.assertTrue(blocks.size() >= 1); + Assert.assertTrue(blocks.contains(lectureBlock)); + } + + @Test + public void loadByTeachers() { + Identity teacher = JunitTestHelper.createAndPersistIdentityAsRndUser("teacher-1"); + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + LectureBlock lectureBlock = createMinimalLectureBlock(entry); + dbInstance.commitAndCloseSession(); + + lectureService.addTeacher(lectureBlock, teacher); + dbInstance.commitAndCloseSession(); + + //search all + LecturesBlockSearchParameters searchParams = new LecturesBlockSearchParameters(); + List<LectureBlock> blocks = lectureBlockDao.loadByTeacher(teacher, searchParams); + Assert.assertNotNull(blocks); + Assert.assertEquals(1, blocks.size()); + Assert.assertEquals(lectureBlock, blocks.get(0)); + } + + @Test + public void loadByTeachers_searchString() { + Identity teacher = JunitTestHelper.createAndPersistIdentityAsRndUser("teacher-1"); + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + LectureBlock lectureBlock = createMinimalLectureBlock(entry); + dbInstance.commitAndCloseSession(); + + lectureService.addTeacher(lectureBlock, teacher); + dbInstance.commitAndCloseSession(); + + //search lectures with the string + LecturesBlockSearchParameters searchParams = new LecturesBlockSearchParameters(); + searchParams.setSearchString("lecturers"); + List<LectureBlock> blocks = lectureBlockDao.loadByTeacher(teacher, searchParams); + Assert.assertNotNull(blocks); + Assert.assertEquals(1, blocks.size()); + Assert.assertEquals(lectureBlock, blocks.get(0)); + + //search lectures with a string which is not available to this teacher + LecturesBlockSearchParameters searchNegativeParams = new LecturesBlockSearchParameters(); + searchNegativeParams.setSearchString("goodbye"); + List<LectureBlock> negativeBlocks = lectureBlockDao.loadByTeacher(teacher, searchNegativeParams); + Assert.assertNotNull(negativeBlocks); + Assert.assertEquals(0, negativeBlocks.size()); + } + + @Test + public void loadByTeachers_startEndDates() { + Identity teacher = JunitTestHelper.createAndPersistIdentityAsRndUser("teacher-1"); + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + LectureBlock lectureBlock = createMinimalLectureBlock(entry); + dbInstance.commitAndCloseSession(); + + lectureService.addTeacher(lectureBlock, teacher); + dbInstance.commitAndCloseSession(); + + //search lectures with the string + LecturesBlockSearchParameters searchNowParams = new LecturesBlockSearchParameters(); + Calendar now = Calendar.getInstance(); + now.add(Calendar.DATE, -1); + searchNowParams.setStartDate(now.getTime()); + now.add(Calendar.DATE, 2); + searchNowParams.setEndDate(now.getTime()); + List<LectureBlock> blocks = lectureBlockDao.loadByTeacher(teacher, searchNowParams); + Assert.assertNotNull(blocks); + Assert.assertEquals(1, blocks.size()); + Assert.assertEquals(lectureBlock, blocks.get(0)); + + //search in future + LecturesBlockSearchParameters searchFutureParams = new LecturesBlockSearchParameters(); + now.add(Calendar.DATE, 2); + searchFutureParams.setStartDate(now.getTime()); + now.add(Calendar.DATE, 2); + searchFutureParams.setEndDate(now.getTime()); + List<LectureBlock> futureBlocks = lectureBlockDao.loadByTeacher(teacher, searchFutureParams); + Assert.assertNotNull(futureBlocks); + Assert.assertEquals(0, futureBlocks.size()); + } + + @Test + public void loadByTeachers_startDate() { + Identity teacher = JunitTestHelper.createAndPersistIdentityAsRndUser("teacher-3"); + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + LectureBlock lectureBlock = createMinimalLectureBlock(entry); + dbInstance.commitAndCloseSession(); + + lectureService.addTeacher(lectureBlock, teacher); + dbInstance.commitAndCloseSession(); + + //search lectures with the string + LecturesBlockSearchParameters searchNowParams = new LecturesBlockSearchParameters(); + Calendar now = Calendar.getInstance(); + now.add(Calendar.DATE, -1); + searchNowParams.setStartDate(now.getTime()); + List<LectureBlock> blocks = lectureBlockDao.loadByTeacher(teacher, searchNowParams); + Assert.assertNotNull(blocks); + Assert.assertEquals(1, blocks.size()); + Assert.assertEquals(lectureBlock, blocks.get(0)); + + //search in future + LecturesBlockSearchParameters searchFutureParams = new LecturesBlockSearchParameters(); + now.add(Calendar.DATE, 2); + searchFutureParams.setStartDate(now.getTime()); + List<LectureBlock> futureBlocks = lectureBlockDao.loadByTeacher(teacher, searchFutureParams); + Assert.assertNotNull(futureBlocks); + Assert.assertEquals(0, futureBlocks.size()); + } + + @Test + public void loadByTeachers_endDate() { + Identity teacher = JunitTestHelper.createAndPersistIdentityAsRndUser("teacher-3"); + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + LectureBlock lectureBlock = createMinimalLectureBlock(entry); + dbInstance.commitAndCloseSession(); + + lectureService.addTeacher(lectureBlock, teacher); + dbInstance.commitAndCloseSession(); + + //search lectures with the string + LecturesBlockSearchParameters searchNowParams = new LecturesBlockSearchParameters(); + Calendar now = Calendar.getInstance(); + now.add(Calendar.DATE, -1); + searchNowParams.setEndDate(now.getTime()); + List<LectureBlock> blocks = lectureBlockDao.loadByTeacher(teacher, searchNowParams); + Assert.assertNotNull(blocks); + Assert.assertEquals(0, blocks.size()); + + //search in future + LecturesBlockSearchParameters searchFutureParams = new LecturesBlockSearchParameters(); + now.add(Calendar.DATE, 2); + searchFutureParams.setEndDate(now.getTime()); + List<LectureBlock> futureBlocks = lectureBlockDao.loadByTeacher(teacher, searchFutureParams); + Assert.assertNotNull(futureBlocks); + Assert.assertEquals(1, futureBlocks.size()); + Assert.assertEquals(lectureBlock, futureBlocks.get(0)); + } + @Test public void addGroup() { RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); @@ -365,29 +517,7 @@ public class LectureBlockDAOTest extends OlatTestCase { Assert.assertEquals(1, rollcalls.size()); Assert.assertEquals(lectureBlock, rollcalls.get(0)); } - - @Test - public void appendLog() { - RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); - LectureBlock block = createMinimalLectureBlock(entry); - dbInstance.commitAndCloseSession(); - //append something - boolean ok = lectureBlockDao.appendLog(block, "New infos"); - Assert.assertTrue(ok); - dbInstance.commitAndCloseSession(); - - LectureBlock updatedBlock = lectureBlockDao.loadByKey(block.getKey()); - Assert.assertEquals("New infos", updatedBlock.getLog()); - - //append more things - boolean okToo = lectureBlockDao.appendLog(block, "More infos"); - Assert.assertTrue(okToo); - dbInstance.commitAndCloseSession(); - - LectureBlock updated2Block = lectureBlockDao.loadByKey(block.getKey()); - Assert.assertEquals("New infos\nMore infos", updated2Block.getLog()); - } @Test public void deleteLectureBlock() { diff --git a/src/test/java/org/olat/modules/lecture/manager/LectureBlockReminderDAOTest.java b/src/test/java/org/olat/modules/lecture/manager/LectureBlockReminderDAOTest.java index 4b46eb80c9329d54cbc650c91c5c8838bb07f9c8..96eacadbb258d6487c4fb601402b1669bdbb6b0a 100644 --- a/src/test/java/org/olat/modules/lecture/manager/LectureBlockReminderDAOTest.java +++ b/src/test/java/org/olat/modules/lecture/manager/LectureBlockReminderDAOTest.java @@ -101,6 +101,35 @@ public class LectureBlockReminderDAOTest extends OlatTestCase { Assert.assertFalse(hasTeacher1); } + @Test + public void deleteReminder() { + //create a reminder + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("reminder-to-delete-1"); + LectureBlock lectureBlock = createMinimalLectureBlock(2); + LectureBlockReminderImpl reminder = lectureBlockReminderDao.createReminder(lectureBlock, id, "Delete it"); + dbInstance.commitAndCloseSession(); + Assert.assertNotNull(reminder); + + //delete the reminders + int deletedRows = lectureBlockReminderDao.deleteReminders(id); + Assert.assertEquals(1, deletedRows); + dbInstance.commitAndCloseSession(); + + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DATE, -3); + List<LectureBlockToTeacher> toRemind = lectureBlockReminderDao.getLectureBlockTeachersToReminder(cal.getTime()); + + boolean hasId = false; + for(LectureBlockToTeacher remind:toRemind) { + if(remind.getLectureBlock().equals(lectureBlock)) { + if(remind.getTeacher().equals(id)) { + hasId = true; + } + } + } + + Assert.assertFalse(hasId); + } private LectureBlock createMinimalLectureBlock(int dayInThePast) { RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); @@ -114,5 +143,4 @@ public class LectureBlockReminderDAOTest extends OlatTestCase { lectureBlock.setTitle("Hello lecturers"); return lectureBlockDao.update(lectureBlock); } - -} +} \ No newline at end of file diff --git a/src/test/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAOTest.java b/src/test/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAOTest.java index af0b01b8d544c4b36d38405e182ee67149a40a63..0a151a10ceb61d283971c9e476de3b94cc3776fc 100644 --- a/src/test/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAOTest.java +++ b/src/test/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAOTest.java @@ -19,7 +19,10 @@ */ package org.olat.modules.lecture.manager; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; +import java.util.List; import org.junit.Assert; import org.junit.Test; @@ -27,6 +30,9 @@ import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; import org.olat.modules.lecture.LectureBlock; import org.olat.modules.lecture.LectureBlockRollCall; +import org.olat.modules.lecture.LectureBlockRollCallSearchParameters; +import org.olat.modules.lecture.LectureBlockStatus; +import org.olat.modules.lecture.LectureRollCallStatus; import org.olat.repository.RepositoryEntry; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; @@ -49,7 +55,7 @@ public class LectureBlockRollCallDAOTest extends OlatTestCase { @Test public void createAndPersistRollCall() { - LectureBlock lectureBlock = createMinimalLectureBlock(); + LectureBlock lectureBlock = createMinimalLectureBlock(2); Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); dbInstance.commitAndCloseSession(); @@ -66,7 +72,7 @@ public class LectureBlockRollCallDAOTest extends OlatTestCase { @Test public void createAndLoadRollCall() { - LectureBlock lectureBlock = createMinimalLectureBlock(); + LectureBlock lectureBlock = createMinimalLectureBlock(2); Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); dbInstance.commitAndCloseSession(); @@ -83,14 +89,354 @@ public class LectureBlockRollCallDAOTest extends OlatTestCase { Assert.assertEquals(lectureBlock, reloadRollCall.getLectureBlock()); Assert.assertEquals(id, reloadRollCall.getIdentity()); } + + @Test + public void createRollCall_absences() { + LectureBlock lectureBlock = createMinimalLectureBlock(3); + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + dbInstance.commitAndCloseSession(); + + List<Integer> absences = Collections.singletonList(2); + LectureBlockRollCall rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, id, null, null, null, absences); + dbInstance.commitAndCloseSession(); + + LectureBlockRollCall reloadRollCall = lectureBlockRollCallDao.loadByKey(rollCall.getKey()); + Assert.assertNotNull(reloadRollCall); + Assert.assertEquals(rollCall, reloadRollCall); + + //check absence + Assert.assertEquals(1, reloadRollCall.getLecturesAbsentNumber()); + List<Integer> absenceList = reloadRollCall.getLecturesAbsentList(); + Assert.assertNotNull(absenceList); + Assert.assertEquals(1, absenceList.size()); + Assert.assertEquals(2, absenceList.get(0).intValue()); + + //check attendee + Assert.assertEquals(2, reloadRollCall.getLecturesAttendedNumber()); + List<Integer> attendeeList = reloadRollCall.getLecturesAttendedList(); + Assert.assertNotNull(attendeeList); + Assert.assertEquals(2, attendeeList.size()); + Assert.assertEquals(0, attendeeList.get(0).intValue()); + Assert.assertEquals(1, attendeeList.get(1).intValue()); + } + + @Test + public void addLectures() { + LectureBlock lectureBlock = createMinimalLectureBlock(4); + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + dbInstance.commitAndCloseSession(); + + List<Integer> absences = Arrays.asList(0); + LectureBlockRollCall rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, id, null, null, null, absences); + dbInstance.commitAndCloseSession(); + + LectureBlockRollCall reloadRollCall = lectureBlockRollCallDao.loadByKey(rollCall.getKey()); + Assert.assertNotNull(reloadRollCall); + Assert.assertEquals(1, reloadRollCall.getLecturesAbsentNumber()); + + List<Integer> additionalAbsences = Arrays.asList(1, 2); + lectureBlockRollCallDao.addLecture(lectureBlock, reloadRollCall, additionalAbsences); + dbInstance.commitAndCloseSession(); + + //check absence + Assert.assertEquals(3, reloadRollCall.getLecturesAbsentNumber()); + List<Integer> absenceList = reloadRollCall.getLecturesAbsentList(); + Assert.assertNotNull(absenceList); + Assert.assertEquals(3, absenceList.size()); + Assert.assertEquals(0, absenceList.get(0).intValue()); + Assert.assertEquals(1, absenceList.get(1).intValue()); + Assert.assertEquals(2, absenceList.get(2).intValue()); + + //check attendee + Assert.assertEquals(1, reloadRollCall.getLecturesAttendedNumber()); + List<Integer> attendeeList = reloadRollCall.getLecturesAttendedList(); + Assert.assertNotNull(attendeeList); + Assert.assertEquals(1, attendeeList.size()); + Assert.assertEquals(3, attendeeList.get(0).intValue()); + } + + @Test + public void removeLectures() { + LectureBlock lectureBlock = createMinimalLectureBlock(4); + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + dbInstance.commitAndCloseSession(); + + List<Integer> absences = Arrays.asList(0, 1, 2, 3); + LectureBlockRollCall rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, id, null, null, null, absences); + dbInstance.commitAndCloseSession(); + + LectureBlockRollCall reloadRollCall = lectureBlockRollCallDao.loadByKey(rollCall.getKey()); + Assert.assertNotNull(reloadRollCall); + Assert.assertEquals(4, reloadRollCall.getLecturesAbsentNumber()); + + List<Integer> removedAbsences = Arrays.asList(1, 2); + lectureBlockRollCallDao.removeLecture(lectureBlock, reloadRollCall, removedAbsences); + dbInstance.commitAndCloseSession(); + + //check absence + Assert.assertEquals(2, reloadRollCall.getLecturesAbsentNumber()); + List<Integer> absenceList = reloadRollCall.getLecturesAbsentList(); + Assert.assertNotNull(absenceList); + Assert.assertEquals(2, absenceList.size()); + Assert.assertEquals(0, absenceList.get(0).intValue()); + Assert.assertEquals(3, absenceList.get(1).intValue()); + + //check attendee + Assert.assertEquals(2, reloadRollCall.getLecturesAttendedNumber()); + List<Integer> attendeeList = reloadRollCall.getLecturesAttendedList(); + Assert.assertNotNull(attendeeList); + Assert.assertEquals(2, attendeeList.size()); + Assert.assertEquals(1, attendeeList.get(0).intValue()); + Assert.assertEquals(2, attendeeList.get(1).intValue()); + } + + @Test + public void adaptLectures_removeAbsences() { + LectureBlock lectureBlock = createMinimalLectureBlock(4); + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + dbInstance.commitAndCloseSession(); + + List<Integer> absences = Arrays.asList(0, 1, 2, 3); + LectureBlockRollCall rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, id, null, null, null, absences); + dbInstance.commitAndCloseSession(); + + LectureBlockRollCall reloadRollCall = lectureBlockRollCallDao.loadByKey(rollCall.getKey()); + Assert.assertNotNull(reloadRollCall); + Assert.assertEquals(4, reloadRollCall.getLecturesAbsentNumber()); + + //adapt the number of lectures + LectureBlockRollCall adaptedCall = lectureBlockRollCallDao.adaptLecture(lectureBlock, reloadRollCall, 2, id); + dbInstance.commitAndCloseSession(); + + //check absence + Assert.assertEquals(2, adaptedCall.getLecturesAbsentNumber()); + List<Integer> absenceList = adaptedCall.getLecturesAbsentList(); + Assert.assertNotNull(absenceList); + Assert.assertEquals(2, absenceList.size()); + Assert.assertEquals(0, absenceList.get(0).intValue()); + Assert.assertEquals(1, absenceList.get(1).intValue()); + + //check attendee + Assert.assertEquals(0, reloadRollCall.getLecturesAttendedNumber()); + List<Integer> attendeeList = reloadRollCall.getLecturesAttendedList(); + Assert.assertNotNull(attendeeList); + Assert.assertEquals(0, attendeeList.size()); + } + + @Test + public void adaptLectures_removeMixed() { + LectureBlock lectureBlock = createMinimalLectureBlock(4); + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + dbInstance.commitAndCloseSession(); + + List<Integer> absences = Arrays.asList(1, 2); + LectureBlockRollCall rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, id, null, null, null, absences); + dbInstance.commitAndCloseSession(); + + LectureBlockRollCall reloadRollCall = lectureBlockRollCallDao.loadByKey(rollCall.getKey()); + Assert.assertNotNull(reloadRollCall); + Assert.assertEquals(2, reloadRollCall.getLecturesAbsentNumber()); + + //adapt the number of lectures + LectureBlockRollCall adaptedCall = lectureBlockRollCallDao.adaptLecture(lectureBlock, reloadRollCall, 2, id); + dbInstance.commitAndCloseSession(); + + //check absence + Assert.assertEquals(1, adaptedCall.getLecturesAbsentNumber()); + List<Integer> absenceList = adaptedCall.getLecturesAbsentList(); + Assert.assertNotNull(absenceList); + Assert.assertEquals(1, absenceList.size()); + Assert.assertEquals(1, absenceList.get(0).intValue()); + + //check attendee + Assert.assertEquals(1, reloadRollCall.getLecturesAttendedNumber()); + List<Integer> attendeeList = reloadRollCall.getLecturesAttendedList(); + Assert.assertNotNull(attendeeList); + Assert.assertEquals(1, attendeeList.size()); + Assert.assertEquals(0, attendeeList.get(0).intValue()); + } + + @Test + public void adaptLectures_addMixed() { + LectureBlock lectureBlock = createMinimalLectureBlock(3); + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + dbInstance.commitAndCloseSession(); + + List<Integer> absences = Arrays.asList(1, 2); + LectureBlockRollCall rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, id, null, null, null, absences); + dbInstance.commitAndCloseSession(); + + LectureBlockRollCall reloadRollCall = lectureBlockRollCallDao.loadByKey(rollCall.getKey()); + Assert.assertNotNull(reloadRollCall); + Assert.assertEquals(2, reloadRollCall.getLecturesAbsentNumber()); + + //adapt the number of lectures + LectureBlockRollCall adaptedCall = lectureBlockRollCallDao.adaptLecture(lectureBlock, reloadRollCall, 4, id); + dbInstance.commitAndCloseSession(); + + //check absence + Assert.assertEquals(2, adaptedCall.getLecturesAbsentNumber()); + List<Integer> absenceList = adaptedCall.getLecturesAbsentList(); + Assert.assertNotNull(absenceList); + Assert.assertEquals(2, absenceList.size()); + Assert.assertEquals(1, absenceList.get(0).intValue()); + Assert.assertEquals(2, absenceList.get(1).intValue()); + + //check attendee + Assert.assertEquals(2, reloadRollCall.getLecturesAttendedNumber()); + List<Integer> attendeeList = reloadRollCall.getLecturesAttendedList(); + Assert.assertNotNull(attendeeList); + Assert.assertEquals(2, attendeeList.size()); + Assert.assertEquals(0, attendeeList.get(0).intValue()); + Assert.assertEquals(3, attendeeList.get(1).intValue()); + } + + @Test + public void getRollCalls_searchParams_True() { + // an open lecture block + LectureBlock openLectureBlock = createMinimalLectureBlock(3); + Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-2"); + dbInstance.commitAndCloseSession(); + + // a closed lecture block + LectureBlock closedLectureBlock = createMinimalLectureBlock(3); + dbInstance.commitAndCloseSession(); + closedLectureBlock.setStatus(LectureBlockStatus.done); + closedLectureBlock.setRollCallStatus(LectureRollCallStatus.closed); + lectureBlockDao.update(closedLectureBlock); + List<Integer> absences = Arrays.asList(1, 2); + LectureBlockRollCall rollCall1 = lectureBlockRollCallDao.createAndPersistRollCall(closedLectureBlock, id1, null, null, null, Collections.emptyList()); + LectureBlockRollCall rollCall2 = lectureBlockRollCallDao.createAndPersistRollCall(closedLectureBlock, id2, null, null, null, absences); + LectureBlockRollCall rollCall3 = lectureBlockRollCallDao.createAndPersistRollCall(openLectureBlock, id1, null, null, null, absences); + LectureBlockRollCall rollCall4 = lectureBlockRollCallDao.createAndPersistRollCall(openLectureBlock, id2, null, null, null, Collections.emptyList()); + dbInstance.commit(); + + rollCall2.setAbsenceSupervisorNotificationDate(new Date()); + rollCall2 = lectureBlockRollCallDao.update(rollCall2); + dbInstance.commitAndCloseSession(); + + {//only absences + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setHasAbsence(Boolean.TRUE); + List<LectureBlockRollCall> rollCalls = lectureBlockRollCallDao.getRollCalls(searchParams); + Assert.assertFalse(rollCalls.contains(rollCall1)); + Assert.assertTrue(rollCalls.contains(rollCall2)); + Assert.assertTrue(rollCalls.contains(rollCall3)); + Assert.assertFalse(rollCalls.contains(rollCall4)); + } + + {//only with supervisor date + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setHasSupervisorNotificationDate(Boolean.TRUE); + List<LectureBlockRollCall> rollCalls = lectureBlockRollCallDao.getRollCalls(searchParams); + Assert.assertFalse(rollCalls.contains(rollCall1)); + Assert.assertTrue(rollCalls.contains(rollCall2)); + Assert.assertFalse(rollCalls.contains(rollCall3)); + Assert.assertFalse(rollCalls.contains(rollCall4)); + } + + {//only closed + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setClosed(Boolean.TRUE); + List<LectureBlockRollCall> rollCalls = lectureBlockRollCallDao.getRollCalls(searchParams); + Assert.assertTrue(rollCalls.contains(rollCall1)); + Assert.assertTrue(rollCalls.contains(rollCall2)); + Assert.assertFalse(rollCalls.contains(rollCall3)); + Assert.assertFalse(rollCalls.contains(rollCall4)); + } + + {//only with supervisor date + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setClosed(Boolean.TRUE); + searchParams.setHasAbsence(Boolean.TRUE); + searchParams.setHasSupervisorNotificationDate(Boolean.TRUE); + List<LectureBlockRollCall> rollCalls = lectureBlockRollCallDao.getRollCalls(searchParams); + Assert.assertFalse(rollCalls.contains(rollCall1)); + Assert.assertTrue(rollCalls.contains(rollCall2)); + Assert.assertFalse(rollCalls.contains(rollCall3)); + Assert.assertFalse(rollCalls.contains(rollCall4)); + } + } + + @Test + public void getRollCalls_searchParams_False() { + // an open lecture block + LectureBlock openLectureBlock = createMinimalLectureBlock(3); + Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-2"); + dbInstance.commitAndCloseSession(); + + // a closed lecture block + LectureBlock closedLectureBlock = createMinimalLectureBlock(3); + dbInstance.commitAndCloseSession(); + closedLectureBlock.setStatus(LectureBlockStatus.done); + closedLectureBlock.setRollCallStatus(LectureRollCallStatus.closed); + lectureBlockDao.update(closedLectureBlock); + + List<Integer> absences = Arrays.asList(1, 2); + LectureBlockRollCall rollCall1 = lectureBlockRollCallDao.createAndPersistRollCall(closedLectureBlock, id1, null, null, null, Collections.emptyList()); + LectureBlockRollCall rollCall2 = lectureBlockRollCallDao.createAndPersistRollCall(closedLectureBlock, id2, null, null, null, absences); + LectureBlockRollCall rollCall3 = lectureBlockRollCallDao.createAndPersistRollCall(openLectureBlock, id1, null, null, null, absences); + LectureBlockRollCall rollCall4 = lectureBlockRollCallDao.createAndPersistRollCall(openLectureBlock, id2, null, null, null, Collections.emptyList()); + dbInstance.commit(); + + rollCall2.setAbsenceSupervisorNotificationDate(new Date()); + rollCall2 = lectureBlockRollCallDao.update(rollCall2); + dbInstance.commitAndCloseSession(); + + {// only not closed + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setClosed(Boolean.FALSE); + List<LectureBlockRollCall> rollCalls = lectureBlockRollCallDao.getRollCalls(searchParams); + Assert.assertFalse(rollCalls.contains(rollCall1)); + Assert.assertFalse(rollCalls.contains(rollCall2)); + Assert.assertTrue(rollCalls.contains(rollCall3)); + Assert.assertTrue(rollCalls.contains(rollCall4)); + } + + {// without absence + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setHasAbsence(Boolean.FALSE); + List<LectureBlockRollCall> rollCalls = lectureBlockRollCallDao.getRollCalls(searchParams); + Assert.assertTrue(rollCalls.contains(rollCall1)); + Assert.assertFalse(rollCalls.contains(rollCall2)); + Assert.assertFalse(rollCalls.contains(rollCall3)); + Assert.assertTrue(rollCalls.contains(rollCall4)); + } + + {// without supervisor date + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setHasSupervisorNotificationDate(Boolean.FALSE); + List<LectureBlockRollCall> rollCalls = lectureBlockRollCallDao.getRollCalls(searchParams); + Assert.assertTrue(rollCalls.contains(rollCall1)); + Assert.assertFalse(rollCalls.contains(rollCall2)); + Assert.assertTrue(rollCalls.contains(rollCall3)); + Assert.assertTrue(rollCalls.contains(rollCall4)); + } + + {// open, without supervisor date + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setClosed(Boolean.FALSE); + searchParams.setHasAbsence(Boolean.FALSE); + searchParams.setHasSupervisorNotificationDate(Boolean.FALSE); + List<LectureBlockRollCall> rollCalls = lectureBlockRollCallDao.getRollCalls(searchParams); + Assert.assertFalse(rollCalls.contains(rollCall1)); + Assert.assertFalse(rollCalls.contains(rollCall2)); + Assert.assertFalse(rollCalls.contains(rollCall3)); + Assert.assertTrue(rollCalls.contains(rollCall4)); + } + } - private LectureBlock createMinimalLectureBlock() { + private LectureBlock createMinimalLectureBlock(int numOfLectures) { RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); LectureBlock lectureBlock = lectureBlockDao.createLectureBlock(entry); lectureBlock.setStartDate(new Date()); lectureBlock.setEndDate(new Date()); lectureBlock.setTitle("Hello lecturers"); + lectureBlock.setPlannedLecturesNumber(numOfLectures); + lectureBlock.setEffectiveLecturesNumber(numOfLectures); return lectureBlockDao.update(lectureBlock); } } diff --git a/src/test/java/org/olat/modules/lecture/manager/ReasonDAOTest.java b/src/test/java/org/olat/modules/lecture/manager/ReasonDAOTest.java index 50200a41a6df027c8244ed6d27bf61d19f39d020..5f0bc0a721baf0936df1985675a54adc2d3c145f 100644 --- a/src/test/java/org/olat/modules/lecture/manager/ReasonDAOTest.java +++ b/src/test/java/org/olat/modules/lecture/manager/ReasonDAOTest.java @@ -108,4 +108,24 @@ public class ReasonDAOTest extends OlatTestCase { boolean inUse = reasonDao.isReasonInUse(reason); Assert.assertFalse(inUse); } + + @Test + public void deleteReasons() { + //create a reason + String title = "Forgotten reason"; + String description = "Find a list"; + Reason reason = reasonDao.createReason(title, description); + dbInstance.commitAndCloseSession(); + //check it exists + List<Reason> reasons = reasonDao.getReasons(); + Assert.assertTrue(reasons.contains(reason)); + + //delete the reason + boolean deleted = reasonDao.delete(reason); + Assert.assertTrue(deleted); + + //check it exists + List<Reason> reloadedDasons = reasonDao.getReasons(); + Assert.assertFalse(reloadedDasons.contains(reason)); + } } diff --git a/src/test/java/org/olat/modules/lecture/manager/RepositoryEntryLectureConfigurationDAOTest.java b/src/test/java/org/olat/modules/lecture/manager/RepositoryEntryLectureConfigurationDAOTest.java index d9013bf91160b05b58d4a095cfd397a439ecfdb7..4ba99acd783cf705d4a08d7b81d1ce0af70ff322 100644 --- a/src/test/java/org/olat/modules/lecture/manager/RepositoryEntryLectureConfigurationDAOTest.java +++ b/src/test/java/org/olat/modules/lecture/manager/RepositoryEntryLectureConfigurationDAOTest.java @@ -106,5 +106,69 @@ public class RepositoryEntryLectureConfigurationDAOTest extends OlatTestCase { RepositoryEntryLectureConfiguration reloadedConfig = lectureConfigurationDao.getConfiguration(lectureBlock); Assert.assertEquals(config, reloadedConfig); } - + + @Test + public void cloneConfigureLectureConfiguration() { + //create a configuration + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + RepositoryEntry cloneEntry = JunitTestHelper.createAndPersistRepositoryEntry(); + RepositoryEntryLectureConfiguration config = lectureConfigurationDao.createConfiguration(entry); + config.setLectureEnabled(true); + config.setOverrideModuleDefault(true); + config.setCalculateAttendanceRate(Boolean.TRUE); + config.setRequiredAttendanceRate(0.75d); + config.setParticipantCalendarSyncEnabled(Boolean.TRUE); + config.setTeacherCalendarSyncEnabled(Boolean.TRUE); + RepositoryEntryLectureConfiguration mergedConfig = lectureConfigurationDao.update(config); + dbInstance.commitAndCloseSession(); + + //clone it + RepositoryEntryLectureConfiguration clonedConfig = lectureConfigurationDao.cloneConfiguration(mergedConfig, cloneEntry); + dbInstance.commitAndCloseSession(); + Assert.assertNotNull(clonedConfig); + + + RepositoryEntryLectureConfiguration reloadedClonedConfig = lectureConfigurationDao.getConfiguration(cloneEntry); + Assert.assertEquals(clonedConfig, reloadedClonedConfig); + Assert.assertEquals(true, reloadedClonedConfig.isLectureEnabled()); + Assert.assertEquals(true, reloadedClonedConfig.isOverrideModuleDefault()); + Assert.assertEquals(Boolean.TRUE, reloadedClonedConfig.getCalculateAttendanceRate()); + Assert.assertEquals(0.75d, reloadedClonedConfig.getRequiredAttendanceRate(), 0.0001); + Assert.assertEquals(Boolean.TRUE, reloadedClonedConfig.getParticipantCalendarSyncEnabled()); + Assert.assertEquals(Boolean.TRUE, reloadedClonedConfig.getTeacherCalendarSyncEnabled()); + } + + @Test + public void isConfigurationEnabledFor() { + //create a configuration + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + RepositoryEntryLectureConfiguration config = lectureConfigurationDao.createConfiguration(entry); + config.setLectureEnabled(true); + RepositoryEntryLectureConfiguration mergedConfig = lectureConfigurationDao.update(config); + dbInstance.commitAndCloseSession(); + Assert.assertNotNull(mergedConfig); + + //check that the configuration enables the lectures feature + boolean enabled = lectureConfigurationDao.isConfigurationEnabledFor(entry); + Assert.assertTrue(enabled); + } + + @Test + public void deleteConfiguration_byRepositoryEntry() { + //create a configuration + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + RepositoryEntryLectureConfiguration config = lectureConfigurationDao.createConfiguration(entry); + config.setLectureEnabled(true); + RepositoryEntryLectureConfiguration mergedConfig = lectureConfigurationDao.update(config); + dbInstance.commitAndCloseSession(); + Assert.assertNotNull(mergedConfig); + + //delete the configuration + lectureConfigurationDao.deleteConfiguration(entry); + dbInstance.commitAndCloseSession(); + + //check that the configuration is really deleted + RepositoryEntryLectureConfiguration deletedConfig = lectureConfigurationDao.getConfiguration(entry); + Assert.assertNull(deletedConfig); + } } diff --git a/src/test/java/org/olat/modules/reminder/manager/ReminderDAOTest.java b/src/test/java/org/olat/modules/reminder/manager/ReminderDAOTest.java index 38e9d318919e5d8dd2447310b12a12b0ba756600..6357129341f428667e919df8fb122f42b74ec765 100644 --- a/src/test/java/org/olat/modules/reminder/manager/ReminderDAOTest.java +++ b/src/test/java/org/olat/modules/reminder/manager/ReminderDAOTest.java @@ -66,6 +66,7 @@ public class ReminderDAOTest extends OlatTestCase { Assert.assertNotNull(reminder); reminder.setConfiguration("<rules></rules>"); reminder.setDescription("Reminder - 1"); + reminder.setEmailSubject("This is a subject"); reminder.setEmailBody("Hello world"); //save and check @@ -79,6 +80,7 @@ public class ReminderDAOTest extends OlatTestCase { Assert.assertEquals(entry, savedReminder.getEntry()); Assert.assertEquals("Reminder - 1", savedReminder.getDescription()); Assert.assertEquals("<rules></rules>", savedReminder.getConfiguration()); + Assert.assertEquals("This is a subject", savedReminder.getEmailSubject()); Assert.assertEquals("Hello world", savedReminder.getEmailBody()); //reload and double check @@ -92,6 +94,7 @@ public class ReminderDAOTest extends OlatTestCase { Assert.assertEquals(savedReminder, reloadedReminder); Assert.assertEquals("Reminder - 1", reloadedReminder.getDescription()); Assert.assertEquals("<rules></rules>", reloadedReminder.getConfiguration()); + Assert.assertEquals("This is a subject", reloadedReminder.getEmailSubject()); Assert.assertEquals("Hello world", reloadedReminder.getEmailBody()); } @@ -104,6 +107,7 @@ public class ReminderDAOTest extends OlatTestCase { Reminder reminder = reminderDao.createReminder(entry, creator); reminder.setConfiguration("<rules></rules>"); reminder.setDescription("Reminder - 2"); + reminder.setEmailSubject("This is a subject"); reminder.setEmailBody("Hello world"); Reminder savedReminder = reminderDao.save(reminder); Assert.assertNotNull(savedReminder); @@ -152,6 +156,7 @@ public class ReminderDAOTest extends OlatTestCase { Reminder reminder = reminderDao.createReminder(entry, creator); reminder.setConfiguration("<rules></rules>"); reminder.setDescription("Reminder - 12"); + reminder.setEmailSubject("This is a deleted subject"); reminder.setEmailBody("Hello, I'm deleted"); Reminder savedReminder = reminderDao.save(reminder); Assert.assertNotNull(savedReminder); @@ -180,6 +185,7 @@ public class ReminderDAOTest extends OlatTestCase { Reminder reminder = reminderDao.createReminder(entry, creator); reminder.setConfiguration("<rules></rules>"); reminder.setDescription("Reminder - 4"); + reminder.setEmailSubject("This is a subject"); reminder.setEmailBody("Hello world"); Reminder savedReminder = reminderDao.save(reminder); Assert.assertNotNull(savedReminder); @@ -194,6 +200,7 @@ public class ReminderDAOTest extends OlatTestCase { Assert.assertEquals(savedReminder, loadedReminder); Assert.assertEquals(entry, loadedReminder.getEntry()); Assert.assertEquals("Reminder - 4", loadedReminder.getDescription()); + Assert.assertEquals("This is a subject", loadedReminder.getEmailSubject()); Assert.assertEquals("Hello world", loadedReminder.getEmailBody()); } @@ -344,6 +351,7 @@ public class ReminderDAOTest extends OlatTestCase { Assert.assertEquals(creator, reloadedDuplicate.getCreator()); Assert.assertEquals(entry, reloadedDuplicate.getEntry()); Assert.assertEquals(reminderToCopy.getEmailBody(), reloadedDuplicate.getEmailBody()); + Assert.assertEquals(reminderToCopy.getEmailSubject(), reloadedDuplicate.getEmailSubject()); Assert.assertTrue(reloadedDuplicate.getDescription().startsWith(reminderToCopy.getDescription())); Assert.assertEquals(reminderToCopy.getConfiguration(), reloadedDuplicate.getConfiguration()); } @@ -435,6 +443,7 @@ public class ReminderDAOTest extends OlatTestCase { Reminder reminder = reminderDao.createReminder(entry, creator); reminder.setConfiguration("<rules></rules>"); reminder.setDescription("Reminder - " + num); + reminder.setEmailSubject("This is a subject - " + num); reminder.setEmailBody("Hello world - " + num); return reminderDao.save(reminder); } diff --git a/src/test/java/org/olat/modules/reminder/manager/ReminderRuleEngineTest.java b/src/test/java/org/olat/modules/reminder/manager/ReminderRuleEngineTest.java index 55a6408ca7044c2b59ff9e31dfb976f1f5fbf00f..97936acfb3d47e2c3a5224d2250710636f6b3698 100644 --- a/src/test/java/org/olat/modules/reminder/manager/ReminderRuleEngineTest.java +++ b/src/test/java/org/olat/modules/reminder/manager/ReminderRuleEngineTest.java @@ -50,6 +50,7 @@ import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.group.BusinessGroup; import org.olat.group.manager.BusinessGroupDAO; import org.olat.group.manager.BusinessGroupRelationDAO; +import org.olat.modules.assessment.Role; import org.olat.modules.reminder.ReminderRule; import org.olat.modules.reminder.model.ReminderRuleImpl; import org.olat.modules.reminder.rule.CourseEnrollmentDateRuleSPI; @@ -1059,7 +1060,7 @@ public class ReminderRuleEngineTest extends OlatTestCase { ienv.setIdentity(student); UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment()); - course.getCourseEnvironment().getAssessmentManager().saveScoreEvaluation(testNode, tutor, student, scoreEval, userCourseEnv, true); + course.getCourseEnvironment().getAssessmentManager().saveScoreEvaluation(testNode, tutor, student, scoreEval, userCourseEnv, true, Role.coach); dbInstance.commit(); return testNode.getIdent(); diff --git a/src/test/java/org/olat/modules/webFeed/manager/FeedFileStorgeTest.java b/src/test/java/org/olat/modules/webFeed/manager/FeedFileStorgeTest.java index 2c1749aaf5ea078b6bb8426502cd1227c204544c..4b37ba4ea4852aeed2065fb1683a8131f56bd904 100644 --- a/src/test/java/org/olat/modules/webFeed/manager/FeedFileStorgeTest.java +++ b/src/test/java/org/olat/modules/webFeed/manager/FeedFileStorgeTest.java @@ -39,221 +39,221 @@ import org.olat.test.OlatTestCase; /** * Test the FeedFileStorage. - * + * * saveItemMedia - * - * + * + * * Initial date: 22.05.2017<br> * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com * */ public class FeedFileStorgeTest extends OlatTestCase { - + FeedFileStorge sut; - + private FileResourceManager fileResourceManager; - + @Before public void setup() { fileResourceManager = FileResourceManager.getInstance(); sut = new FeedFileStorge(); } - + @Test public void getOrCreateFeedContainer_create() { FeedFileResource ores = new BlogFileResource(); - + VFSContainer feedContainer = sut.getOrCreateFeedContainer(ores); - + assertThat(feedContainer).isNotNull(); - + fileResourceManager.deleteFileResource(ores); } - + @Test public void getOrCreateFeedContainer_get() { FeedFileResource ores = new BlogFileResource(); - + sut.getOrCreateFeedContainer(ores); VFSContainer feedContainer = sut.getOrCreateFeedContainer(ores); - + assertThat(feedContainer).isNotNull(); - + fileResourceManager.deleteFileResource(ores); } - + @Test public void getOrCreateFeedContainer_null() { VFSContainer feedContainer = sut.getOrCreateFeedContainer(null); - + assertThat(feedContainer).isNull(); } - + @Test public void getOrCreateFeedMediaContainer_create() { FeedFileResource ores = new BlogFileResource(); - + VFSContainer feedMediaContainer = sut.getOrCreateFeedMediaContainer(ores); - + assertThat(feedMediaContainer).isNotNull(); - + fileResourceManager.deleteFileResource(ores); } - + @Test public void getOrCreateFeedMediaContainer_get() { FeedFileResource ores = new BlogFileResource(); - + sut.getOrCreateFeedMediaContainer(ores); VFSContainer feedMediaContainer = sut.getOrCreateFeedMediaContainer(ores); - + assertThat(feedMediaContainer).isNotNull(); - + fileResourceManager.deleteFileResource(ores); } - + @Test public void getOrCreateFeedMediaContainer_null() { VFSContainer feedMediaContainer = sut.getOrCreateFeedMediaContainer(null); - + assertThat(feedMediaContainer).isNull(); } - + @Test public void getOrCreateFeedItemsContainer_create() { FeedFileResource ores = new BlogFileResource(); - + VFSContainer feedItemsContainer = sut.getOrCreateFeedItemsContainer(ores); - + assertThat(feedItemsContainer).isNotNull(); - + fileResourceManager.deleteFileResource(ores); } - + @Test public void getOrCreateFeedItemsContainer_get() { FeedFileResource ores = new BlogFileResource(); - + sut.getOrCreateFeedItemsContainer(ores); VFSContainer feedItemsContainer = sut.getOrCreateFeedItemsContainer(ores); - + assertThat(feedItemsContainer).isNotNull(); - + fileResourceManager.deleteFileResource(ores); } - + @Test public void getOrCreateFeedItemsContainer_null() { VFSContainer feedItemsContainer = sut.getOrCreateFeedItemsContainer(null); - + assertThat(feedItemsContainer).isNull(); } - + @Test public void getOrCreateItemContainer_create() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); Item item = new ItemImpl(feed); item.setGuid("guid"); - + VFSContainer itemContainer = sut.getOrCreateItemContainer(item); - + assertThat(itemContainer).isNotNull(); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void getOrCreateItemContainer_get() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); Item item = new ItemImpl(feed); item.setGuid("guid"); - + sut.getOrCreateItemContainer(item); VFSContainer itemContainer = sut.getOrCreateItemContainer(item); - + assertThat(itemContainer).isNotNull(); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void getOrCreateItemContainer_Item_null() { VFSContainer itemContainer = sut.getOrCreateItemContainer(null); - + assertThat(itemContainer).isNull(); } - + @Test public void getOrCreateItemContainer_Feed_null() { Item item = new ItemImpl(null); item.setGuid("guid"); - + VFSContainer itemContainer = sut.getOrCreateItemContainer(item); - + assertThat(itemContainer).isNull(); } - + @Test public void getOrCreateItemContainer_Guid_empty() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); Item item = new ItemImpl(feed); item.setGuid(""); - + VFSContainer itemContainer = sut.getOrCreateItemContainer(item); - + assertThat(itemContainer).isNull(); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void getOrCreateItemContainer_guid_create() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); String guid = "guid 123"; - + VFSContainer itemContainer = sut.getOrCreateItemContainer(feed, guid); - + assertThat(itemContainer).isNotNull(); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void getOrCreateItemContainer_guid_get() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); String guid = "guid 123"; - + sut.getOrCreateItemContainer(feed, guid); VFSContainer itemContainer = sut.getOrCreateItemContainer(feed, guid); - + assertThat(itemContainer).isNotNull(); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void getOrCreateItemContainer_guid_Feed_null() { String guid = "guid 123"; - + VFSContainer itemContainer = sut.getOrCreateItemContainer(null, guid); - + assertThat(itemContainer).isNull(); } - + @Test public void getOrCreateItemContainer_guid_Guid_empty() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); - + VFSContainer itemContainer = sut.getOrCreateItemContainer(feed, null); - + assertThat(itemContainer).isNull(); - + fileResourceManager.deleteFileResource(resource); } @@ -263,60 +263,60 @@ public class FeedFileStorgeTest extends OlatTestCase { Feed feed = new FeedImpl(resource); Item item = new ItemImpl(feed); item.setGuid("guid"); - + VFSContainer itemMediaContainer = sut.getOrCreateItemMediaContainer(item); - + assertThat(itemMediaContainer).isNotNull(); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void getOrCreateItemMediaContainer_get() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); Item item = new ItemImpl(feed); item.setGuid("guid"); - + sut.getOrCreateItemMediaContainer(item); VFSContainer itemMediaContainer = sut.getOrCreateItemMediaContainer(item); - + assertThat(itemMediaContainer).isNotNull(); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void getOrCreateItemMediaContainer_Item_null() { VFSContainer itemMediaContainer = sut.getOrCreateItemMediaContainer(null); - + assertThat(itemMediaContainer).isNull(); } - + @Test public void getOrCreateItemMediaContainer_Feed_null() { Item item = new ItemImpl(null); item.setGuid("guid"); - + VFSContainer itemMediaContainer = sut.getOrCreateItemMediaContainer(item); - + assertThat(itemMediaContainer).isNull(); } - + @Test public void getOrCreateItemMediaContainer_Guid_empty() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); Item item = new ItemImpl(feed); item.setGuid(""); - + VFSContainer itemMediaContainer = sut.getOrCreateItemMediaContainer(item); - + assertThat(itemMediaContainer).isNull(); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void deleteItemContainer() { BlogFileResource resource = new BlogFileResource(); @@ -327,15 +327,15 @@ public class FeedFileStorgeTest extends OlatTestCase { Item item2= new ItemImpl(feed); item2.setGuid("guid 2"); sut.getOrCreateItemContainer(item2); - + sut.deleteItemContainer(item1); - + // check if there is only one item container left assertThat(sut.getOrCreateFeedItemsContainer(feed).getItems().size()).isEqualTo(1); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void deleteItemContainer_not_existing() { BlogFileResource resource = new BlogFileResource(); @@ -345,15 +345,15 @@ public class FeedFileStorgeTest extends OlatTestCase { Item item2= new ItemImpl(feed); item2.setGuid("guid 2"); sut.getOrCreateItemContainer(item2); - + sut.deleteItemContainer(item1); - + // check if there is only one item container left assertThat(sut.getOrCreateFeedItemsContainer(feed).getItems().size()).isEqualTo(1); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void deleteItemContainer_null() { BlogFileResource resource = new BlogFileResource(); @@ -361,52 +361,52 @@ public class FeedFileStorgeTest extends OlatTestCase { Item item1 = new ItemImpl(feed); item1.setGuid("guid 1"); sut.getOrCreateItemContainer(item1); - + sut.deleteItemContainer(null); - + // check if there is one item container left assertThat(sut.getOrCreateFeedItemsContainer(feed).getItems().size()).isEqualTo(1); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void saveFeedAsXML_new() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); feed.setAuthor("initialAuthor"); - + sut.saveFeedAsXML(feed); - + // check if there is one file in the feed container assertThat(sut.getOrCreateFeedContainer(feed).getItems().size()).isEqualTo(1); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void saveFeedAsXML_overwrite() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); feed.setAuthor("initialAuthor"); sut.saveFeedAsXML(feed); - + feed.setAuthor("secondAuthor"); sut.saveFeedAsXML(feed); - + // check if there is one file in the feed container assertThat(sut.getOrCreateFeedContainer(feed).getItems().size()).isEqualTo(1); - + fileResourceManager.deleteFileResource(resource); } @Test public void saveFeedAsXML_null() { sut.saveFeedAsXML(null); - + // no exception } - + @Test public void loadFeedFromXML_Ores() { BlogFileResource resource = new BlogFileResource(); @@ -414,26 +414,55 @@ public class FeedFileStorgeTest extends OlatTestCase { String autor = "autor"; feed.setAuthor(autor); sut.saveFeedAsXML(feed); - + Feed reloaded = sut.loadFeedFromXML(resource); - + assertThat(reloaded).isNotNull(); assertThat(reloaded.getAuthor()).isEqualTo(autor); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void loadFeedFromXML_Ores_not_existing() { BlogFileResource resource = new BlogFileResource(); - + Feed reloaded = sut.loadFeedFromXML(resource); - + assertThat(reloaded).isNull(); - + + fileResourceManager.deleteFileResource(resource); + } + + @Test + public void loadFeedFromXML_shortening_values() { + StringBuffer sb = new StringBuffer(5000); + for (int i = 0; i < 5000; i++){ + sb.append("A"); + } + String stringWith5000Chars = sb.toString(); + BlogFileResource resource = new BlogFileResource(); + Feed feed = new FeedImpl(resource); + feed.setAuthor(stringWith5000Chars); + feed.setDescription(stringWith5000Chars); + feed.setTitle(stringWith5000Chars); + feed.setExternalFeedUrl(stringWith5000Chars); + feed.setExternalImageURL(stringWith5000Chars); + sut.saveFeedAsXML(feed); + + Feed reloaded = sut.loadFeedFromXML(resource); + + assertThat(reloaded).isNotNull(); + assertThat(reloaded.getAuthor()).hasSize(255); + assertThat(reloaded.getTitle()).hasSize(1024); + assertThat(reloaded.getDescription()).hasSize(4000); + assertThat(reloaded.getExternalFeedUrl()).isNull(); + assertThat(reloaded.getExternalImageURL()).isNull(); + assertThat(reloaded.getImageName()).isNull(); + fileResourceManager.deleteFileResource(resource); } - + @Test public void loadFeedFromXML_Path() { BlogFileResource resource = new BlogFileResource(); @@ -442,60 +471,60 @@ public class FeedFileStorgeTest extends OlatTestCase { feed.setAuthor(autor); sut.saveFeedAsXML(feed); Path feedDir = fileResourceManager.getFileResource(resource).toPath(); - + Feed reloaded = FeedManager.getInstance().loadFeedFromXML(feedDir); - + assertThat(reloaded).isNotNull(); assertThat(reloaded.getAuthor()).isEqualTo(autor); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void loadFeedFromXML_Path_not_existing() { Path feedDir = Paths.get("abc"); - + Feed reloaded = FeedManager.getInstance().loadFeedFromXML(feedDir); - + assertThat(reloaded).isNull(); } - + @Test public void deleteFeedXML() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); feed.setAuthor("initialAuthor"); sut.saveFeedAsXML(feed); - + sut.deleteFeedXML(feed); - + // check if there is no file in the feed container assertThat(sut.getOrCreateFeedContainer(feed).getItems().size()).isEqualTo(0); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void deleteFeedXML_not_existing() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); feed.setAuthor("initialAuthor"); - + sut.deleteFeedXML(feed); - + // check if there is no file in the feed container assertThat(sut.getOrCreateFeedContainer(feed).getItems().size()).isEqualTo(0); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void deleteFeedXMLnull() { sut.deleteFeedXML(null); - + // no exception } - + @Test public void saveItemAsXML_new() { BlogFileResource resource = new BlogFileResource(); @@ -503,15 +532,15 @@ public class FeedFileStorgeTest extends OlatTestCase { Item item = new ItemImpl(feed); item.setGuid("123"); item.setAuthor("autor"); - + sut.saveItemAsXML(item); - + // check if there is one file in the item container assertThat(sut.getOrCreateItemContainer(item).getItems().size()).isEqualTo(1); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void saveItemAsXML_overwrite() { BlogFileResource resource = new BlogFileResource(); @@ -520,23 +549,23 @@ public class FeedFileStorgeTest extends OlatTestCase { item.setGuid("123"); item.setAuthor("autor"); sut.saveItemAsXML(item); - + item.setAuthor("secondAuthor"); sut.saveItemAsXML(item); - + // check if there is one file in the item container assertThat(sut.getOrCreateItemContainer(item).getItems().size()).isEqualTo(1); - + fileResourceManager.deleteFileResource(resource); } @Test public void saveItemAsXML_null() { sut.saveItemAsXML(null); - + // no exception } - + @Test public void loadItemFromXML() { BlogFileResource resource = new BlogFileResource(); @@ -547,16 +576,16 @@ public class FeedFileStorgeTest extends OlatTestCase { String autor = "autor"; item.setAuthor(autor); sut.saveItemAsXML(item); - VFSContainer itemContainer = sut.getOrCreateItemContainer(item); - + VFSContainer itemContainer = sut.getOrCreateItemContainer(item); + Item reloaded = sut.loadItemFromXML(itemContainer); - + assertThat(reloaded).isNotNull(); assertThat(reloaded.getAuthor()).isEqualTo(autor); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void loadItemFromXML_not_existing() { BlogFileResource resource = new BlogFileResource(); @@ -566,22 +595,22 @@ public class FeedFileStorgeTest extends OlatTestCase { item.setGuid(guid); String autor = "autor"; item.setAuthor(autor); - VFSContainer itemContainer = sut.getOrCreateItemContainer(item); - + VFSContainer itemContainer = sut.getOrCreateItemContainer(item); + Item reloaded = sut.loadItemFromXML(itemContainer); - + assertThat(reloaded).isNull(); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void loadItemFromXML_null() { Item reloaded = sut.loadItemFromXML(null); - + assertThat(reloaded).isNull(); } - + @Test public void loadItemsFromXML() { BlogFileResource resource = new BlogFileResource(); @@ -598,14 +627,14 @@ public class FeedFileStorgeTest extends OlatTestCase { String guid3 = "guid 3"; item3.setGuid(guid3); sut.saveItemAsXML(item3); - + List<Item> items = sut.loadItemsFromXML(feed); - + assertThat(items.size()).isEqualTo(3); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void loadItemsFromXML_missing_XML() { BlogFileResource resource = new BlogFileResource(); @@ -619,33 +648,60 @@ public class FeedFileStorgeTest extends OlatTestCase { item2.setGuid(guid2); sut.saveItemAsXML(item2); sut.deleteItemXML(item1); - + List<Item> items = sut.loadItemsFromXML(feed); - + assertThat(items.size()).isEqualTo(1); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void loadItemsFromXML_empty() { BlogFileResource resource = new BlogFileResource(); Feed feed = new FeedImpl(resource); - + List<Item> items = sut.loadItemsFromXML(feed); - + assertThat(items.size()).isEqualTo(0); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void loadItemsFromXML_null() { List<Item> items = sut.loadItemsFromXML(null); - + assertThat(items.size()).isEqualTo(0); } - + + @Test + public void loadItemsFromXML_shortening() { + StringBuffer sb = new StringBuffer(5000); + for (int i = 0; i < 5000; i++){ + sb.append("A"); + } + String stringWith5000Chars = sb.toString(); + BlogFileResource resource = new BlogFileResource(); + Feed feed = new FeedImpl(resource); + Item item = new ItemImpl(feed); + String guid1 = "guid 1"; + item.setGuid(guid1); + item.setAuthor(stringWith5000Chars); + item.setExternalLink(stringWith5000Chars); + item.setTitle(stringWith5000Chars); + sut.saveItemAsXML(item); + + List<Item> items = sut.loadItemsFromXML(feed); + Item reloadedItem = items.get(0); + + assertThat(reloadedItem.getAuthor()).hasSize(255); + assertThat(reloadedItem.getExternalLink()).isNull(); + assertThat(reloadedItem.getTitle()).hasSize(1024); + + fileResourceManager.deleteFileResource(resource); + } + @Test public void deleteItemXML() { BlogFileResource resource = new BlogFileResource(); @@ -654,15 +710,15 @@ public class FeedFileStorgeTest extends OlatTestCase { item.setGuid("123"); item.setAuthor("autor"); sut.saveItemAsXML(item); - + sut.deleteItemXML(item); - + // check if there is no file in the item container assertThat(sut.getOrCreateItemContainer(item).getItems().size()).isEqualTo(0); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void deleteItemXML_not_existing() { BlogFileResource resource = new BlogFileResource(); @@ -670,19 +726,19 @@ public class FeedFileStorgeTest extends OlatTestCase { Item item = new ItemImpl(feed); item.setGuid("123"); item.setAuthor("autor"); - + sut.deleteItemXML(item); - + // check if there is no file in the item container assertThat(sut.getOrCreateItemContainer(item).getItems().size()).isEqualTo(0); - + fileResourceManager.deleteFileResource(resource); } - + @Test public void deleteItemXMLnull() { sut.deleteItemXML(null); - + // no exception } diff --git a/src/test/java/org/olat/modules/webFeed/manager/FeedManagerImplTest.java b/src/test/java/org/olat/modules/webFeed/manager/FeedManagerImplTest.java index 176990cec05ffc467a4041fb01647a0a73718636..271f61f5a9f88adc4b8c9dd9892d74008d3cda6a 100644 --- a/src/test/java/org/olat/modules/webFeed/manager/FeedManagerImplTest.java +++ b/src/test/java/org/olat/modules/webFeed/manager/FeedManagerImplTest.java @@ -20,13 +20,15 @@ * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. +* under the Apache 2.0 license as the original file. * <p> */ package org.olat.modules.webFeed.manager; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -39,6 +41,9 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.olat.core.commons.services.notifications.NotificationsManager; +import org.olat.core.gui.components.form.flexible.elements.FileElement; +import org.olat.core.id.Identity; import org.olat.core.util.coordinate.Coordinator; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.coordinate.Syncer; @@ -46,18 +51,42 @@ import org.olat.fileresource.FileResourceManager; import org.olat.modules.webFeed.ExternalFeedFetcher; import org.olat.modules.webFeed.Feed; import org.olat.modules.webFeed.Item; +import org.olat.modules.webFeed.model.FeedImpl; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.springframework.test.util.ReflectionTestUtils; /** - * + * * Initial date: 12.05.2017<br> * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com * */ public class FeedManagerImplTest { - + + private static final Long FEED_KEY = 4L; + private static final String RESOURCEABLE_TYPE_NAME = "resurcable type name"; + private static final Long RESOURCABLE_ID = 5L; + private static final String EXTERNAL_URL_OLD = "oldExternalURL"; + private static final String EXTERNAL_URL_NEW = "newExternalURL"; + private static final Long ITEM_KEY = 6L; + private static Identity IGNORE_NEWS_FOR_NOBODY = null; + private static boolean SEND_NO_EVENTS = false; + + @Mock + private OLATResource resourceDummy; + @Mock + private Feed internatFeedMock; + private Feed externalFeed; + @Mock + private Item internalItemMock; + @Mock + private FileElement fileElementDummy; + @Mock + private Syncer syncerDummy; + @Mock private FeedDAO feedDAOMock; @Mock @@ -75,18 +104,14 @@ public class FeedManagerImplTest { @Mock private Coordinator coordinaterMock; @Mock - OLATResource resourceDummy; - @Mock - Feed feedDummy; + private RepositoryManager repositoryManager; @Mock - Item itemDummy; - @Mock - Syncer syncerDummy; - + private NotificationsManager notificationsManagerMock; + private FeedManagerImpl sut; - + @Before - public void injectNonSpringManagers() { + public void setUp() { MockitoAnnotations.initMocks(this); when(coordinaterManagerMock.getCoordinator()).thenReturn(coordinaterMock); when(coordinaterMock.getSyncer()).thenReturn(syncerDummy); @@ -96,162 +121,346 @@ public class FeedManagerImplTest { ReflectionTestUtils.setField(sut, "itemDAO", itemDAOMock); ReflectionTestUtils.setField(sut, "feedFileStorage", feedFileStorageMock); ReflectionTestUtils.setField(sut, "externalFeedFetcher", feedFetcherMock); - + ReflectionTestUtils.setField(sut, "repositoryManager", repositoryManager); + ReflectionTestUtils.setField(sut, "notificationsManager", notificationsManagerMock); + + when(internatFeedMock.getKey()).thenReturn(FEED_KEY); + when(internatFeedMock.getResourceableTypeName()).thenReturn(RESOURCEABLE_TYPE_NAME); + when(internatFeedMock.getResourceableId()).thenReturn(RESOURCABLE_ID); + when(internatFeedMock.isInternal()).thenReturn(true); + + when(internalItemMock.getKey()).thenReturn(ITEM_KEY); + when(internalItemMock.getFeed()).thenReturn(internatFeedMock); + + externalFeed = new FeedImpl(resourceDummy); + externalFeed.setKey(FEED_KEY); + externalFeed.setExternal(true); + externalFeed.setExternalFeedUrl(EXTERNAL_URL_OLD); } - + + @Test + public void shouldUpdateFeedWhenExternalUrlChanged() { + when(feedDAOMock.loadFeed(externalFeed)).thenReturn(externalFeed); + when(feedDAOMock.updateFeed(externalFeed)).thenReturn(externalFeed); + + Feed updatedFeed = sut.updateExternalFeedUrl(externalFeed, EXTERNAL_URL_NEW); + + assertThat(updatedFeed.getExternalFeedUrl()).isEqualTo(EXTERNAL_URL_NEW); + assertThat(updatedFeed.getLastModified()).isNotNull(); + verify(feedDAOMock).updateFeed(externalFeed); + } + + @Test + public void shouldNotUpdateFeedWhenExternalUrlIsTheSame() { + when(feedDAOMock.loadFeed(externalFeed)).thenReturn(externalFeed); + when(feedDAOMock.updateFeed(externalFeed)).thenReturn(externalFeed); + + Feed updatedFeed = sut.updateExternalFeedUrl(externalFeed, EXTERNAL_URL_OLD); + + assertThat(updatedFeed.getExternalFeedUrl()).isEqualTo(EXTERNAL_URL_OLD); + assertThat(updatedFeed.getLastModified()).isNotNull(); + verify(feedDAOMock).updateFeed(externalFeed); + } + + @Test + public void shouldDeleteAllItemsIfExternalUrlChanged() { + when(feedDAOMock.loadFeed(externalFeed)).thenReturn(externalFeed); + when(feedDAOMock.updateFeed(externalFeed)).thenReturn(externalFeed); + + sut.updateExternalFeedUrl(externalFeed, EXTERNAL_URL_NEW); + + verify(itemDAOMock).removeItems(externalFeed); + } + + @Test + public void shouldNotDeleteItemsWhenExternaUrlIsTheSame() { + when(feedDAOMock.loadFeed(externalFeed)).thenReturn(externalFeed); + when(feedDAOMock.updateFeed(externalFeed)).thenReturn(externalFeed); + + sut.updateExternalFeedUrl(externalFeed, EXTERNAL_URL_OLD); + + verify(itemDAOMock, never()).removeItems(externalFeed); + } + + @Test + public void shouldFetchItemsWhenExternalUrlChanged() { + when(feedDAOMock.loadFeed(externalFeed)).thenReturn(externalFeed); + when(feedDAOMock.updateFeed(externalFeed)).thenReturn(externalFeed); + + sut.updateExternalFeedUrl(externalFeed, EXTERNAL_URL_NEW); + + verify(feedFetcherMock).fetchFeed(externalFeed); + verify(feedFetcherMock).fetchItems(externalFeed); + } + + @Test + public void shouldSaveItemWhenItemCreated() { + when(feedDAOMock.loadFeed(FEED_KEY)).thenReturn(internatFeedMock); + + sut.createItem(internatFeedMock, internalItemMock, fileElementDummy); + + verify(itemDAOMock).createItem(internatFeedMock, internalItemMock); + } + + @Test + public void shouldOnlyAllowToCreateItemIfFeedIsInternal() { + when(feedDAOMock.loadFeed(FEED_KEY)).thenReturn(internatFeedMock); + when(internatFeedMock.isInternal()).thenReturn(false); + + Feed feedOfCreatedItem = sut.createItem(null, internalItemMock, fileElementDummy); + + assertThat(feedOfCreatedItem).isNull(); + verify(itemDAOMock, never()).createItem(internatFeedMock, internalItemMock); + } + + @Test + public void shouldSaveItemWhenItemUpdated() { + when(itemDAOMock.loadItem(ITEM_KEY)).thenReturn(internalItemMock); + when(itemDAOMock.updateItem(internalItemMock)).thenReturn(internalItemMock); + + sut.updateItem(internalItemMock, fileElementDummy); + + verify(itemDAOMock).updateItem(internalItemMock); + } + + @Test + public void shouldNotSaveItemIfItemToUpdateDoesNotExists() { + when(itemDAOMock.loadItem(ITEM_KEY)).thenReturn(null); + when(itemDAOMock.updateItem(internalItemMock)).thenReturn(internalItemMock); + + sut.updateItem(internalItemMock, fileElementDummy); + + verify(itemDAOMock, never()).updateItem(internalItemMock); + } + + @Test + public void shouldMarkPublisherNewsWhenItemCreated() { + when(feedDAOMock.loadFeed(FEED_KEY)).thenReturn(internatFeedMock); + when(feedDAOMock.updateFeed(internatFeedMock)).thenReturn(internatFeedMock); + + sut.createItem(internatFeedMock, internalItemMock, fileElementDummy); + + verify(notificationsManagerMock).markPublisherNews( + RESOURCEABLE_TYPE_NAME, + RESOURCABLE_ID.toString(), + IGNORE_NEWS_FOR_NOBODY, + SEND_NO_EVENTS); + } + + @Test + public void shouldMarkPublisherNewsWhenItemUpdated() { + when(itemDAOMock.loadItem(ITEM_KEY)).thenReturn(internalItemMock); + when(itemDAOMock.updateItem(internalItemMock)).thenReturn(internalItemMock); + + sut.updateItem(internalItemMock, fileElementDummy); + + verify(notificationsManagerMock).markPublisherNews( + RESOURCEABLE_TYPE_NAME, + RESOURCABLE_ID.toString(), + IGNORE_NEWS_FOR_NOBODY, + SEND_NO_EVENTS); + } + @Test public void importShouldNothingDoIfNoXmlFileIsPresent() { when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(null); - + sut.importFeedFromXML(any(OLATResource.class), true); - + verifyZeroInteractions(feedDAOMock); verifyZeroInteractions(itemDAOMock); } - + @Test public void importShouldSaveFeedToDatabase() { - when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(feedDummy); - when(feedDAOMock.createFeed(any(Feed.class))).thenReturn(feedDummy); - when(feedDummy.isExternal()).thenReturn(false); - + when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(internatFeedMock); + when(feedDAOMock.createFeed(any(Feed.class))).thenReturn(internatFeedMock); + when(internatFeedMock.isExternal()).thenReturn(false); + sut.importFeedFromXML(resourceDummy, true); - + verify(feedDAOMock).createFeed(any(Feed.class)); } - + @Test public void importShouldSaveItemsToDatabase() { - List<Item> items = java.util.Arrays.asList(itemDummy, itemDummy, itemDummy); + List<Item> items = java.util.Arrays.asList(internalItemMock, internalItemMock, internalItemMock); - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); - when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); + when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(internatFeedMock); when(feedFileStorageMock.loadItemsFromXML(resourceDummy)).thenReturn(items); - + sut.importFeedFromXML(resourceDummy, true); - + verify(itemDAOMock, times(3)).createItem(any(Feed.class), any(Item.class)); } - + @Test public void importShouldNotCreateItemsIfNoXmlFilesArePresent() { List<Item> emtpyList = new ArrayList<>(); - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); - when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); + when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(internatFeedMock); when(feedFileStorageMock.loadItemsFromXML(resourceDummy)).thenReturn(emtpyList); - + sut.importFeedFromXML(resourceDummy, true); verifyZeroInteractions(itemDAOMock); } - + @Test public void importShoulDeleteAuthorKey() { - List<Item> items = java.util.Arrays.asList(itemDummy); + List<Item> items = java.util.Arrays.asList(internalItemMock); - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); - when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); + when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(internatFeedMock); when(feedFileStorageMock.loadItemsFromXML(resourceDummy)).thenReturn(items); - when(itemDAOMock.loadItemByGuid(any(Long.class), any(String.class))).thenReturn(itemDummy); - + when(itemDAOMock.loadItemByGuid(any(Long.class), any(String.class))).thenReturn(internalItemMock); + sut.importFeedFromXML(resourceDummy, true); - - verify(itemDummy).setAuthorKey(null); + + verify(internalItemMock).setAuthorKey(null); } - + @Test public void importShoulDeleteModifierKey() { - List<Item> items = java.util.Arrays.asList(itemDummy); + List<Item> items = java.util.Arrays.asList(internalItemMock); - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); - when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); + when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(internatFeedMock); when(feedFileStorageMock.loadItemsFromXML(resourceDummy)).thenReturn(items); - when(itemDAOMock.loadItemByGuid(any(Long.class), any(String.class))).thenReturn(itemDummy); - + when(itemDAOMock.loadItemByGuid(any(Long.class), any(String.class))).thenReturn(internalItemMock); + sut.importFeedFromXML(resourceDummy, true); - - verify(itemDummy).setModifierKey(null); + + verify(internalItemMock).setModifierKey(null); } - + @Test public void importShoulDeleteFeedXmlFile() { - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); - when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); + when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(internatFeedMock); sut.importFeedFromXML(resourceDummy, true); - - verify(feedFileStorageMock).deleteFeedXML(feedDummy); + + verify(feedFileStorageMock).deleteFeedXML(internatFeedMock); } - + @Test public void importShoulDeleteItemsXmlFiles() { - List<Item> items = java.util.Arrays.asList(itemDummy, itemDummy, itemDummy); + List<Item> items = java.util.Arrays.asList(internalItemMock, internalItemMock, internalItemMock); - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); - when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); + when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(internatFeedMock); when(feedFileStorageMock.loadItemsFromXML(resourceDummy)).thenReturn(items); - + sut.importFeedFromXML(resourceDummy, true); - verify(feedFileStorageMock, times(3)).deleteItemXML(itemDummy); + verify(feedFileStorageMock, times(3)).deleteItemXML(internalItemMock); } - + @Test public void importShoulLoadItemsOfExternalFeeds() { - List<Item> items = java.util.Arrays.asList(itemDummy); + List<Item> items = java.util.Arrays.asList(internalItemMock); - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); - when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); + when(feedFileStorageMock.loadFeedFromXML(any(OLATResource.class))).thenReturn(internatFeedMock); when(feedFileStorageMock.loadItemsFromXML(resourceDummy)).thenReturn(items); - when(feedDummy.isExternal()).thenReturn(true); - + when(internatFeedMock.isExternal()).thenReturn(true); + sut.importFeedFromXML(resourceDummy, true); - verify(feedFetcherMock).fetchFeed(feedDummy); - verify(feedFetcherMock).fetchItems(feedDummy); + verify(feedFetcherMock).fetchFeed(internatFeedMock); + verify(feedFetcherMock).fetchItems(internatFeedMock); } - + @Test public void exportShouldWriteFeedToXmlFile() { - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); sut.getFeedArchive(resourceDummy); - - verify(feedFileStorageMock).saveFeedAsXML(feedDummy); + + verify(feedFileStorageMock).saveFeedAsXML(internatFeedMock); } - + @Test public void exportShouldWriteItemsToXmlFiles() { - List<Item> threeItems = java.util.Arrays.asList(itemDummy, itemDummy, itemDummy); - + List<Item> threeItems = java.util.Arrays.asList(internalItemMock, internalItemMock, internalItemMock); + when(itemDAOMock.loadItems(any(Feed.class))).thenReturn(threeItems); - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); sut.getFeedArchive(resourceDummy); - - verify(feedFileStorageMock, times(3)).saveItemAsXML(itemDummy); + + verify(feedFileStorageMock, times(3)).saveItemAsXML(internalItemMock); } - + @Test public void exportShoulDeleteFeedXmlFile() { - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); sut.getFeedArchive(resourceDummy); - - verify(feedFileStorageMock).deleteFeedXML(feedDummy); + + verify(feedFileStorageMock).deleteFeedXML(internatFeedMock); } - + @Test public void exportShoulDeleteItemsXmlFiles() { - List<Item> threeItems = java.util.Arrays.asList(itemDummy, itemDummy, itemDummy); + List<Item> threeItems = java.util.Arrays.asList(internalItemMock, internalItemMock, internalItemMock); when(itemDAOMock.loadItems(any(Feed.class))).thenReturn(threeItems); - when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(feedDummy); - + when(feedDAOMock.loadFeed(any(OLATResource.class))).thenReturn(internatFeedMock); + sut.getFeedArchive(resourceDummy); - verify(feedFileStorageMock, times(3)).deleteItemXML(itemDummy); + verify(feedFileStorageMock, times(3)).deleteItemXML(internalItemMock); + } + + + @Test + public void enrichFeedFromRepositoryEntryShouldTransferAtributes() { + Feed feed = new FeedImpl(resourceDummy); + RepositoryEntry entry = new RepositoryEntry(); + String title = "Title"; + entry.setDisplayname(title); + String description = "Description"; + entry.setDescription(description); + String authors = "Author"; + entry.setAuthors(authors); + + Feed enrichedFeed = sut.enrichFeedByRepositoryEntry(feed, entry); + + assertThat(enrichedFeed.getTitle()).isEqualTo(title); + assertThat(enrichedFeed.getDescription()).isEqualTo(description); + assertThat(enrichedFeed.getAuthor()).isEqualTo(authors); } - + + + @Test + public void enrichFeedFromRepositoryEntryShouldReturnUnchangedFeedIfRepositoryIsNull() { + Feed feed = new FeedImpl(resourceDummy); + String title = "Title"; + feed.setTitle(title); + String description = "Description"; + feed.setDescription(description); + String authors = "Author"; + feed.setAuthor(authors); + + Feed enrichedFeed = sut.enrichFeedByRepositoryEntry(feed, null); + + assertThat(enrichedFeed).isEqualTo(feed); + assertThat(enrichedFeed.getTitle()).isEqualTo(title); + assertThat(enrichedFeed.getDescription()).isEqualTo(description); + assertThat(enrichedFeed.getAuthor()).isEqualTo(authors); + } + + @Test + public void enrichFeedFromRepositoryEntryShouldReturnNullIfFeedIsNull() { + RepositoryEntry entry = new RepositoryEntry(); + + Feed enrichedFeed = sut.enrichFeedByRepositoryEntry(null, entry); + + assertThat(enrichedFeed).isNull(); + } + } diff --git a/src/test/java/org/olat/modules/webFeed/manager/ItemDAOTest.java b/src/test/java/org/olat/modules/webFeed/manager/ItemDAOTest.java index 5bda874655debfc7325b6991da5cb24ee9e1d827..77166370f99825779e8c17fc8c849792f24ed5a1 100644 --- a/src/test/java/org/olat/modules/webFeed/manager/ItemDAOTest.java +++ b/src/test/java/org/olat/modules/webFeed/manager/ItemDAOTest.java @@ -29,6 +29,7 @@ import java.util.List; import org.junit.Test; import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; import org.olat.modules.webFeed.Enclosure; import org.olat.modules.webFeed.Feed; import org.olat.modules.webFeed.Item; @@ -310,6 +311,53 @@ public class ItemDAOTest extends OlatTestCase { assertThat(item).isNull(); } + @Test + public void loadItemByGuid_without_feed() { + OLATResource resource = JunitTestHelper.createRandomResource(); + Feed feed = feedDao.createFeedForResourcable(resource); + dbInstance.commitAndCloseSession(); + + // create an item + String guid = "guid-123467890"; + Item tempItem = new ItemImpl(feed); + tempItem.setGuid(guid); + itemDao.createItem(feed, tempItem); + dbInstance.commitAndCloseSession(); + + // reload the item from the database + Item item = itemDao.loadItemByGuid(guid); + + //check values + assertThat(item).isNotNull(); + + //clean up + itemDao.removeItem(item); + } + + @Test + public void loadItemByGuid_without_feed_multiple_guids() { + OLATResource resource = JunitTestHelper.createRandomResource(); + Feed feed = feedDao.createFeedForResourcable(resource); + dbInstance.commitAndCloseSession(); + + // create an item + String guid = "guid-12345"; + Item tempItem = new ItemImpl(feed); + tempItem.setGuid(guid); + itemDao.createItem(feed, tempItem); + dbInstance.commitAndCloseSession(); + tempItem = new ItemImpl(feed); + tempItem.setGuid(guid); + itemDao.createItem(feed, tempItem); + dbInstance.commitAndCloseSession(); + + // reload the item from the database + Item item = itemDao.loadItemByGuid(guid); + + //check values + assertThat(item).isNull(); + } + @Test public void loadItems_Feed() { OLATResource resource = JunitTestHelper.createRandomResource(); @@ -431,6 +479,8 @@ public class ItemDAOTest extends OlatTestCase { Feed feed = feedDao.createFeedForResourcable(resource); dbInstance.commitAndCloseSession(); + Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("user-1234"); + Item item = itemDao.createItem(feed); dbInstance.commitAndCloseSession(); @@ -443,7 +493,7 @@ public class ItemDAOTest extends OlatTestCase { item.setExternalLink("https://example.com/"); item.setGuid("guid-2"); item.setHeight(3); - item.setModifierKey(2L); + item.setModifierKey(author.getKey()); item.setPublishDate(new Date()); item.setTitle("tile"); item.setWidth(5); diff --git a/src/test/java/org/olat/modules/wiki/WikiUnitTest.java b/src/test/java/org/olat/modules/wiki/WikiUnitTest.java index 6b58228f8f48c3210310869cefd0ce2d05d7f201..00f184e02aefd230a300d7a5e2b6301008230ca8 100644 --- a/src/test/java/org/olat/modules/wiki/WikiUnitTest.java +++ b/src/test/java/org/olat/modules/wiki/WikiUnitTest.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertNotNull; import java.util.List; +import org.junit.Assert; import org.junit.Test; import org.olat.core.id.OLATResourceable; import org.olat.modules.wiki.versioning.ChangeInfo; @@ -46,6 +47,15 @@ import org.olat.test.OlatTestCase; */ public class WikiUnitTest extends OlatTestCase { private static final String WIKI_CONTENT = "==heading==\n'''bold'''\n[[Image:test.jpg|bla]]"; + + @Test + public void alternativeId() { + String alternativeId = "SW5kZXg_.wp"; + String convertedId = WikiManager.convertAlternativeFilename(alternativeId); + + String indexId = WikiManager.generatePageId(WikiPage.WIKI_INDEX_PAGE) + WikiManager.WIKI_DOT_FILE_SUFFIX; + Assert.assertEquals(indexId, convertedId); + } @Test public void testWikiStuff() { diff --git a/src/test/java/org/olat/repository/manager/RepositoryEntryDAOTest.java b/src/test/java/org/olat/repository/manager/RepositoryEntryDAOTest.java index 0bda248053fd043fa333107f4cd523b9fd6d9cf9..cd76c8d9c789d739b2d29755c168242333e01447 100644 --- a/src/test/java/org/olat/repository/manager/RepositoryEntryDAOTest.java +++ b/src/test/java/org/olat/repository/manager/RepositoryEntryDAOTest.java @@ -20,6 +20,7 @@ package org.olat.repository.manager; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -35,13 +36,13 @@ import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; /** - * + * * Initial date: 12.03.2014<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class RepositoryEntryDAOTest extends OlatTestCase { - + @Autowired private DB dbInstance; @Autowired @@ -50,52 +51,52 @@ public class RepositoryEntryDAOTest extends OlatTestCase { private RepositoryService repositoryService; @Autowired private RepositoryEntryDAO repositoryEntryDao; - + @Test public void loadByKey() { RepositoryEntry re = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 1", "", null); dbInstance.commitAndCloseSession(); Assert.assertNotNull(re); - + RepositoryEntry loadedRe = repositoryEntryDao.loadByKey(re.getKey()); Assert.assertNotNull(loadedRe.getStatistics()); Assert.assertNotNull(loadedRe.getOlatResource()); } - + @Test public void loadByResourceKey() { RepositoryEntry re = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 2", "", null); dbInstance.commitAndCloseSession(); Assert.assertNotNull(re); - + RepositoryEntry loadedRe = repositoryEntryDao.loadByResourceKey(re.getOlatResource().getKey()); Assert.assertNotNull(loadedRe.getStatistics()); Assert.assertEquals(re.getOlatResource(), loadedRe.getOlatResource()); } - + @Test public void loadByResourceKeys() { RepositoryEntry re1 = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 3a", "", null); RepositoryEntry re2 = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 3b", "", null); dbInstance.commitAndCloseSession(); - + List<Long> resourceKeys = new ArrayList<>(2); resourceKeys.add(re1.getOlatResource().getKey()); resourceKeys.add(re2.getOlatResource().getKey()); - + //load 2 resources List<RepositoryEntry> loadedRes = repositoryEntryDao.loadByResourceKeys(resourceKeys); Assert.assertNotNull(loadedRes); Assert.assertEquals(2, loadedRes.size()); Assert.assertTrue(loadedRes.contains(re1)); Assert.assertTrue(loadedRes.contains(re2)); - + //try with empty list List<RepositoryEntry> emptyRes = repositoryEntryDao.loadByResourceKeys(Collections.<Long>emptyList()); Assert.assertNotNull(emptyRes); Assert.assertEquals(0, emptyRes.size()); } - + @Test public void searchByIdAndRefs() { RepositoryEntry re = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 4", "", null); @@ -104,58 +105,58 @@ public class RepositoryEntryDAOTest extends OlatTestCase { String externalRef = UUID.randomUUID().toString(); re = repositoryManager.setDescriptionAndName(re, null, null, null, null, externalId, externalRef, null, null); dbInstance.commitAndCloseSession(); - + //by primary key List<RepositoryEntry> primaryKeyList = repositoryEntryDao.searchByIdAndRefs(Long.toString(re.getKey())); Assert.assertNotNull(primaryKeyList); Assert.assertEquals(1, primaryKeyList.size()); Assert.assertEquals(re, primaryKeyList.get(0)); - + //by soft key List<RepositoryEntry> softKeyList = repositoryEntryDao.searchByIdAndRefs(re.getSoftkey()); Assert.assertNotNull(softKeyList); Assert.assertEquals(1, softKeyList.size()); Assert.assertEquals(re, softKeyList.get(0)); - + //by resourceable id key List<RepositoryEntry> resourceableIdList = repositoryEntryDao.searchByIdAndRefs(Long.toString(re.getResourceableId())); Assert.assertNotNull(resourceableIdList); Assert.assertEquals(1, resourceableIdList.size()); Assert.assertEquals(re, resourceableIdList.get(0)); - + //by resource resourceable id Long resResourceableId = re.getOlatResource().getResourceableId(); List<RepositoryEntry> resResourceableIdList = repositoryEntryDao.searchByIdAndRefs(resResourceableId.toString()); Assert.assertNotNull(resResourceableIdList); Assert.assertEquals(1, resResourceableIdList.size()); Assert.assertEquals(re, resResourceableIdList.get(0)); - + //by external id List<RepositoryEntry> externalIdList = repositoryEntryDao.searchByIdAndRefs(externalId); Assert.assertNotNull(externalIdList); Assert.assertEquals(1, externalIdList.size()); Assert.assertEquals(re, externalIdList.get(0)); - + //by external ref List<RepositoryEntry> externalRefList = repositoryEntryDao.searchByIdAndRefs(externalRef); Assert.assertNotNull(externalRefList); Assert.assertEquals(1, externalRefList.size()); Assert.assertEquals(re, externalRefList.get(0)); - + } - + @Test public void getAllRepositoryEntries() { RepositoryEntry re = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 4", "", null); dbInstance.commitAndCloseSession(); Assert.assertNotNull(re); - + List<RepositoryEntry> allRes = repositoryEntryDao.getAllRepositoryEntries(0, 25); Assert.assertNotNull(allRes); Assert.assertFalse(allRes.isEmpty()); Assert.assertTrue(allRes.size() < 26); } - + @Test public void loadRepositoryEntryResource() { RepositoryEntry re = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 5", "", null); @@ -163,12 +164,12 @@ public class RepositoryEntryDAOTest extends OlatTestCase { Assert.assertNotNull(re); Assert.assertNotNull(re.getSoftkey()); Assert.assertNotNull(re.getOlatResource()); - + OLATResource loadedResource = repositoryEntryDao.loadRepositoryEntryResource(re.getKey()); Assert.assertNotNull(loadedResource); Assert.assertEquals(re.getOlatResource(), loadedResource); } - + @Test public void loadRepositoryEntryResourceBySoftKey() { RepositoryEntry re = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 5", "", null); @@ -176,9 +177,69 @@ public class RepositoryEntryDAOTest extends OlatTestCase { Assert.assertNotNull(re); Assert.assertNotNull(re.getSoftkey()); Assert.assertNotNull(re.getOlatResource()); - + OLATResource loadedResource = repositoryEntryDao.loadRepositoryEntryResourceBySoftKey(re.getSoftkey()); Assert.assertNotNull(loadedResource); Assert.assertEquals(re.getOlatResource(), loadedResource); } + + @Test + public void loadRepositoryEntriesByExternalId() { + String externalId = "myExternalId"; + + // remove old test date + String query = "update repositoryentry as v set v.externalId=null where v.externalId=:externalId"; + dbInstance.getCurrentEntityManager() + .createQuery(query) + .setParameter("externalId", externalId) + .executeUpdate(); + + // insert test data + RepositoryEntry re1 = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 7a", "", null); + re1.setExternalId(externalId); + repositoryService.update(re1); + RepositoryEntry re2 = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 7b", "", null); + re2.setExternalId(externalId); + repositoryService.update(re2); + dbInstance.commitAndCloseSession(); + + Collection<RepositoryEntry> entries = repositoryEntryDao.loadRepositoryEntriesByExternalId(externalId); + Assert.assertNotNull(entries); + Assert.assertEquals(2, entries.size()); + + //try with null + Collection<RepositoryEntry> emptyRes = repositoryEntryDao.loadRepositoryEntriesByExternalId(null); + Assert.assertNotNull(emptyRes); + Assert.assertEquals(0, emptyRes.size()); + } + + @Test + public void loadRepositoryEntriesByExternalRef() { + String externalRef = "myExternalRef"; + + // remove old test date + String query = "update repositoryentry as v set v.externalRef=null where v.externalRef=:externalRef"; + dbInstance.getCurrentEntityManager() + .createQuery(query) + .setParameter("externalRef", externalRef) + .executeUpdate(); + + // insert test data + RepositoryEntry re1 = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 8a", "", null); + re1.setExternalRef(externalRef); + repositoryService.update(re1); + RepositoryEntry re2 = repositoryService.create("Rei Ayanami", "-", "Repository entry DAO Test 8b", "", null); + re2.setExternalRef(externalRef); + repositoryService.update(re2); + dbInstance.commitAndCloseSession(); + + Collection<RepositoryEntry> entries = repositoryEntryDao.loadRepositoryEntriesByExternalRef(externalRef); + Assert.assertNotNull(entries); + Assert.assertEquals(2, entries.size()); + + //try with null + Collection<RepositoryEntry> emptyRes = repositoryEntryDao.loadRepositoryEntriesByExternalRef(null); + Assert.assertNotNull(emptyRes); + Assert.assertEquals(0, emptyRes.size()); + } } \ No newline at end of file diff --git a/src/test/java/org/olat/resource/accesscontrol/ACFrontendManagerTest.java b/src/test/java/org/olat/resource/accesscontrol/ACFrontendManagerTest.java index 110d463d5948bbe05aa4303cee5dc8a3949d9f31..89bc082f964d5444bd5a380980357fd4b41f029b 100644 --- a/src/test/java/org/olat/resource/accesscontrol/ACFrontendManagerTest.java +++ b/src/test/java/org/olat/resource/accesscontrol/ACFrontendManagerTest.java @@ -47,22 +47,23 @@ import org.olat.resource.accesscontrol.manager.ACMethodDAO; import org.olat.resource.accesscontrol.manager.ACOfferDAO; import org.olat.resource.accesscontrol.model.AccessMethod; import org.olat.resource.accesscontrol.model.FreeAccessMethod; +import org.olat.resource.accesscontrol.model.TokenAccessMethod; import org.olat.resource.accesscontrol.provider.paypal.model.PaypalAccessMethod; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; /** - * + * * Description:<br> * Test the frontend manager - * + * * <P> * Initial Date: 18 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public class ACFrontendManagerTest extends OlatTestCase { - + @Autowired private DB dbInstance; @Autowired @@ -85,7 +86,7 @@ public class ACFrontendManagerTest extends OlatTestCase { private ACMethodDAO acMethodManager; @Autowired private AccessControlModule acModule; - + @Test public void testManagers() { assertNotNull(acOfferManager); @@ -95,19 +96,27 @@ public class ACFrontendManagerTest extends OlatTestCase { assertNotNull(repositoryManager); assertNotNull(securityManager); } - + @Test public void testRepoWorkflow() { //create a repository entry RepositoryEntry re = createRepositoryEntry(); assertNotNull(re); - + //create and save an offer Offer offer = acService.createOffer(re.getOlatResource(), "TestRepoWorkflow"); assertNotNull(offer); offer = acService.save(offer); dbInstance.commitAndCloseSession(); - + + //create a link offer to method + List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); + AccessMethod method = methods.get(0); + OfferAccess access = acMethodManager.createOfferAccess(offer, method); + acMethodManager.save(access); + + dbInstance.commitAndCloseSession(); + //retrieve the offer List<Offer> offers = acService.findOfferByResource(re.getOlatResource(), true, null); assertEquals(1, offers.size()); @@ -116,7 +125,7 @@ public class ACFrontendManagerTest extends OlatTestCase { assertNotNull(savedOffer.getResource()); assertTrue(re.getOlatResource().equalsByPersistableKey(savedOffer.getResource())); } - + /** * Test free access to a group without waiting list */ @@ -126,23 +135,23 @@ public class ACFrontendManagerTest extends OlatTestCase { Identity id = JunitTestHelper.createAndPersistIdentityAsUser("agp-" + UUID.randomUUID().toString()); BusinessGroup group = businessGroupService.createBusinessGroup(null, "Free group", "Really free", null, null, false, false, null); Offer offer = acService.createOffer(group.getResource(), "FreeGroup"); - offer = acService.save(offer); + offer = acService.save(offer); List<AccessMethod> freeMethods = acMethodManager.getAvailableMethodsByType(FreeAccessMethod.class); OfferAccess offerAccess = acService.createOfferAccess(offer, freeMethods.get(0)); Assert.assertNotNull(offerAccess); dbInstance.commitAndCloseSession(); - + //access it AccessResult result = acService.accessResource(id, offerAccess, null); Assert.assertNotNull(result); Assert.assertTrue(result.isAccessible()); dbInstance.commitAndCloseSession(); - + //is id a participant? boolean participant = businessGroupRelationDao.hasRole(id, group, GroupRoles.participant.name()); Assert.assertTrue(participant); } - + /** * Test free access to a group without waiting list and which is full */ @@ -155,27 +164,27 @@ public class ACFrontendManagerTest extends OlatTestCase { BusinessGroup group = businessGroupService.createBusinessGroup(null, "Free group", "But you must wait", new Integer(0), new Integer(2), false, false, null); businessGroupRelationDao.addRole(id1, group, GroupRoles.participant.name()); businessGroupRelationDao.addRole(id2, group, GroupRoles.participant.name()); - + Offer offer = acService.createOffer(group.getResource(), "Free group (waiting)"); - offer = acService.save(offer); + offer = acService.save(offer); List<AccessMethod> freeMethods = acMethodManager.getAvailableMethodsByType(FreeAccessMethod.class); OfferAccess offerAccess = acService.createOfferAccess(offer, freeMethods.get(0)); Assert.assertNotNull(offerAccess); dbInstance.commitAndCloseSession(); - + //access it AccessResult result = acService.accessResource(id3, offerAccess, null); Assert.assertNotNull(result); Assert.assertFalse(result.isAccessible()); dbInstance.commitAndCloseSession(); - + //is id a waiting? boolean participant = businessGroupRelationDao.hasRole(id3, group, GroupRoles.participant.name()); Assert.assertFalse(participant); boolean waiting = businessGroupRelationDao.hasRole(id3, group, GroupRoles.waiting.name()); Assert.assertFalse(waiting); } - + /** * Test free access to a group with waiting list enough place */ @@ -185,25 +194,25 @@ public class ACFrontendManagerTest extends OlatTestCase { Identity id = JunitTestHelper.createAndPersistIdentityAsUser("agp-" + UUID.randomUUID().toString()); BusinessGroup group = businessGroupService.createBusinessGroup(null, "Free group", "But you must wait", new Integer(0), new Integer(10), true, false, null); Offer offer = acService.createOffer(group.getResource(), "Free group (waiting)"); - offer = acService.save(offer); + offer = acService.save(offer); List<AccessMethod> freeMethods = acMethodManager.getAvailableMethodsByType(FreeAccessMethod.class); OfferAccess offerAccess = acService.createOfferAccess(offer, freeMethods.get(0)); Assert.assertNotNull(offerAccess); dbInstance.commitAndCloseSession(); - + //access it AccessResult result = acService.accessResource(id, offerAccess, null); Assert.assertNotNull(result); Assert.assertTrue(result.isAccessible()); dbInstance.commitAndCloseSession(); - + //is id a waiting? boolean participant = businessGroupRelationDao.hasRole(id, group, GroupRoles.participant.name()); Assert.assertTrue(participant); boolean waiting = businessGroupRelationDao.hasRole(id, group, GroupRoles.waiting.name()); Assert.assertFalse(waiting); } - + /** * Test free access to a group with waiting list enough place */ @@ -216,28 +225,28 @@ public class ACFrontendManagerTest extends OlatTestCase { BusinessGroup group = businessGroupService.createBusinessGroup(null, "Free group", "But you must wait", new Integer(0), new Integer(2), true, false, null); businessGroupRelationDao.addRole(id1, group, GroupRoles.participant.name()); businessGroupRelationDao.addRole(id2, group, GroupRoles.participant.name()); - + Offer offer = acService.createOffer(group.getResource(), "Free group (waiting)"); - offer = acService.save(offer); + offer = acService.save(offer); List<AccessMethod> freeMethods = acMethodManager.getAvailableMethodsByType(FreeAccessMethod.class); OfferAccess offerAccess = acService.createOfferAccess(offer, freeMethods.get(0)); Assert.assertNotNull(offerAccess); dbInstance.commitAndCloseSession(); - + //access it AccessResult result = acService.accessResource(id3, offerAccess, null); Assert.assertNotNull(result); Assert.assertTrue(result.isAccessible()); dbInstance.commitAndCloseSession(); - + //is id a waiting? boolean participant = businessGroupRelationDao.hasRole(id3, group, GroupRoles.participant.name()); Assert.assertFalse(participant); boolean waiting = businessGroupRelationDao.hasRole(id3, group, GroupRoles.waiting.name()); Assert.assertTrue(waiting); } - - + + /** * Test paypal scenario where a user begin the process to pay an access * to a group while an administrator is filling the group, @@ -257,40 +266,40 @@ public class ACFrontendManagerTest extends OlatTestCase { BusinessGroup group = businessGroupService.createBusinessGroup(null, "Free group", "But you must wait", new Integer(0), new Integer(2), true, false, null); Offer offer = acService.createOffer(group.getResource(), "Free group (waiting)"); - offer = acService.save(offer); + offer = acService.save(offer); List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(PaypalAccessMethod.class); Assert.assertFalse(methods.isEmpty()); OfferAccess offerAccess = acService.createOfferAccess(offer, methods.get(0)); Assert.assertNotNull(offerAccess); dbInstance.commitAndCloseSession(); - + //id1 start payment process boolean reserved = acService.reserveAccessToResource(id1, offerAccess); Assert.assertTrue(reserved); dbInstance.commitAndCloseSession(); - + //admin fill the group businessGroupRelationDao.addRole(id2, group, GroupRoles.participant.name()); businessGroupRelationDao.addRole(id3, group, GroupRoles.participant.name()); dbInstance.commitAndCloseSession(); - + //id1 finish the process AccessResult result = acService.accessResource(id1, offerAccess, null); Assert.assertNotNull(result); Assert.assertTrue(result.isAccessible()); dbInstance.commitAndCloseSession(); - + //is id a waiting? boolean participant = businessGroupRelationDao.hasRole(id1, group, GroupRoles.participant.name()); Assert.assertTrue(participant); boolean waiting = businessGroupRelationDao.hasRole(id1, group, GroupRoles.waiting.name()); Assert.assertFalse(waiting); - + if(!enabled) { acModule.setPaypalEnabled(false); } } - + @Test public void testPaiedAccesToBusinessGroup_full() { //enable paypal @@ -306,7 +315,7 @@ public class ACFrontendManagerTest extends OlatTestCase { BusinessGroup group = businessGroupService.createBusinessGroup(null, "Free group", "But you must wait", new Integer(0), new Integer(2), false, false, null); Offer offer = acService.createOffer(group.getResource(), "Free group (waiting)"); - offer = acService.save(offer); + offer = acService.save(offer); List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(PaypalAccessMethod.class); Assert.assertFalse(methods.isEmpty()); OfferAccess offerAccess = acService.createOfferAccess(offer, methods.get(0)); @@ -321,21 +330,21 @@ public class ACFrontendManagerTest extends OlatTestCase { //id1 try to reserve a place before the payment process boolean reserved = acService.reserveAccessToResource(id1, offerAccess); Assert.assertFalse(reserved); - + if(!enabled) { acModule.setPaypalEnabled(false); } } - + @Test public void makeAccessible() { Identity id = JunitTestHelper.createAndPersistIdentityAsUser("acc-" + UUID.randomUUID()); List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(FreeAccessMethod.class); AccessMethod method = methods.get(0); - + RepositoryEntry re = createRepositoryEntry(); Assert.assertNotNull(re); - + //create an offer to buy OLATResource randomOres = re.getOlatResource(); Offer offer = acService.createOffer(randomOres, "Test auto access"); @@ -344,15 +353,15 @@ public class ACFrontendManagerTest extends OlatTestCase { offer = acService.save(offer); acService.saveOfferAccess(link); dbInstance.commit(); - + long start = System.nanoTime(); AccessResult acResult = acService.isAccessible(re, id, false, true); Assert.assertNotNull(acResult); - Assert.assertTrue(acResult.isAccessible()); + Assert.assertTrue(acResult.isAccessible()); dbInstance.commit(); CodeHelper.printNanoTime(start, "One click"); } - + private RepositoryEntry createRepositoryEntry() { //create a repository entry OLATResourceable resourceable = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); diff --git a/src/test/java/org/olat/resource/accesscontrol/ACMethodManagerTest.java b/src/test/java/org/olat/resource/accesscontrol/ACMethodManagerTest.java index 1baef22cfe3e263e960cfe13291e3e9aa238564f..ad635fa556fa1ee8f8e6542cacb160306f9223de 100644 --- a/src/test/java/org/olat/resource/accesscontrol/ACMethodManagerTest.java +++ b/src/test/java/org/olat/resource/accesscontrol/ACMethodManagerTest.java @@ -21,6 +21,7 @@ package org.olat.resource.accesscontrol; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -44,15 +45,16 @@ import org.olat.resource.accesscontrol.manager.ACOfferDAO; import org.olat.resource.accesscontrol.model.AccessMethod; import org.olat.resource.accesscontrol.model.FreeAccessMethod; import org.olat.resource.accesscontrol.model.TokenAccessMethod; +import org.olat.shibboleth.manager.ShibbolethAutoAccessMethod; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; /** - * + * * Description:<br> * Test the payment manager - * + * * <P> * Initial Date: 18 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com @@ -61,29 +63,30 @@ public class ACMethodManagerTest extends OlatTestCase { private static Identity ident1; private static boolean isInitialized = false; - + @Autowired private DB dbInstance; - + @Autowired private ACOfferDAO acOfferManager; - + @Autowired private ACService acService; - + @Autowired private ACMethodDAO acMethodManager; @Autowired private OLATResourceManager resourceManager; - + @Before public void setUp() { if(!isInitialized) { ident1 = JunitTestHelper.createAndPersistIdentityAsRndUser("ac-method-mgr"); } + acMethodManager.enableMethod(ShibbolethAutoAccessMethod.class, true); } - + @Test public void testManagers() { assertNotNull(acOfferManager); @@ -91,34 +94,41 @@ public class ACMethodManagerTest extends OlatTestCase { assertNotNull(dbInstance); assertNotNull(acMethodManager); } - + @Test public void testTokenMethod() { List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); assertNotNull(methods); assertEquals(1, methods.size()); } - + @Test public void testFreeMethod() { List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(FreeAccessMethod.class); assertNotNull(methods); assertEquals(1, methods.size()); } - + + @Test + public void testAutoShibMethod() { + List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(ShibbolethAutoAccessMethod.class); + assertNotNull(methods); + assertEquals(1, methods.size()); + } + @Test public void testStandardMethods() { Roles roles = new Roles(false, false, false, true, false, false, false); List<AccessMethod> methods = acMethodManager.getAvailableMethods(ident1, roles); assertNotNull(methods); assertTrue(methods.size() >= 2); - + Set<String> duplicateTypes = new HashSet<>(); - + boolean foundFree = false; boolean foundToken = false; for(AccessMethod method:methods) { - Assert.assertFalse(duplicateTypes.contains(method.getType())); + Assert.assertFalse(duplicateTypes.contains(method.getType())); if(method instanceof FreeAccessMethod) { foundFree = true; } else if(method instanceof TokenAccessMethod) { @@ -131,7 +141,58 @@ public class ACMethodManagerTest extends OlatTestCase { assertTrue(foundFree); assertTrue(foundToken); } - + + @Test + public void testIsValidMethodAvailable() { + //create a resource and an offer + OLATResource randomOres = createResource(); + Offer offer = acService.createOffer(randomOres, "TestIsValidMethodAvailable"); + offer = acService.save(offer); + dbInstance.commitAndCloseSession(); + + //create a link offer to gui method + List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); + AccessMethod method = methods.get(0); + OfferAccess access = acMethodManager.createOfferAccess(offer, method); + acMethodManager.save(access); + + //create a link offer to gui method + List<AccessMethod> methodsNonGUI = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); + AccessMethod methodNonGUI = methodsNonGUI.get(0); + OfferAccess accessNonGUI = acMethodManager.createOfferAccess(offer, methodNonGUI); + acMethodManager.save(accessNonGUI); + + dbInstance.commitAndCloseSession(); + + boolean isAvailable = acMethodManager.isValidMethodAvailable(randomOres, null); + + assertTrue(isAvailable); + } + + @Test + public void testIsValidMethodAvailable_nonGui() { + //create a resource and an offer + OLATResource randomOres = createResource(); + Offer offer = acService.createOffer(randomOres, "TestIsValidMethodAvailableNonGui"); + offer = acService.save(offer); + dbInstance.commitAndCloseSession(); + + //create a link offer to method + List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(ShibbolethAutoAccessMethod.class); + assertNotNull(methods); + assertEquals(1, methods.size()); + + AccessMethod method = methods.get(0); + OfferAccess access = acMethodManager.createOfferAccess(offer, method); + acMethodManager.save(access); + + dbInstance.commitAndCloseSession(); + + boolean isAvailable = acMethodManager.isValidMethodAvailable(randomOres, null); + + assertFalse(isAvailable); + } + @Test public void testOfferAccess() { //create a resource and an offer @@ -139,18 +200,18 @@ public class ACMethodManagerTest extends OlatTestCase { Offer offer = acService.createOffer(randomOres, "TestOfferAccess"); offer = acService.save(offer); dbInstance.commitAndCloseSession(); - + //create a link offer to method List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); assertNotNull(methods); assertEquals(1, methods.size()); - + AccessMethod method = methods.get(0); OfferAccess access = acMethodManager.createOfferAccess(offer, method); acMethodManager.save(access); dbInstance.commitAndCloseSession(); - + //retrieve the link List<OfferAccess> retrievedOfferAccess = acMethodManager.getOfferAccess(offer, true); assertNotNull(retrievedOfferAccess); @@ -162,49 +223,49 @@ public class ACMethodManagerTest extends OlatTestCase { assertNotNull(retrievedAccess.getOffer()); Assert.assertEquals(offer, retrievedAccess.getOffer()); } - + @Test public void testSeveralOfferAccess() { //create some resources and offers OLATResource randomOres1 = createResource(); Offer offer1 = acService.createOffer(randomOres1, "TestSeveralOfferAccess 1"); offer1 = acService.save(offer1); - + OLATResource randomOres2 = createResource(); Offer offer2 = acService.createOffer(randomOres2, "TestSeveralOfferAccess 2"); offer2 = acService.save(offer2); - + OLATResource randomOres3 = createResource(); Offer offer3 = acService.createOffer(randomOres3, "TestSeveralOfferAccess 3"); offer3 = acService.save(offer3); - + dbInstance.commitAndCloseSession(); - + //create a link offer to method List<AccessMethod> tokenMethods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); assertNotNull(tokenMethods); assertEquals(1, tokenMethods.size()); AccessMethod tokenMethod = tokenMethods.get(0); - + List<AccessMethod> freeMethods = acMethodManager.getAvailableMethodsByType(FreeAccessMethod.class); assertNotNull(freeMethods); assertEquals(1, freeMethods.size()); AccessMethod freeMethod = freeMethods.get(0); - + OfferAccess access1 = acMethodManager.createOfferAccess(offer1, tokenMethod); acMethodManager.save(access1); - + OfferAccess access2 = acMethodManager.createOfferAccess(offer2, tokenMethod); acMethodManager.save(access2); - + OfferAccess access3_1 = acMethodManager.createOfferAccess(offer3, tokenMethod); acMethodManager.save(access3_1); - + OfferAccess access3_2 = acMethodManager.createOfferAccess(offer3, freeMethod); acMethodManager.save(access3_2); dbInstance.commitAndCloseSession(); - + //retrieve the link to offer 1 List<OfferAccess> retrievedOfferAccess = acMethodManager.getOfferAccess(offer1, true); assertNotNull(retrievedOfferAccess); @@ -216,8 +277,8 @@ public class ACMethodManagerTest extends OlatTestCase { assertNotNull(retrievedAccess.getOffer()); assertEquals(offer1, retrievedAccess.getOffer()); dbInstance.commitAndCloseSession(); - - + + {//retrieve the links to offer 3 List<OfferAccess> retrievedOfferAccess3 = acMethodManager.getOfferAccess(offer3, true); assertNotNull(retrievedOfferAccess3); @@ -244,16 +305,16 @@ public class ACMethodManagerTest extends OlatTestCase { } assertNotNull(retrievedAccess3_2.getOffer()); assertEquals(offer3, retrievedAccess3_2.getOffer()); - + dbInstance.commitAndCloseSession(); } - + {//retrieve the links by resource - List<Offer> offers = new ArrayList<Offer>(); + List<Offer> offers = new ArrayList<>(); offers.add(offer1); offers.add(offer2); offers.add(offer3); - + List<OfferAccess> retrievedAllOfferAccess = acMethodManager.getOfferAccess(offers, true); assertNotNull(retrievedAllOfferAccess); assertEquals(4, retrievedAllOfferAccess.size()); @@ -261,7 +322,7 @@ public class ACMethodManagerTest extends OlatTestCase { dbInstance.commitAndCloseSession(); } } - + @Test public void testDeleteOfferAccess() { //create some resources and offers @@ -269,38 +330,38 @@ public class ACMethodManagerTest extends OlatTestCase { Offer offer = acService.createOffer(randomOres1, "TestDeleteOfferAccess"); offer = acService.save(offer); dbInstance.commitAndCloseSession(); - + //create two link offer to method List<AccessMethod> tokenMethods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); assertNotNull(tokenMethods); assertEquals(1, tokenMethods.size()); AccessMethod tokenMethod = tokenMethods.get(0); - + List<AccessMethod> freeMethods = acMethodManager.getAvailableMethodsByType(FreeAccessMethod.class); assertNotNull(freeMethods); assertEquals(1, freeMethods.size()); AccessMethod freeMethod = freeMethods.get(0); - - + + OfferAccess access3_1 = acMethodManager.createOfferAccess(offer, tokenMethod); acMethodManager.save(access3_1); - + OfferAccess access3_2 = acMethodManager.createOfferAccess(offer, freeMethod); acMethodManager.save(access3_2); dbInstance.commitAndCloseSession(); - + //delete one of them acMethodManager.delete(access3_2); dbInstance.commitAndCloseSession(); - - //retrieve + + //retrieve List<OfferAccess> retrievedOfferAccess = acMethodManager.getOfferAccess(offer, true); assertNotNull(retrievedOfferAccess); assertEquals(1, retrievedOfferAccess.size()); assertEquals(access3_1, retrievedOfferAccess.get(0)); } - + private OLATResource createResource() { //create a repository entry OLATResourceable resourceable = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); diff --git a/src/test/java/org/olat/resource/accesscontrol/ACOfferManagerTest.java b/src/test/java/org/olat/resource/accesscontrol/ACOfferManagerTest.java index 350c0c29edb1d365fb288ebc5bea2dd6320c06d3..9587a02360d655ecd32c5d6ead57d1a18d8334e1 100644 --- a/src/test/java/org/olat/resource/accesscontrol/ACOfferManagerTest.java +++ b/src/test/java/org/olat/resource/accesscontrol/ACOfferManagerTest.java @@ -38,16 +38,19 @@ import org.olat.core.id.OLATResourceable; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceImpl; import org.olat.resource.OLATResourceManager; +import org.olat.resource.accesscontrol.manager.ACMethodDAO; import org.olat.resource.accesscontrol.manager.ACOfferDAO; +import org.olat.resource.accesscontrol.model.AccessMethod; import org.olat.resource.accesscontrol.model.OfferImpl; +import org.olat.resource.accesscontrol.model.TokenAccessMethod; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; /** - * + * * Description:<br> - * + * * <P> * Initial Date: 18 avr. 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com @@ -56,28 +59,31 @@ public class ACOfferManagerTest extends OlatTestCase { @Autowired private DB dbInstance; - + @Autowired private ACOfferDAO acOfferManager; - + @Autowired private ACService acService; - + + @Autowired + private ACMethodDAO acMethodManager; + @Test public void testManagers() { assertNotNull(acOfferManager); assertNotNull(acService); } - + @Test public void testSaveOffer() { //create a resource OLATResourceable testOreable = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); OLATResource testOres = OLATResourceManager.getInstance().findOrPersistResourceable(testOreable); assertNotNull(testOres); - + dbInstance.commitAndCloseSession(); - + //create an offer Offer offer = acOfferManager.createOffer(testOres, "TestSaveOffer"); assertNotNull(offer); @@ -92,7 +98,15 @@ public class ACOfferManagerTest extends OlatTestCase { acOfferManager.saveOffer(offer); dbInstance.commitAndCloseSession(); - + + //create a link offer to method + List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); + AccessMethod method = methods.get(0); + OfferAccess access = acMethodManager.createOfferAccess(offer, method); + acMethodManager.save(access); + + dbInstance.commitAndCloseSession(); + //check if the offer is saved List<Offer> offers = acOfferManager.findOfferByResource(testOres, true, null); assertNotNull(offers); @@ -110,41 +124,49 @@ public class ACOfferManagerTest extends OlatTestCase { assertEquals(testOres.getResourceableTypeName(), savedOffer.getResourceTypeName()); assertEquals("TestSaveOffer", savedOffer.getResourceDisplayName()); } - + @Test public void testDeleteOffer() { OLATResourceable testOreable = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); OLATResource testOres = OLATResourceManager.getInstance().findOrPersistResourceable(testOreable); assertNotNull(testOres); - + dbInstance.commitAndCloseSession(); - + //create an offer Offer offer = acOfferManager.createOffer(testOres, "TestDeleteOffer"); assertNotNull(offer); assertEquals(OfferImpl.class, offer.getClass()); //and save the offer acOfferManager.saveOffer(offer); - + dbInstance.commitAndCloseSession(); - + + //create a link offer to method + List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); + AccessMethod method = methods.get(0); + OfferAccess access = acMethodManager.createOfferAccess(offer, method); + acMethodManager.save(access); + + dbInstance.commitAndCloseSession(); + //retrieve the offer List<Offer> offers = acOfferManager.findOfferByResource(testOres, true, null); assertNotNull(offers); assertEquals(1, offers.size()); assertEquals(offer, offers.get(0)); dbInstance.commitAndCloseSession(); - + //delete the offer acOfferManager.deleteOffer(offer); dbInstance.commitAndCloseSession(); - + //try to retrieve the offer List<Offer> noOffers = acOfferManager.findOfferByResource(testOres, true, null); assertNotNull(noOffers); assertEquals(0, noOffers.size()); dbInstance.commitAndCloseSession(); - + //retrieve all offers, deleted too List<Offer> delOffers = acOfferManager.findOfferByResource(testOres, false, null); assertNotNull(delOffers); @@ -153,68 +175,68 @@ public class ACOfferManagerTest extends OlatTestCase { assertEquals(false, delOffers.get(0).isValid()); dbInstance.commitAndCloseSession(); } - + @Test public void testDeleteResource() { //create a random resource OLATResourceable testOreable = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); OLATResource testOres = OLATResourceManager.getInstance().findOrPersistResourceable(testOreable); assertNotNull(testOres); - + dbInstance.commitAndCloseSession(); - + //create an offer Offer offer = acOfferManager.createOffer(testOres, "TestDeleteResource"); assertNotNull(offer); assertEquals(OfferImpl.class, offer.getClass()); //and save the offer acOfferManager.saveOffer(offer); - + dbInstance.commitAndCloseSession(); - + //delete the resource testOres = dbInstance.loadObject(OLATResourceImpl.class, testOres.getKey()); dbInstance.deleteObject(testOres); - + dbInstance.commitAndCloseSession(); - + //load offer by resource -> nothing found List<Offer> retrievedOffers = acOfferManager.findOfferByResource(testOres, true, null); assertNotNull(retrievedOffers); assertEquals(0, retrievedOffers.size()); - + //load offer by key -> found and loaded without error Offer retrievedOffer = acOfferManager.loadOfferByKey(offer.getKey()); assertNotNull(retrievedOffer); assertNull(retrievedOffer.getResource()); assertEquals(offer, retrievedOffer); } - + @Test public void testFilter() { //create resources OLATResourceable testOreable1 = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); OLATResource testOres1 = OLATResourceManager.getInstance().findOrPersistResourceable(testOreable1); assertNotNull(testOres1); - + OLATResourceable testOreable2 = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); OLATResource testOres2 = OLATResourceManager.getInstance().findOrPersistResourceable(testOreable2); assertNotNull(testOres2); - + OLATResourceable testOreable3 = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); OLATResource testOres3 = OLATResourceManager.getInstance().findOrPersistResourceable(testOreable3); assertNotNull(testOres3); - + dbInstance.commitAndCloseSession(); - + //create offers Offer offer1 = acOfferManager.createOffer(testOres1, "TestFilter 1"); Offer offer2 = acOfferManager.createOffer(testOres2, "TestFilter 2"); acOfferManager.saveOffer(offer1); acOfferManager.saveOffer(offer2); - + dbInstance.commitAndCloseSession(); - + //filter by resources List<Long> resourceKeys = new ArrayList<Long>(); resourceKeys.add(testOres1.getKey()); @@ -227,36 +249,36 @@ public class ACOfferManagerTest extends OlatTestCase { assertTrue(filteredKeys.contains(testOres2.getKey())); assertFalse(filteredKeys.contains(testOres3.getKey())); } - + @Test public void testFilterWithDelete() { //create resources OLATResourceable testOreable1 = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); OLATResource testOres1 = OLATResourceManager.getInstance().findOrPersistResourceable(testOreable1); assertNotNull(testOres1); - + OLATResourceable testOreable2 = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); OLATResource testOres2 = OLATResourceManager.getInstance().findOrPersistResourceable(testOreable2); assertNotNull(testOres2); - + OLATResourceable testOreable3 = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); OLATResource testOres3 = OLATResourceManager.getInstance().findOrPersistResourceable(testOreable3); assertNotNull(testOres3); - + dbInstance.commitAndCloseSession(); - + //create offers Offer offer1 = acOfferManager.createOffer(testOres1, "TestFilterWithDelete 1"); Offer offer2 = acOfferManager.createOffer(testOres2, "TestFilterWithDelete 2"); acOfferManager.saveOffer(offer1); acOfferManager.saveOffer(offer2); - + dbInstance.commitAndCloseSession(); - + //delete resource of offer 2 testOres2 = dbInstance.loadObject(OLATResourceImpl.class, testOres2.getKey()); dbInstance.deleteObject(testOres2); - + //filter by resources List<Long> resourceKeys = new ArrayList<Long>(); resourceKeys.add(testOres1.getKey()); diff --git a/src/test/java/org/olat/resource/accesscontrol/ACReservationDAOTest.java b/src/test/java/org/olat/resource/accesscontrol/ACReservationDAOTest.java index 312b24fe930bad03ad381d2817a986d6eae79d03..7058754d1c71ba9bf8f5ba3909ad5748449d9718 100644 --- a/src/test/java/org/olat/resource/accesscontrol/ACReservationDAOTest.java +++ b/src/test/java/org/olat/resource/accesscontrol/ACReservationDAOTest.java @@ -35,6 +35,7 @@ import org.olat.resource.OLATResource; import org.olat.resource.accesscontrol.manager.ACReservationDAO; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; +import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; @@ -57,7 +58,7 @@ public class ACReservationDAOTest extends OlatTestCase { @Before public void interruptReservationJob() { try { - scheduler.pauseJob("acReservationCleanupJobDetail", Scheduler.DEFAULT_GROUP); + scheduler.pauseJob(new JobKey("acReservationCleanupJobDetail", Scheduler.DEFAULT_GROUP)); } catch (SchedulerException e) { log.error("Cannot intterupt the reservation job.", e); } diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAOTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAOTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5209ce5e456205ef75436bcf8e8993d27fe33993 --- /dev/null +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAOTest.java @@ -0,0 +1,311 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.resource.accesscontrol.manager.ACMethodDAO; +import org.olat.resource.accesscontrol.model.AccessMethod; +import org.olat.resource.accesscontrol.model.FreeAccessMethod; +import org.olat.resource.accesscontrol.model.TokenAccessMethod; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder.Status; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 14.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class AdvanceOrderDAOTest extends OlatTestCase { + + private static final IdentifierKey IDENTIFIER_KEY = IdentifierKey.externalId; + private static final String IDENTIFIER_VALUE = "identifierValue"; + private Identity identity; + private AccessMethod freeMethod; + private AccessMethod tokenMethod; + + @Autowired + private DB dbInstance; + @Autowired + private ACMethodDAO acMethodDAO; + + @Autowired + private AdvanceOrderDAO sut; + + @Before + public void emptyTable() { + String statement = "delete from advanceOrder"; + dbInstance.getCurrentEntityManager().createQuery(statement).executeUpdate(); + } + + @Before + public void setUp() { + acMethodDAO.enableMethod(FreeAccessMethod.class, true); + List<AccessMethod> freeMethods = acMethodDAO.getAvailableMethodsByType(FreeAccessMethod.class); + freeMethod = freeMethods.get(0); + acMethodDAO.enableMethod(TokenAccessMethod.class, true); + List<AccessMethod> tokenMethods = acMethodDAO.getAvailableMethodsByType(TokenAccessMethod.class); + tokenMethod = tokenMethods.get(0); + + identity = JunitTestHelper.createAndPersistIdentityAsRndUser("user"); + } + + @Test + public void shouldCreateAdvanceOrder() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + + assertThat(advanceOrder.getKey()).isNull(); + assertThat(advanceOrder.getCreationDate()).isNotNull(); + assertThat(advanceOrder.getLastModified()).isNotNull(); + assertThat(advanceOrder.getIdentity()).isEqualTo(identity); + assertThat(advanceOrder.getIdentifierKey()).isEqualTo(IDENTIFIER_KEY); + assertThat(advanceOrder.getIdentifierValue()).isEqualTo(IDENTIFIER_VALUE); + assertThat(advanceOrder.getMethod()).isEqualTo(freeMethod); + assertThat(advanceOrder.getStatus()).isEqualTo(Status.PENDING); + assertThat(advanceOrder.getStatusModified()).isNotNull(); + } + + @Test + public void shouldSaveNewAdvanceOrder() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + dbInstance.commitAndCloseSession(); + + AdvanceOrder savedAdvanceOrder = sut.save(advanceOrder); + dbInstance.commitAndCloseSession(); + + assertThat(savedAdvanceOrder.getKey()).isNotNull(); + } + + @Test + public void shouldSaveUpdatedAdvanceOrder() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + advanceOrder = sut.save(advanceOrder); + advanceOrder.setStatus(Status.DONE); + + dbInstance.commitAndCloseSession(); + AdvanceOrder savedAdvanceOrder = sut.save(advanceOrder); + dbInstance.commitAndCloseSession(); + + assertThat(savedAdvanceOrder.getStatus()).isEqualTo(Status.DONE); + } + + @Test + public void shouldFindPendingAdvanceOrderForIdentity() { + AdvanceOrder firstPendingAdvanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + sut.save(firstPendingAdvanceOrder); + AdvanceOrder secondPendingAdvanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + sut.save(secondPendingAdvanceOrder); + Identity otherIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("other"); + AdvanceOrder advanceOrderWithOtherIdentity = sut.create(otherIdentity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + sut.save(advanceOrderWithOtherIdentity); + AdvanceOrder doneAdvanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + sut.accomplishAndSave(doneAdvanceOrder); + dbInstance.commitAndCloseSession(); + + Collection<AdvanceOrder> pendingAdvanceOrders = sut.loadPendingAdvanceOrders(identity); + + assertThat(pendingAdvanceOrders).hasSize(2); + } + + @Test + public void shouldFindPendingAdvaceOrderForIdentifiers() { + AdvanceOrder aoMatchingInternalId = sut.create(identity, IdentifierKey.internalId, IDENTIFIER_VALUE, freeMethod); + sut.save(aoMatchingInternalId); + AdvanceOrder aoMatchingExternalId = sut.create(identity, IdentifierKey.externalId, IDENTIFIER_VALUE, freeMethod); + sut.save(aoMatchingExternalId); + AdvanceOrder aoNotMatchingRef = sut.create(identity, IdentifierKey.externalRef, IDENTIFIER_VALUE, freeMethod); + sut.save(aoNotMatchingRef); + AdvanceOrder aoNotMatchingValue = sut.create(identity, IdentifierKey.internalId, "not matching", freeMethod); + sut.save(aoNotMatchingValue); + dbInstance.commitAndCloseSession(); + + Map<IdentifierKey, String> identifiers = new HashMap<>(); + identifiers.put(IdentifierKey.internalId, IDENTIFIER_VALUE); + identifiers.put(IdentifierKey.externalId, IDENTIFIER_VALUE); + Collection<AdvanceOrder> advanceOrders = sut.loadPendingAdvanceOrders(identifiers); + + assertThat(advanceOrders).hasSize(2).contains(aoMatchingInternalId, aoMatchingExternalId); + } + + @Test + public void shouldFindPendingAdvaceOrderForIdentifiersIfNullValues() { + AdvanceOrder aoMatchingInternalId = sut.create(identity, IdentifierKey.internalId, IDENTIFIER_VALUE, freeMethod); + sut.save(aoMatchingInternalId); + AdvanceOrder aoMatchingExternalId = sut.create(identity, IdentifierKey.externalId, IDENTIFIER_VALUE, freeMethod); + sut.save(aoMatchingExternalId); + AdvanceOrder aoNotMatchingRef = sut.create(identity, IdentifierKey.externalRef, IDENTIFIER_VALUE, freeMethod); + sut.save(aoNotMatchingRef); + AdvanceOrder aoNotMatchingValue = sut.create(identity, IdentifierKey.internalId, "not matching", freeMethod); + sut.save(aoNotMatchingValue); + dbInstance.commitAndCloseSession(); + + Map<IdentifierKey, String> identifiers = new HashMap<>(); + identifiers.put(IdentifierKey.internalId, IDENTIFIER_VALUE); + identifiers.put(null, IDENTIFIER_VALUE); + identifiers.put(IdentifierKey.externalId, ""); + Collection<AdvanceOrder> advanceOrders = sut.loadPendingAdvanceOrders(identifiers); + + assertThat(advanceOrders).hasSize(1).contains(aoMatchingInternalId); + } + + @Test + public void shouldDeleteAdvaceOrderByKey() { + AdvanceOrder aoToKeep1 = sut.create(identity, IdentifierKey.internalId, IDENTIFIER_VALUE, freeMethod); + sut.save(aoToKeep1); + AdvanceOrder aoToDelete = sut.create(identity, IdentifierKey.externalId, IDENTIFIER_VALUE, freeMethod); + aoToDelete = sut.save(aoToDelete); + AdvanceOrder aoToKeep2 = sut.create(identity, IdentifierKey.externalRef, IDENTIFIER_VALUE, freeMethod); + sut.save(aoToKeep2); + AdvanceOrder aoToKeep3 = sut.create(identity, IdentifierKey.internalId, "not matching", freeMethod); + sut.save(aoToKeep3); + dbInstance.commitAndCloseSession(); + + sut.deleteAdvanceOrder(aoToDelete); + + assertThat(sut.loadPendingAdvanceOrders(identity)).hasSize(3).doesNotContain(aoToDelete); + } + + @Test + public void shouldDeleteAdvanceOrdersByIdentity() { + AdvanceOrder aoPending = sut.create(identity, IdentifierKey.internalId, IDENTIFIER_VALUE, freeMethod); + sut.save(aoPending); + AdvanceOrder aoDone = sut.create(identity, IdentifierKey.externalId, IDENTIFIER_VALUE, freeMethod); + sut.save(aoDone); + sut.accomplishAndSave(aoDone); + Identity otherIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("otheruser"); + AdvanceOrder aoOtherIdentity = sut.create(otherIdentity, IdentifierKey.internalId, "not matching", freeMethod); + sut.save(aoOtherIdentity); + dbInstance.commitAndCloseSession(); + + sut.deleteAdvanceOrders(identity); + + Collection<AdvanceOrder> aoDeletedUser = loadAllAdvanceOrders(identity); + assertThat(aoDeletedUser).hasSize(0); + Collection<AdvanceOrder> aoActiveUser = loadAllAdvanceOrders(otherIdentity); + assertThat(aoActiveUser).hasSize(1); + } + + private Collection<AdvanceOrder> loadAllAdvanceOrders(Identity identity) { + if (identity == null) return new ArrayList<>(0); + + StringBuilder sb = new StringBuilder(); + sb.append("select advanceOrder from advanceOrder advanceOrder") + .append(" where advanceOrder.identity.key=:identityKey"); + + List<AdvanceOrder> advanceOrder = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), AdvanceOrder.class) + .setParameter("identityKey", identity.getKey()) + .getResultList(); + + return advanceOrder; + } + + @Test + public void shouldMarkAsDoneWhenAccomplished() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + advanceOrder = sut.save(advanceOrder); + + AdvanceOrder accomplishedAdvanceOrder = sut.accomplishAndSave(advanceOrder); + + assertThat(accomplishedAdvanceOrder.getStatus()).isEqualTo(Status.DONE); + } + + @Test + public void shouldNotMarkedAsDoneIfNoOffer() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + advanceOrder = sut.save(advanceOrder); + + AdvanceOrder accomplishedAdvanceOrder = sut.accomplishAndSave(advanceOrder); + + assertThat(accomplishedAdvanceOrder.getStatus()).isEqualTo(advanceOrder.getStatus()); + } + + @Test + public void shouldExistIfAllValuesTheSame() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + sut.save(advanceOrder); + dbInstance.commitAndCloseSession(); + + boolean exists = sut.exists(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + + assertThat(exists).isTrue(); + } + + @Test + public void shouldNotExistIfTheIdentityIsDifferent() { + Identity otherIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("other"); + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + sut.save(advanceOrder); + dbInstance.commitAndCloseSession(); + + boolean exists = sut.exists(otherIdentity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + + assertThat(exists).isFalse(); + } + + + @Test + public void shouldNotExistIfTheIdentifierKeyIsDifferent() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + sut.save(advanceOrder); + dbInstance.commitAndCloseSession(); + + boolean exists = sut.exists(identity, IdentifierKey.internalId, IDENTIFIER_VALUE, freeMethod); + + assertThat(exists).isFalse(); + } + + @Test + public void shouldNotExistIfTheIdentifierValueIsDifferent() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + sut.save(advanceOrder); + dbInstance.commitAndCloseSession(); + + boolean exists = sut.exists(identity, IDENTIFIER_KEY, "otherValue", freeMethod); + + assertThat(exists).isFalse(); + } + + @Test + public void shouldNotExistIfTheHandlerTypeIsDifferent() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + sut.save(advanceOrder); + dbInstance.commitAndCloseSession(); + + boolean exists = sut.exists(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, tokenMethod); + + assertThat(exists).isFalse(); + } +} diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImplTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..609f7ba3895d6ce424775a975f0f4830589c9a40 --- /dev/null +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImplTest.java @@ -0,0 +1,285 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.basesecurity.GroupRoles; +import org.olat.basesecurity.IdentityImpl; +import org.olat.core.id.Identity; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.manager.RepositoryEntryRelationDAO; +import org.olat.resource.OLATResource; +import org.olat.resource.accesscontrol.ACService; +import org.olat.resource.accesscontrol.AccessControlModule; +import org.olat.resource.accesscontrol.Offer; +import org.olat.resource.accesscontrol.OfferAccess; +import org.olat.resource.accesscontrol.model.AccessMethod; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder.Status; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrderInput; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.olat.resource.accesscontrol.provider.auto.model.AdvanceOrderImpl; +import org.olat.resource.accesscontrol.provider.auto.model.AutoAccessMethod; + +/** + * + * Initial date: 14.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class AutoAccessManagerImplTest { + + private static final Class<? extends AutoAccessMethod> METHOD_CLASS = AutoAccessMethod.class; + private static final IdentityImpl IDENTITY = new IdentityImpl(); + private static final String FIRST_VALUE = "firstValue"; + private static final String SECOND_VALUE = "secondvalue"; + private static final String THIRD_VALUE = "third value"; + private static final String DISPLAY_NAME = "displayName"; + + @Mock + private IdentifierHandler identifierHandlerMock; + @Mock + private InputValidator inputValidator; + @Mock + private SplitterFactory splitterFactory; + @Mock + private IdentifierValueSplitter splitterMock; + @Mock + private AdvanceOrderDAO advanceOrderDaoMock; + @Mock + private ACService acServiceMock; + @Mock + private AccessControlModule acModuleMock; + @Mock + private AdvanceOrderInput advanceOrderInputMock; + @Mock + private RepositoryEntryRelationDAO repositoryEntryRelationDaoMock; + @Mock + private RepositoryEntry repositoryEntryMock; + private List<RepositoryEntry> listWithRespositotyEntryMock; + @Mock + private OLATResource resourceMock; + + private AutoAccessMethod accessMethodDummy; + + @InjectMocks + private AutoAccessManagerImpl sut = new AutoAccessManagerImpl(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + accessMethodDummy = mock(AutoAccessMethod.class); + List<AccessMethod> accessMethods = Arrays.asList(accessMethodDummy); + when(acServiceMock.getAvailableMethodsByType(AutoAccessMethod.class)).thenReturn(accessMethods); + + doReturn(METHOD_CLASS).when(advanceOrderInputMock).getMethodClass(); + when(advanceOrderInputMock.getIdentity()).thenReturn(IDENTITY); + Set<IdentifierKey> keys = new HashSet<>(Arrays.asList(IdentifierKey.internalId, IdentifierKey.externalId)); + when(advanceOrderInputMock.getKeys()).thenReturn(keys); + when(advanceOrderInputMock.getSplitterType()).thenReturn("splitter"); + + when(acModuleMock.isAutoEnabled()).thenReturn(true); + + when(inputValidator.isValid(advanceOrderInputMock)).thenReturn(true); + + when(splitterFactory.getSplitter(anyString())).thenReturn(splitterMock); + List<String> values = Arrays.asList(FIRST_VALUE, SECOND_VALUE, THIRD_VALUE); + when(splitterMock.split(isNull())).thenReturn(values); + + when(repositoryEntryMock.getDisplayname()).thenReturn(DISPLAY_NAME); + when(repositoryEntryMock.getOlatResource()).thenReturn(resourceMock); + listWithRespositotyEntryMock = new ArrayList<>(); + listWithRespositotyEntryMock.add(repositoryEntryMock); + } + + private Collection<AdvanceOrder> getPendingAdvanceOrders() { + Collection<AdvanceOrder> advanceOrders; + AdvanceOrderImpl ao1 = new AdvanceOrderImpl(); + ao1.setIdentifierKey(IdentifierKey.internalId); + ao1.setIdentifierValue("abc"); + ao1.setStatus(Status.PENDING); + ao1.setMethod(accessMethodDummy); + ao1.setIdentity(IDENTITY); + AdvanceOrderImpl ao2 = new AdvanceOrderImpl(); + ao2.setIdentifierKey(IdentifierKey.internalId); + ao2.setIdentifierValue("abc3"); + ao2.setStatus(Status.PENDING); + ao2.setMethod(accessMethodDummy); + ao2.setIdentity(IDENTITY); + advanceOrders = Arrays.asList(ao1, ao2); + return advanceOrders; + } + + @Test + public void shouldNotCreatAdvanceEntriesIfInputIsNotValid() { + when(inputValidator.isValid(advanceOrderInputMock)).thenReturn(false); + + sut.createAdvanceOrders(advanceOrderInputMock); + + verify(advanceOrderDaoMock, never()).create(any(Identity.class), any(IdentifierKey.class), anyString(), any(AutoAccessMethod.class)); + } + + @Test + public void shouldAddAnAdvanceEntryForEveryKeyValueCombination() { + sut.createAdvanceOrders(advanceOrderInputMock); + + verify(advanceOrderDaoMock, times(6)).create(any(Identity.class), any(IdentifierKey.class), anyString(), any(AutoAccessMethod.class)); + } + + @Test + public void shouldAddAdvanceEntryOnlyIfNotExists() { + when(advanceOrderDaoMock.exists(IDENTITY, IdentifierKey.internalId, SECOND_VALUE, accessMethodDummy)).thenReturn(true); + + sut.createAdvanceOrders(advanceOrderInputMock); + + verify(advanceOrderDaoMock, times(5)).create(any(Identity.class), any(IdentifierKey.class), anyString(), any(AutoAccessMethod.class)); + } + + @Test + public void shouldNotGrantAccessIfAlreadyDone() { + Collection<AdvanceOrder> advanceOrders = new ArrayList<>(); + AdvanceOrderImpl doneAdvanceOrder = new AdvanceOrderImpl(); + doneAdvanceOrder.setStatus(Status.DONE); + doneAdvanceOrder.setIdentifierKey(IdentifierKey.externalId); + doneAdvanceOrder.setIdentifierValue("abc"); + advanceOrders.add(doneAdvanceOrder); + + sut.grantAccess(advanceOrders); + + verify(identifierHandlerMock, never()).findRepositoryEntries(any(IdentifierKey.class), anyString()); + } + + @Test + public void shouldNotGrantAccessIfAutoAccessDisabled() { + when(acModuleMock.isAutoEnabled()).thenReturn(false); + + sut.grantAccess(getPendingAdvanceOrders()); + + verify(identifierHandlerMock, never()).findRepositoryEntries(any(IdentifierKey.class), anyString()); + } + + @Test + public void shouldNotGrantAccessIfNoResourceFound() { + when(identifierHandlerMock.findRepositoryEntries(any(IdentifierKey.class), anyString())).thenReturn(null); + + sut.grantAccess(getPendingAdvanceOrders()); + + verify(acServiceMock, never()).createOffer(any(OLATResource.class), anyString()); + verify(acServiceMock, never()).createOfferAccess(any(Offer.class), any(AccessMethod.class)); + verify(acServiceMock, never()).accessResource(any(Identity.class), any(OfferAccess.class), isNull()); + } + + @Test + public void shouldMakeOfferBeforeGrantingAccessIfNotExists() { + when(identifierHandlerMock.findRepositoryEntries(any(IdentifierKey.class), anyString())).thenReturn(listWithRespositotyEntryMock); + when(repositoryEntryRelationDaoMock.hasRole(IDENTITY, repositoryEntryMock, GroupRoles.participant.name())).thenReturn(false); + when(acServiceMock.getValidOfferAccess(any(OLATResource.class), any(AccessMethod.class))).thenReturn(new ArrayList<>()); + Offer offerMock = mock(Offer.class); + when(acServiceMock.createOffer(any(OLATResource.class), anyString())).thenReturn(offerMock); + List<AccessMethod> methods = Arrays.asList(accessMethodDummy); + when(acServiceMock.getAvailableMethodsByType(METHOD_CLASS)).thenReturn(methods); + + Collection<AdvanceOrder> advanceOrders = getPendingAdvanceOrders(); + sut.grantAccess(advanceOrders); + + verify(acServiceMock, times(2)).createOffer(any(OLATResource.class), anyString()); + verify(acServiceMock, times(2)).createOfferAccess(any(Offer.class), isA(AccessMethod.class)); + } + + @Test + public void shouldNotMakeOfferBeforeGrantingAccessIfOfferExists() { + when(identifierHandlerMock.findRepositoryEntries(any(IdentifierKey.class), anyString())).thenReturn(listWithRespositotyEntryMock); + OfferAccess offerAccessDummy = mock(OfferAccess.class); + List<OfferAccess> offerAccess = Arrays.asList(offerAccessDummy); + when(acServiceMock.getValidOfferAccess(any(OLATResource.class), any(AccessMethod.class))).thenReturn(offerAccess); + + sut.grantAccess(getPendingAdvanceOrders()); + + verify(acServiceMock, never()).createOffer(any(OLATResource.class), isNull()); + verify(acServiceMock, never()).createOfferAccess(any(Offer.class), any(AccessMethod.class)); + } + + @Test + public void shouldGrantAccessIfNoAccess() { + when(identifierHandlerMock.findRepositoryEntries(any(IdentifierKey.class), anyString())).thenReturn(listWithRespositotyEntryMock); + OfferAccess offerAccessDummy = mock(OfferAccess.class); + List<OfferAccess> offerAccess = Arrays.asList(offerAccessDummy); + when(acServiceMock.getValidOfferAccess(any(OLATResource.class), any(AccessMethod.class))).thenReturn(offerAccess); + + sut.grantAccess(getPendingAdvanceOrders()); + + verify(acServiceMock, times(2)).accessResource(IDENTITY, offerAccessDummy, null); + } + + @Test + public void shouldNotGrantAccessIfHasAccess() { + when(identifierHandlerMock.findRepositoryEntries(any(IdentifierKey.class), anyString())).thenReturn(listWithRespositotyEntryMock); + when(repositoryEntryRelationDaoMock.hasRole(IDENTITY, repositoryEntryMock, GroupRoles.participant.name())).thenReturn(true); + + sut.grantAccess(getPendingAdvanceOrders()); + + verify(acServiceMock, never()).accessResource(any(Identity.class), any(OfferAccess.class), isNull()); + } + + @Test + public void shouldMarkAccessOrderAsDone() { + when(identifierHandlerMock.findRepositoryEntries(any(IdentifierKey.class), anyString())).thenReturn(listWithRespositotyEntryMock); + OfferAccess offerAccessDummy = mock(OfferAccess.class); + List<OfferAccess> offerAccess = Arrays.asList(offerAccessDummy); + when(acServiceMock.getValidOfferAccess(any(OLATResource.class), any(AccessMethod.class))).thenReturn(offerAccess); + + sut.grantAccess(getPendingAdvanceOrders()); + + verify(advanceOrderDaoMock, times(2)).accomplishAndSave(any(AdvanceOrder.class)); + } + + @Test + public void shouldFindAdvanceOrdersForEveryIdentifierKey() { + Long key = 1L; + when(resourceMock.getKey()).thenReturn(key); + + sut.loadPendingAdvanceOrders(repositoryEntryMock); + + verify(identifierHandlerMock, times(IdentifierKey.values().length)).getRepositoryEntryValue(any(IdentifierKey.class), any(RepositoryEntry.class)); + } +} diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalIdHandlerTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalIdHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0d21fc8365c1c1d1f4954b3ff1b240fc2da3ec34 --- /dev/null +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalIdHandlerTest.java @@ -0,0 +1,74 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryService; + +/** + * + * Initial date: 15.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class ExternalIdHandlerTest { + + @Mock + private RepositoryService repositoryServiceMock; + @Mock + private RepositoryEntry entryMock; + + @InjectMocks + private ExternalIdHandler sut; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void shouldDelegateTheSearchToRepositoryService() { + String externalId = "EXT-123"; + + sut.find(externalId); + + verify(repositoryServiceMock).loadRepositoryEntriesByExternalId(externalId); + } + + @Test + public void shouldReturnTheExternalIdFromRepositoryEntry() { + String externalId = "1234"; + when(entryMock.getExternalId()).thenReturn(externalId); + + String value = sut.getRepositoryEntryValue(entryMock); + + assertThat(value).isEqualTo(externalId); + } + +} diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalRefHandlerTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalRefHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0eb900a40eb2c2952302a1e00094e76d4fdd7ab9 --- /dev/null +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/ExternalRefHandlerTest.java @@ -0,0 +1,74 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryService; + +/** + * + * Initial date: 15.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class ExternalRefHandlerTest { + + @Mock + private RepositoryService repositoryServiceMock; + @Mock + private RepositoryEntry entryMock; + + @InjectMocks + private ExternalRefHandler sut; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void shouldDelegateTheSearchToRepositoryService() { + String externalRef = "EXT-123"; + + sut.find(externalRef); + + verify(repositoryServiceMock).loadRepositoryEntriesByExternalRef(externalRef); + } + + @Test + public void shouldReturnTheExternalRefFromRepositoryEntry() { + String externalRef = "1234"; + when(entryMock.getExternalRef()).thenReturn(externalRef); + + String value = sut.getRepositoryEntryValue(entryMock); + + assertThat(value).isEqualTo(externalRef); + } + +} diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierHandlerTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1c659235fea27c36ae91724601f123250816c1c9 --- /dev/null +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/IdentifierHandlerTest.java @@ -0,0 +1,103 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.olat.repository.RepositoryEntry; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; + +import edu.emory.mathcs.backport.java.util.Collections; + +/** + * + * Initial date: 14.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + **/ +public class IdentifierHandlerTest { + + private static RepositoryEntry course; + private static RepositoryEntry course2; + + @Mock + private ExternalIdHandler externaHandlerMock; + + @InjectMocks + private IdentifierHandler sut; + + @Spy + private Collection<IdentifierKeyHandler> handlers = new ArrayList<>(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(externaHandlerMock.getIdentifierKey()).thenReturn(IdentifierKey.externalId); + handlers.add(externaHandlerMock); + sut.initHandlerCache(); + + course = new RepositoryEntry(); + course2 = new RepositoryEntry(); + } + + @Test + public void shouldReturnTheRepositoryIfFoundOne() { + List<RepositoryEntry> resources = Arrays.asList(course); + when(externaHandlerMock.find(anyString())).thenReturn(resources); + + List<RepositoryEntry> loaded = sut.findRepositoryEntries(IdentifierKey.externalId, "EXT-123"); + + assertThat(loaded.get(0)).isEqualTo(course); + } + + @Test + public void shouldReturnEmptyListIfNoCourseFound() { + when(externaHandlerMock.find(anyString())).thenReturn(Collections.<RepositoryEntry>emptyList()); + + List<RepositoryEntry> loaded = sut.findRepositoryEntries(IdentifierKey.externalId, "EXT-123"); + + assertThat(loaded).isEmpty(); + } + + @Test + public void shouldReturnAllIfMoreThanOneCourseFound() { + List<RepositoryEntry> resources = Arrays.asList(course, course2); + when(externaHandlerMock.find(anyString())).thenReturn(resources); + + List<RepositoryEntry> loaded = sut.findRepositoryEntries(IdentifierKey.externalId, "EXT-123"); + + assertThat(loaded).hasSameSizeAs(resources); + } + +} diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/InputValidatorTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/InputValidatorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a828cbd122ccf9612dcc85e186accaf7cfe7bd6f --- /dev/null +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/InputValidatorTest.java @@ -0,0 +1,122 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.olat.basesecurity.IdentityImpl; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrderInput; +import org.olat.resource.accesscontrol.provider.auto.IdentifierKey; +import org.olat.resource.accesscontrol.provider.auto.model.AutoAccessMethod; + +/** + * + * Initial date: 17.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class InputValidatorTest { + + private AdvanceOrderInput inputMock; + + private InputValidator sut = new InputValidator(); + + @Before + public void setUp() { + inputMock = mock(AdvanceOrderInput.class); + + when(inputMock.getIdentity()).thenReturn(new IdentityImpl()); + Set<IdentifierKey> keys = new HashSet<>(); + keys.add(IdentifierKey.externalId); + when(inputMock.getKeys()).thenReturn(keys); + when(inputMock.getRawValues()).thenReturn("rawValues"); + doReturn(AutoAccessMethod.class).when(inputMock).getMethodClass(); + } + + @Test + public void shouldNotBeValidIfInputIsNull() { + boolean isValid = sut.isValid(null); + + assertThat(isValid).isFalse(); + } + + @Test + public void shouldNotBeValidIfIdentityIsNull() { + when(inputMock.getIdentity()).thenReturn(null); + + boolean isValid = sut.isValid(inputMock); + + assertThat(isValid).isFalse(); + } + + @Test + public void shouldNotBeValidIfKeysIsNull() { + when(inputMock.getKeys()).thenReturn(null); + + boolean isValid = sut.isValid(inputMock); + + assertThat(isValid).isFalse(); + } + + @Test + public void shouldNotBeValidIfEmptyKeys() { + when(inputMock.getKeys()).thenReturn(new HashSet<>(0)); + + boolean isValid = sut.isValid(inputMock); + + assertThat(isValid).isFalse(); + } + + @Test + public void shouldNotBeValidIfMethodtypeIsNull() { + when(inputMock.getMethodClass()).thenReturn(null); + + boolean isValid = sut.isValid(inputMock); + + assertThat(isValid).isFalse(); + } + + @Test + public void shouldNotBeValidIfRawValuesIsNull() { + when(inputMock.getRawValues()).thenReturn(null); + + boolean isValid = sut.isValid(inputMock); + + assertThat(isValid).isFalse(); + } + + @Test + public void shouldNotBeValidIfMethodDoesNotExist() { + when(inputMock.getIdentity()).thenReturn(null); + + boolean isValid = sut.isValid(inputMock); + + assertThat(isValid).isFalse(); + } + +} diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/InternalIdHandlerTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/InternalIdHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ff4c8c89a1731cde50fdf96af71fe9d785b96d13 --- /dev/null +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/InternalIdHandlerTest.java @@ -0,0 +1,84 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collection; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryService; + +/** + * + * Initial date: 15.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class InternalIdHandlerTest { + + @Mock + private RepositoryService repositoryServiceMock; + @Mock + private RepositoryEntry entryMock; + + @InjectMocks + private InternalIdHandler sut; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void shouldDelegateTheSearchToRepositoryService() { + sut.find("123"); + + verify(repositoryServiceMock).loadByKey(anyLong()); + } + + @Test + public void shouldReturnEmptyCollectionIfNotFound() { + when(repositoryServiceMock.loadByKey(anyLong())).thenReturn(null); + + Collection<RepositoryEntry> resources = sut.find("123"); + + assertThat(resources).isEmpty(); + } + + @Test + public void shouldReturnTheExternalIdFromRepositoryEntry() { + Long key = 1234L; + when(entryMock.getKey()).thenReturn(key); + + String value = sut.getRepositoryEntryValue(entryMock); + + String keyAsString = Long.toString(key); + assertThat(value).isEqualTo(keyAsString); + } +} diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/SemicolonSplitterTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/SemicolonSplitterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..25e78ecd8c529000aadc6f1252b20d6d98c74e1a --- /dev/null +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/SemicolonSplitterTest.java @@ -0,0 +1,72 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.auto.manager; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.Test; + + +/** + * + * Initial date: 23.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class SemicolonSplitterTest { + + private final static String SEMICOLON = ";"; + + private SemicolonSplitter sut = new SemicolonSplitter(); + + @Test + public void shouldReturnMultipleValues() { + String value1 = "single,3"; + String value2 = "multiple"; + String value3 = "value3"; + String rawValue = value1 + SEMICOLON + value2 + SEMICOLON + value3 + SEMICOLON; + List<String> rawValues = Arrays.asList(value1, value2, value3); + + Collection<String> values = sut.split(rawValue); + + assertThat(values).hasSize(rawValues.size()).hasSameElementsAs(rawValues); + } + + @Test + public void shouldReturnSingleValue() { + String singleValue = "single,3"; + List<String> rawValues = Arrays.asList(singleValue); + + Collection<String> values = sut.split(singleValue); + + assertThat(values).hasSize(rawValues.size()).hasSameElementsAs(rawValues); + } + + @Test + public void shouldReturnEmptyCollectionIfNullInput() { + Collection<String> values = sut.split(null); + + assertThat(values).hasSize(0); + } +} diff --git a/src/test/java/org/olat/restapi/CoursesTest.java b/src/test/java/org/olat/restapi/CoursesTest.java index 3d9c19393a0646304870eaab514a9f89c282dfe7..ce26168c2b56d2760abf4cb6c756cc194adcd544 100644 --- a/src/test/java/org/olat/restapi/CoursesTest.java +++ b/src/test/java/org/olat/restapi/CoursesTest.java @@ -20,7 +20,7 @@ * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. +* under the Apache 2.0 license as the original file. * <p> */ @@ -82,16 +82,16 @@ import org.olat.test.OlatJerseyTestCase; import org.springframework.beans.factory.annotation.Autowired; public class CoursesTest extends OlatJerseyTestCase { - + private static final OLog log = Tracing.createLoggerFor(CoursesTest.class); - + private Identity admin; private ICourse course1, course2, course3; private RepositoryEntry re1, re2, re3; private String externalId, externalRef; private String externalId3; private RestConnection conn; - + @Autowired private DB dbInstance; @Autowired @@ -112,13 +112,13 @@ public class CoursesTest extends OlatJerseyTestCase { // create course and persist as OLATResourceImpl admin = BaseSecurityManager.getInstance().findIdentityByName("administrator"); course1 = CoursesWebService.createEmptyCourse(admin, "courses1", "courses1 long name", null, null, null, RepositoryEntry.ACC_OWNERS, false, null, null, null, null, null, null); - + externalId = UUID.randomUUID().toString(); externalRef = UUID.randomUUID().toString(); course2 = CoursesWebService.createEmptyCourse(admin, "courses2", "courses2 long name", null, null, null, RepositoryEntry.ACC_OWNERS, false, null, null, externalId, externalRef, "all", null); - + dbInstance.commitAndCloseSession(); - + re1 = repositoryManager.lookupRepositoryEntry(course1, false); re2 = repositoryManager.lookupRepositoryEntry(course2, false); @@ -134,7 +134,7 @@ public class CoursesTest extends OlatJerseyTestCase { log.error("Exception in setUp(): " + e); } } - + @After public void tearDown() throws Exception { try { @@ -146,11 +146,11 @@ public class CoursesTest extends OlatJerseyTestCase { throw e; } } - + @Test public void testGetCourses() throws IOException, URISyntaxException { assertTrue(conn.login("administrator", "openolat")); - + URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").build(); HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true); HttpResponse response = conn.execute(method); @@ -159,7 +159,7 @@ public class CoursesTest extends OlatJerseyTestCase { List<CourseVO> courses = parseCourseArray(body); assertNotNull(courses); assertTrue(courses.size() >= 2); - + boolean vo1 = false; boolean vo2 = false; for(CourseVO course:courses) { @@ -168,20 +168,20 @@ public class CoursesTest extends OlatJerseyTestCase { vo1 = true; Assert.assertEquals("courses1", course.getTitle()); } - + if(repoEntryKey != null && re2.getKey().equals(repoEntryKey)) { vo2 = true; Assert.assertEquals("courses2", course.getTitle()); - } + } } Assert.assertTrue(vo1); Assert.assertTrue(vo2); } - + @Test public void testGetCourses_searchExternalID() throws IOException, URISyntaxException { assertTrue(conn.login("administrator", "openolat")); - + URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("externalId", externalId).build(); HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true); HttpResponse response = conn.execute(method); @@ -190,7 +190,7 @@ public class CoursesTest extends OlatJerseyTestCase { List<CourseVO> courses = parseCourseArray(body); assertNotNull(courses); assertTrue(courses.size() >= 1); - + CourseVO vo = null; for(CourseVO course:courses) { if(externalId.equals(course.getExternalId())) { @@ -200,17 +200,17 @@ public class CoursesTest extends OlatJerseyTestCase { assertNotNull(vo); assertEquals(vo.getKey(), course2.getResourceableId()); } - + @Test public void testGetCourses_searchExternalID_withLifecycle() throws IOException, URISyntaxException { assertTrue(conn.login("administrator", "openolat")); - + URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("externalId", externalId3).build(); HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true); HttpResponse response = conn.execute(method); assertEquals(200, response.getStatusLine().getStatusCode()); InputStream body = response.getEntity().getContent(); - + List<CourseVO> courses = parseCourseArray(body); assertNotNull("Course list cannot be null", courses); assertEquals(1, courses.size()); @@ -220,11 +220,11 @@ public class CoursesTest extends OlatJerseyTestCase { assertNotNull("Has a lifecycle", vo.getLifecycle()); assertNotNull("Life cycle has a soft key", vo.getLifecycle().getSoftkey()); } - + @Test public void testGetCourses_searchExternalRef() throws IOException, URISyntaxException { assertTrue(conn.login("administrator", "openolat")); - + URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("externalRef", externalRef).build(); HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true); HttpResponse response = conn.execute(method); @@ -233,7 +233,7 @@ public class CoursesTest extends OlatJerseyTestCase { List<CourseVO> courses = parseCourseArray(body); assertNotNull(courses); assertTrue(courses.size() >= 1); - + CourseVO vo = null; for(CourseVO course:courses) { if(externalRef.equals(course.getExternalRef())) { @@ -243,11 +243,11 @@ public class CoursesTest extends OlatJerseyTestCase { assertNotNull(vo); assertEquals(vo.getKey(), course2.getResourceableId()); } - + @Test public void testGetCourses_managed() throws IOException, URISyntaxException { assertTrue(conn.login("administrator", "openolat")); - + URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("managed", "true").build(); HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true); HttpResponse response = conn.execute(method); @@ -256,17 +256,17 @@ public class CoursesTest extends OlatJerseyTestCase { List<CourseVO> courses = parseCourseArray(body); assertNotNull(courses); assertTrue(courses.size() >= 1); - + for(CourseVO course:courses) { boolean managed = StringHelper.containsNonWhitespace(course.getManagedFlags()); Assert.assertTrue(managed); } } - + @Test public void testGetCourses_notManaged() throws IOException, URISyntaxException { assertTrue(conn.login("administrator", "openolat")); - + URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("managed", "false").build(); HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true); HttpResponse response = conn.execute(method); @@ -275,17 +275,17 @@ public class CoursesTest extends OlatJerseyTestCase { List<CourseVO> courses = parseCourseArray(body); assertNotNull(courses); assertTrue(courses.size() >= 1); - + for(CourseVO course:courses) { boolean managed = StringHelper.containsNonWhitespace(course.getManagedFlags()); Assert.assertFalse(managed); } } - + @Test public void testGetCoursesWithPaging() throws IOException, URISyntaxException { assertTrue(conn.login("administrator", "openolat")); - + URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses") .queryParam("start", "0").queryParam("limit", "1").build(); HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON + ";pagingspec=1.0", true); @@ -296,15 +296,15 @@ public class CoursesTest extends OlatJerseyTestCase { assertNotNull(courses.getCourses()); assertEquals(1, courses.getCourses().length); } - + @Test public void testCreateEmptyCourse() throws IOException, URISyntaxException { assertTrue(conn.login("administrator", "openolat")); - + URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses") .queryParam("shortTitle", "course3").queryParam("title", "course3 long name").build(); HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true); - + HttpResponse response = conn.execute(method); assertEquals(200, response.getStatusLine().getStatusCode()); CourseVO course = conn.parse(response, CourseVO.class); @@ -315,80 +315,80 @@ public class CoursesTest extends OlatJerseyTestCase { assertNotNull(re); assertNotNull(re.getOlatResource()); } - + @Test public void testCreateEmpty_withoutAuthorCourse() throws IOException, URISyntaxException { assertTrue(conn.login("administrator", "openolat")); - + URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses") .queryParam("shortTitle", "Course without author") .queryParam("title", "Course without author") .queryParam("setAuthor", "false").build(); HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true); - + HttpResponse response = conn.execute(method); Assert.assertEquals(200, response.getStatusLine().getStatusCode()); CourseVO courseVo = conn.parse(response, CourseVO.class); Assert.assertNotNull(courseVo); Assert.assertEquals("Course without author", courseVo.getTitle()); - + // load repository entry RepositoryEntry re = repositoryManager.lookupRepositoryEntry(courseVo.getRepoEntryKey()); Assert.assertNotNull(re); Assert.assertNotNull(re.getOlatResource()); Assert.assertEquals("Course without author", re.getDisplayname()); - + // load the course ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId()); Assert.assertNotNull(course); Assert.assertEquals("Course without author", course.getCourseTitle()); Assert.assertEquals(re, course.getCourseEnvironment().getCourseGroupManager().getCourseEntry()); - + // check the list of owners List<Identity> owners = repositoryEntryRelationDao.getMembers(re, RepositoryEntryRelationType.both, GroupRoles.owner.name()); Assert.assertNotNull(owners); Assert.assertTrue(owners.isEmpty()); } - + @Test public void testCreateEmpty_withInitialAuthor() throws IOException, URISyntaxException { Identity adhocAuthor = JunitTestHelper.createAndPersistIdentityAsRndUser("adhoc-author"); dbInstance.commit(); assertTrue(conn.login("administrator", "openolat")); - + URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses") .queryParam("shortTitle", "Course without author") .queryParam("title", "Course without author") .queryParam("initialAuthor", adhocAuthor.getKey().toString()) .build(); HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true); - + HttpResponse response = conn.execute(method); Assert.assertEquals(200, response.getStatusLine().getStatusCode()); CourseVO courseVo = conn.parse(response, CourseVO.class); Assert.assertNotNull(courseVo); Assert.assertEquals("Course without author", courseVo.getTitle()); - + // load repository entry RepositoryEntry re = repositoryManager.lookupRepositoryEntry(courseVo.getRepoEntryKey()); Assert.assertNotNull(re); Assert.assertNotNull(re.getOlatResource()); Assert.assertEquals("Course without author", re.getDisplayname()); - + // load the course ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId()); Assert.assertNotNull(course); Assert.assertEquals("Course without author", course.getCourseTitle()); Assert.assertEquals(re, course.getCourseEnvironment().getCourseGroupManager().getCourseEntry()); - + // check the list of owners List<Identity> owners = repositoryEntryRelationDao.getMembers(re, RepositoryEntryRelationType.both, GroupRoles.owner.name()); Assert.assertNotNull(owners); Assert.assertEquals(1, owners.size()); Assert.assertEquals(adhocAuthor, owners.get(0)); } - + @Test public void testImportCourse() throws IOException, URISyntaxException { URL cpUrl = CoursesTest.class.getResource("Course_with_blog.zip"); @@ -396,7 +396,7 @@ public class CoursesTest extends OlatJerseyTestCase { File cp = new File(cpUrl.toURI()); assertTrue(conn.login("administrator", "openolat")); - + URI request = UriBuilder.fromUri(getContextURI()).path("repo/courses").build(); HttpPost method = conn.createPost(request, MediaType.APPLICATION_JSON); @@ -412,15 +412,15 @@ public class CoursesTest extends OlatJerseyTestCase { .addTextBody("softkey", softKey) .build(); method.setEntity(entity); - + HttpResponse response = conn.execute(method); assertTrue(response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 201); - + CourseVO vo = conn.parse(response, CourseVO.class); assertNotNull(vo); assertNotNull(vo.getRepoEntryKey()); assertNotNull(vo.getKey()); - + Long repoKey = vo.getRepoEntryKey(); RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(repoKey); assertNotNull(re); @@ -428,7 +428,44 @@ public class CoursesTest extends OlatJerseyTestCase { assertEquals("Very small course", re.getDisplayname()); assertEquals(softKey, re.getSoftkey()); } - + + @Test + public void testImportCourse_owner() throws IOException, URISyntaxException { + URL cpUrl = CoursesTest.class.getResource("Course_with_blog.zip"); + File cp = new File(cpUrl.toURI()); + + String username = "ownerImportCourse"; + Identity owner = JunitTestHelper.createAndPersistIdentityAsUser(username); + + assertTrue(conn.login("administrator", "openolat")); + + URI request = UriBuilder.fromUri( getContextURI()) + .path("repo/courses") + .queryParam("ownerUsername", owner.getName()).build(); + HttpPost method = conn.createPost(request, MediaType.APPLICATION_JSON); + + String softKey = UUID.randomUUID().toString().replace("-", "").substring(0, 30); + HttpEntity entity = MultipartEntityBuilder.create() + .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) + .addBinaryBody("file", cp, ContentType.APPLICATION_OCTET_STREAM, cp.getName()) + .addTextBody("filename", "Very_small_course.zip") + .addTextBody("foldername", "New folder 1 2 3") + .addTextBody("resourcename", "Very small course") + .addTextBody("displayname", "Very small course") + .addTextBody("access", "3") + .addTextBody("softkey", softKey) + .build(); + method.setEntity(entity); + + HttpResponse response = conn.execute(method); + assertTrue(response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 201); + + CourseVO vo = conn.parse(response, CourseVO.class); + Long repoKey = vo.getRepoEntryKey(); + RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(repoKey); + assertTrue(repositoryEntryRelationDao.hasRole(owner, re, GroupRoles.owner.name())); + } + @Test public void testCopyCourse() throws IOException, URISyntaxException { Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("author-5"); @@ -447,13 +484,13 @@ public class CoursesTest extends OlatJerseyTestCase { HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true); HttpResponse response = conn.execute(method); assertTrue(response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 201); - + CourseVO vo = conn.parse(response, CourseVO.class); assertNotNull(vo); assertNotNull(vo.getRepoEntryKey()); assertNotNull(vo.getKey()); } - + @Test public void testCopyCourse_unkownCourse() throws IOException, URISyntaxException { Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("author-5"); @@ -474,10 +511,10 @@ public class CoursesTest extends OlatJerseyTestCase { assertTrue(response.getStatusLine().getStatusCode() == 404); EntityUtils.consume(response.getEntity()); } - + protected List<CourseVO> parseCourseArray(InputStream body) { try { - ObjectMapper mapper = new ObjectMapper(jsonFactory); + ObjectMapper mapper = new ObjectMapper(jsonFactory); return mapper.readValue(body, new TypeReference<List<CourseVO>>(){/* */}); } catch (Exception e) { e.printStackTrace(); diff --git a/src/test/java/org/olat/restapi/LecturesBlockRollCallTest.java b/src/test/java/org/olat/restapi/LecturesBlockRollCallTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5fb9de1039f056374979be6004d81f96b43807f8 --- /dev/null +++ b/src/test/java/org/olat/restapi/LecturesBlockRollCallTest.java @@ -0,0 +1,233 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.restapi; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; +import org.junit.Assert; +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureBlockRollCall; +import org.olat.modules.lecture.LectureBlockRollCallSearchParameters; +import org.olat.modules.lecture.LectureBlockStatus; +import org.olat.modules.lecture.LectureRollCallStatus; +import org.olat.modules.lecture.manager.LectureBlockDAO; +import org.olat.modules.lecture.manager.LectureBlockRollCallDAO; +import org.olat.modules.lecture.restapi.LectureBlockRollCallVO; +import org.olat.repository.RepositoryEntry; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatJerseyTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 28 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LecturesBlockRollCallTest extends OlatJerseyTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private LectureBlockDAO lectureBlockDao; + @Autowired + private LectureBlockRollCallDAO lectureBlockRollCallDao; + + @Test + public void getRollCalls_searchParams_True() + throws IOException, URISyntaxException { + // an open lecture block + LectureBlock openLectureBlock = createMinimalLectureBlock(3); + Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-2"); + dbInstance.commitAndCloseSession(); + + // a closed lecture block + LectureBlock closedLectureBlock = createMinimalLectureBlock(3); + dbInstance.commitAndCloseSession(); + closedLectureBlock.setStatus(LectureBlockStatus.done); + closedLectureBlock.setRollCallStatus(LectureRollCallStatus.closed); + lectureBlockDao.update(closedLectureBlock); + + List<Integer> absences = Arrays.asList(1, 2); + LectureBlockRollCall rollCall1 = lectureBlockRollCallDao.createAndPersistRollCall(closedLectureBlock, id1, null, null, null, Collections.emptyList()); + LectureBlockRollCall rollCall2 = lectureBlockRollCallDao.createAndPersistRollCall(closedLectureBlock, id2, null, null, null, absences); + LectureBlockRollCall rollCall3 = lectureBlockRollCallDao.createAndPersistRollCall(openLectureBlock, id1, null, null, null, absences); + LectureBlockRollCall rollCall4 = lectureBlockRollCallDao.createAndPersistRollCall(openLectureBlock, id2, null, null, null, Collections.emptyList()); + dbInstance.commit(); + + rollCall2.setAbsenceSupervisorNotificationDate(new Date()); + rollCall2 = lectureBlockRollCallDao.update(rollCall2); + dbInstance.commitAndCloseSession(); + + // REST call + RestConnection conn = new RestConnection(); + Assert.assertTrue(conn.login("administrator", "openolat")); + + URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("lectures").path("rollcalls") + .queryParam("hasAbsences", "true") + .queryParam("closed", "true") + .queryParam("hasSupervisorNotificationDate", "true").build(); + HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true); + HttpResponse response = conn.execute(method); + + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + List<LectureBlockRollCallVO> voList = parseLectureBlockRollCallArray(response.getEntity().getContent()); + Assert.assertNotNull(voList); + + // check the return values + List<Long> rollCallVoKeys = voList.stream().map(vo -> vo.getKey()).collect(Collectors.toList()); + Assert.assertFalse(rollCallVoKeys.contains(rollCall1.getKey())); + Assert.assertTrue(rollCallVoKeys.contains(rollCall2.getKey())); + Assert.assertFalse(rollCallVoKeys.contains(rollCall3.getKey())); + Assert.assertFalse(rollCallVoKeys.contains(rollCall4.getKey())); + + + //check that roll call 2 has a date + boolean found = false; + for(LectureBlockRollCallVO vo:voList) { + if(vo.getKey().equals(rollCall2.getKey()) && vo.getAbsenceSupervisorNotificationDate() != null) { + found = true; + } + } + Assert.assertTrue(found); + } + + @Test + public void getRollCallByKey() + throws IOException, URISyntaxException { + // a closed lecture block + LectureBlock lectureBlock = createMinimalLectureBlock(3); + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + dbInstance.commit(); + + List<Integer> absences = Arrays.asList(1, 2); + LectureBlockRollCall rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, id, null, null, null, absences); + dbInstance.commitAndCloseSession(); + + // GET REST call + RestConnection conn = new RestConnection(); + Assert.assertTrue(conn.login("administrator", "openolat")); + + URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("lectures").path("rollcalls") + .path(rollCall.getKey().toString()).build(); + HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true); + HttpResponse response = conn.execute(method); + + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + LectureBlockRollCallVO rollCallVo = conn.parse(response, LectureBlockRollCallVO.class); + Assert.assertNotNull(rollCallVo); + Assert.assertEquals(rollCall.getKey(), rollCallVo.getKey()); + } + + @Test + public void getAndUpdateSupervisorDate() + throws IOException, URISyntaxException { + // a closed lecture block + LectureBlock lectureBlock = createMinimalLectureBlock(3); + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("lecturer-1"); + dbInstance.commit(); + + List<Integer> absences = Arrays.asList(1, 2); + LectureBlockRollCall rollCall = lectureBlockRollCallDao.createAndPersistRollCall(lectureBlock, id, null, null, null, absences); + dbInstance.commitAndCloseSession(); + + // POST REST call + LectureBlockRollCallVO rollCallVo = new LectureBlockRollCallVO(); + rollCallVo.setKey(rollCall.getKey()); + rollCallVo.setLecturesAbsentNumber(rollCall.getLecturesAbsentNumber()); + rollCallVo.setLecturesAttendedNumber(rollCall.getLecturesAttendedNumber()); + + rollCallVo.setComment(rollCall.getComment()); + rollCallVo.setAbsenceReason(rollCall.getAbsenceReason()); + rollCallVo.setAbsenceAuthorized(rollCall.getAbsenceAuthorized()); + rollCallVo.setAbsenceSupervisorNotificationDate(new Date()); + + rollCallVo.setIdentityKey(id.getKey()); + rollCallVo.setLectureBlockKey(lectureBlock.getKey()); + + RestConnection conn = new RestConnection(); + Assert.assertTrue(conn.login("administrator", "openolat")); + + URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("lectures").path("rollcalls").build(); + HttpPost postMethod = conn.createPost(uri, MediaType.APPLICATION_JSON); + conn.addJsonEntity(postMethod, rollCallVo); + + HttpResponse response = conn.execute(postMethod); + + // check the response + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + LectureBlockRollCallVO updatedRollCallVo = conn.parse(response, LectureBlockRollCallVO.class); + Assert.assertNotNull(updatedRollCallVo); + Assert.assertEquals(rollCall.getKey(), updatedRollCallVo.getKey()); + Assert.assertNotNull(updatedRollCallVo.getAbsenceSupervisorNotificationDate()); + + + // reload the roll call from the database + LectureBlockRollCallSearchParameters searchParams = new LectureBlockRollCallSearchParameters(); + searchParams.setRollCallKey(rollCall.getKey()); + List<LectureBlockRollCall> rollCalls = lectureBlockRollCallDao.getRollCalls(searchParams); + Assert.assertNotNull(rollCalls); + Assert.assertEquals(1, rollCalls.size()); + LectureBlockRollCall updatedRollCall = rollCalls.get(0); + Assert.assertEquals(rollCall, updatedRollCall); + Assert.assertNotNull(updatedRollCall.getAbsenceSupervisorNotificationDate()); + } + + private LectureBlock createMinimalLectureBlock(int numOfLectures) { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + LectureBlock lectureBlock = lectureBlockDao.createLectureBlock(entry); + lectureBlock.setStartDate(new Date()); + lectureBlock.setEndDate(new Date()); + lectureBlock.setTitle("Hello REST lecturers"); + lectureBlock.setPlannedLecturesNumber(numOfLectures); + lectureBlock.setEffectiveLecturesNumber(numOfLectures); + return lectureBlockDao.update(lectureBlock); + } + + protected List<LectureBlockRollCallVO> parseLectureBlockRollCallArray(InputStream body) { + try { + ObjectMapper mapper = new ObjectMapper(jsonFactory); + return mapper.readValue(body, new TypeReference<List<LectureBlockRollCallVO>>(){/* */}); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/test/java/org/olat/restapi/LecturesBlocksRootTest.java b/src/test/java/org/olat/restapi/LecturesBlocksRootTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e4c24fa315509f7155f6a74397fb377d5bc4d925 --- /dev/null +++ b/src/test/java/org/olat/restapi/LecturesBlocksRootTest.java @@ -0,0 +1,154 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.restapi; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; +import org.junit.Assert; +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.course.ICourse; +import org.olat.modules.lecture.LectureBlock; +import org.olat.modules.lecture.LectureService; +import org.olat.modules.lecture.restapi.LectureBlockVO; +import org.olat.repository.RepositoryEntry; +import org.olat.restapi.repository.course.CoursesWebService; +import org.olat.restapi.support.vo.CourseConfigVO; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatJerseyTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 13 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LecturesBlocksRootTest extends OlatJerseyTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private LectureService lectureService; + + @Test + public void getLecturesBlock() + throws IOException, URISyntaxException { + Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("lect-root-all"); + ICourse course = CoursesWebService.createEmptyCourse(author, "Course with absence", "Course with absence", new CourseConfigVO()); + RepositoryEntry entry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + LectureBlock block = createLectureBlock(entry); + dbInstance.commit(); + lectureService.addTeacher(block, author); + dbInstance.commit(); + + RestConnection conn = new RestConnection(); + Assert.assertTrue(conn.login("administrator", "openolat")); + + URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("lectures").build(); + HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true); + HttpResponse response = conn.execute(method); + + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + List<LectureBlockVO> voList = parseLectureBlockArray(response.getEntity().getContent()); + Assert.assertNotNull(voList); + Assert.assertFalse(voList.isEmpty()); + + LectureBlockVO lectureBlockVo = null; + for(LectureBlockVO vo:voList) { + if(vo.getKey().equals(block.getKey())) { + lectureBlockVo = vo; + } + } + + Assert.assertNotNull(lectureBlockVo); + Assert.assertEquals(block.getKey(), lectureBlockVo.getKey()); + Assert.assertEquals(entry.getKey(), lectureBlockVo.getRepoEntryKey()); + } + + @Test + public void getLecturesBlock_date() + throws IOException, URISyntaxException { + Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("lect-root-1"); + ICourse course = CoursesWebService.createEmptyCourse(author, "Course with absence", "Course with absence", new CourseConfigVO()); + RepositoryEntry entry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + LectureBlock block = createLectureBlock(entry); + dbInstance.commit(); + lectureService.addTeacher(block, author); + dbInstance.commit(); + + RestConnection conn = new RestConnection(); + Assert.assertTrue(conn.login("administrator", "openolat")); + + String date = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss").format(new Date()); + URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("lectures").queryParam("date", date).build(); + HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true); + HttpResponse response = conn.execute(method); + + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + List<LectureBlockVO> voList = parseLectureBlockArray(response.getEntity().getContent()); + Assert.assertNotNull(voList); + Assert.assertFalse(voList.isEmpty()); + + LectureBlockVO lectureBlockVo = null; + for(LectureBlockVO vo:voList) { + if(vo.getKey().equals(block.getKey())) { + lectureBlockVo = vo; + } + } + + Assert.assertNotNull(lectureBlockVo); + Assert.assertEquals(block.getKey(), lectureBlockVo.getKey()); + Assert.assertEquals(entry.getKey(), lectureBlockVo.getRepoEntryKey()); + } + + private LectureBlock createLectureBlock(RepositoryEntry entry) { + LectureBlock lectureBlock = lectureService.createLectureBlock(entry); + lectureBlock.setStartDate(new Date()); + lectureBlock.setEndDate(new Date()); + lectureBlock.setTitle("Hello lecturers"); + lectureBlock.setPlannedLecturesNumber(4); + return lectureService.save(lectureBlock, null); + } + + protected List<LectureBlockVO> parseLectureBlockArray(InputStream body) { + try { + ObjectMapper mapper = new ObjectMapper(jsonFactory); + return mapper.readValue(body, new TypeReference<List<LectureBlockVO>>(){/* */}); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/test/java/org/olat/restapi/QuestionPoolTest.java b/src/test/java/org/olat/restapi/QuestionPoolTest.java new file mode 100644 index 0000000000000000000000000000000000000000..db251f851ffb51a4eb9ea9904cb749504718a9f6 --- /dev/null +++ b/src/test/java/org/olat/restapi/QuestionPoolTest.java @@ -0,0 +1,218 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.restapi; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.util.EntityUtils; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; +import org.junit.Assert; +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.ims.qti.QTIConstants; +import org.olat.modules.qpool.QPoolService; +import org.olat.modules.qpool.QuestionItem; +import org.olat.modules.qpool.QuestionType; +import org.olat.modules.qpool.manager.QItemTypeDAO; +import org.olat.modules.qpool.manager.QuestionItemDAO; +import org.olat.modules.qpool.model.QItemType; +import org.olat.modules.qpool.restapi.QuestionItemVO; +import org.olat.modules.qpool.restapi.QuestionItemVOes; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatJerseyTestCase; +import org.olat.user.restapi.UserVO; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 8 sept. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QuestionPoolTest extends OlatJerseyTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private QPoolService qpoolService; + @Autowired + private QItemTypeDAO qItemTypeDao; + @Autowired + private QuestionItemDAO questionDao; + @Autowired + private QuestionItemDAO questionItemDao; + + @Test + public void importQuestion() + throws IOException, URISyntaxException { + URL itemUrl = QuestionPoolTest.class.getResource("multiple_choice_per_answer.zip"); + assertNotNull(itemUrl); + File itemFile = new File(itemUrl.toURI()); + + RestConnection conn = new RestConnection(); + assertTrue(conn.login("administrator", "openolat")); + + URI request = UriBuilder.fromUri(getContextURI()).path("qpool/items").build(); + HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true); + HttpEntity entity = MultipartEntityBuilder.create() + .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) + .addBinaryBody("file", itemFile, ContentType.APPLICATION_OCTET_STREAM, itemFile.getName()) + .addTextBody("filename", "multiple_choice_per_answer.zip") + .build(); + method.setEntity(entity); + + HttpResponse response = conn.execute(method); + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + + QuestionItemVOes voes = conn.parse(response, QuestionItemVOes.class); + Assert.assertNotNull(voes); + QuestionItemVO[] voArray = voes.getQuestionItems(); + Assert.assertNotNull(voArray); + Assert.assertEquals(1, voArray.length); + QuestionItemVO vo = voArray[0]; + Assert.assertNotNull(vo); + } + + @Test + public void getAuthors() throws IOException, URISyntaxException { + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("item-author-1"); + QuestionItem item = questionDao.createAndPersist(author, "NGC 55", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + dbInstance.commitAndCloseSession(); + + RestConnection conn = new RestConnection(); + Assert.assertTrue(conn.login("administrator", "openolat")); + + URI request = UriBuilder.fromUri(getContextURI()).path("/qpool/items/" + item.getKey() + "/authors/").build(); + HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true); + HttpResponse response = conn.execute(method); + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + List<UserVO> users = parseUserArray(response.getEntity().getContent()); + //check + Assert.assertNotNull(users); + Assert.assertEquals(1, users.size()); + Assert.assertTrue(author.getKey().equals(users.get(0).getKey())); + } + + @Test + public void getAuthor() throws IOException, URISyntaxException { + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("item-author-2"); + QuestionItem item = questionDao.createAndPersist(author, "NGC 55", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + dbInstance.commitAndCloseSession(); + + RestConnection conn = new RestConnection(); + Assert.assertTrue(conn.login("administrator", "openolat")); + + URI request = UriBuilder.fromUri(getContextURI()).path("/qpool/items/" + item.getKey() + "/authors/" + author.getKey()).build(); + HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true); + HttpResponse response = conn.execute(method); + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + UserVO user = conn.parse(response.getEntity().getContent(), UserVO.class); + //check + Assert.assertNotNull(user); + Assert.assertTrue(author.getKey().equals(user.getKey())); + } + + @Test + public void addAuthor() throws IOException, URISyntaxException { + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("item-author-1"); + QuestionItem item = questionDao.createAndPersist(author, "NGC 55", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + Identity coAuthor = JunitTestHelper.createAndPersistIdentityAsRndUser("item-author-1"); + + RestConnection conn = new RestConnection(); + Assert.assertTrue(conn.login("administrator", "openolat")); + + URI request = UriBuilder.fromUri(getContextURI()).path("/qpool/items/" + item.getKey() + "/authors/" + coAuthor.getKey()).build(); + HttpPut method = conn.createPut(request, MediaType.APPLICATION_JSON, true); + HttpResponse response = conn.execute(method); + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + EntityUtils.consume(response.getEntity()); + + //check + List<Identity> authors = qpoolService.getAuthors(item); + Assert.assertNotNull(authors); + Assert.assertEquals(2, authors.size()); + Assert.assertTrue(authors.contains(author)); + Assert.assertTrue(authors.contains(coAuthor)); + } + + @Test + public void removeAuthor() throws IOException, URISyntaxException { + QItemType mcType = qItemTypeDao.loadByType(QuestionType.MC.name()); + Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("item-author-1"); + QuestionItem item = questionDao.createAndPersist(author, "NGC 55", QTIConstants.QTI_12_FORMAT, Locale.ENGLISH.getLanguage(), null, null, null, mcType); + Identity coAuthor = JunitTestHelper.createAndPersistIdentityAsRndUser("item-author-1"); + List<Identity> authors = Collections.singletonList(coAuthor); + questionItemDao.addAuthors(authors, item); + dbInstance.commit(); + + RestConnection conn = new RestConnection(); + Assert.assertTrue(conn.login("administrator", "openolat")); + + URI request = UriBuilder.fromUri(getContextURI()).path("/qpool/items/" + item.getKey() + "/authors/" + coAuthor.getKey()).build(); + HttpDelete method = conn.createDelete(request, MediaType.APPLICATION_JSON); + HttpResponse response = conn.execute(method); + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + EntityUtils.consume(response.getEntity()); + + //check + List<Identity> itemsAuthors = qpoolService.getAuthors(item); + Assert.assertNotNull(itemsAuthors); + Assert.assertEquals(1, itemsAuthors.size()); + Assert.assertTrue(itemsAuthors.contains(author)); + Assert.assertFalse(itemsAuthors.contains(coAuthor)); + } + + protected List<UserVO> parseUserArray(InputStream body) { + try { + ObjectMapper mapper = new ObjectMapper(jsonFactory); + return mapper.readValue(body, new TypeReference<List<UserVO>>(){/* */}); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/test/java/org/olat/restapi/multiple_choice_per_answer.zip b/src/test/java/org/olat/restapi/multiple_choice_per_answer.zip new file mode 100644 index 0000000000000000000000000000000000000000..db49796f9efeb569f151a9a05cf932505e473a30 Binary files /dev/null and b/src/test/java/org/olat/restapi/multiple_choice_per_answer.zip differ diff --git a/src/test/java/org/olat/selenium/CourseElementTest.java b/src/test/java/org/olat/selenium/CourseElementTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e404b946e5ecaa2e9de01b54171bd616c52e1979 --- /dev/null +++ b/src/test/java/org/olat/selenium/CourseElementTest.java @@ -0,0 +1,1421 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.UUID; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.drone.api.annotation.Drone; +import org.jboss.arquillian.graphene.page.InitialPage; +import org.jboss.arquillian.graphene.page.Page; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.olat.selenium.page.LoginPage; +import org.olat.selenium.page.NavigationPage; +import org.olat.selenium.page.Participant; +import org.olat.selenium.page.Student; +import org.olat.selenium.page.User; +import org.olat.selenium.page.core.FolderPage; +import org.olat.selenium.page.course.CourseEditorPageFragment; +import org.olat.selenium.page.course.CoursePageFragment; +import org.olat.selenium.page.course.DialogConfigurationPage; +import org.olat.selenium.page.course.DialogPage; +import org.olat.selenium.page.course.ForumCEPage; +import org.olat.selenium.page.course.InfoMessageCEPage; +import org.olat.selenium.page.course.LTIConfigurationPage; +import org.olat.selenium.page.course.LTIPage; +import org.olat.selenium.page.course.MemberListConfigurationPage; +import org.olat.selenium.page.course.MemberListPage; +import org.olat.selenium.page.course.MembersPage; +import org.olat.selenium.page.course.ParticipantFolderPage; +import org.olat.selenium.page.forum.ForumPage; +import org.olat.selenium.page.graphene.OOGraphene; +import org.olat.selenium.page.repository.AuthoringEnvPage; +import org.olat.selenium.page.repository.FeedPage; +import org.olat.selenium.page.repository.RepositoryEditDescriptionPage; +import org.olat.selenium.page.repository.ScormPage; +import org.olat.selenium.page.repository.AuthoringEnvPage.ResourceType; +import org.olat.selenium.page.repository.RepositoryAccessPage.UserAccess; +import org.olat.selenium.page.user.UserToolsPage; +import org.olat.test.ArquillianDeployments; +import org.olat.test.JunitTestHelper; +import org.olat.test.rest.UserRestClient; +import org.olat.user.restapi.UserVO; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 27 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@RunWith(Arquillian.class) +public class CourseElementTest { + + @Deployment(testable = false) + public static WebArchive createDeployment() { + return ArquillianDeployments.createDeployment(); + } + + @Drone + private WebDriver browser; + @ArquillianResource + private URL deploymentUrl; + @Page + private NavigationPage navBar; + + + /** + * Create a course, create a CP, go the the course editor, + * create a course element of type CP, select the CP which just created, + * close the course editor and check the presence of the CP with the + * default title of the first page. + * + * @param loginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void createCourseWithCP(@InitialPage LoginPage loginPage) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + loginPage.loginAs(author.getLogin(), author.getPassword()); + + //create a course + String courseTitle = "Course-With-CP-" + UUID.randomUUID().toString(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + //go the authoring environment to create a CP + String cpTitle = "CP for a course - " + UUID.randomUUID().toString(); + navBar + .openAuthoringEnvironment() + .createCP(cpTitle) + .assertOnGeneralTab(); + + navBar.openCourse(courseTitle); + + String cpNodeTitle = "CP-1"; + //create a course element of type CP with the CP that we create above + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit(); + courseEditor + .createNode("cp") + .nodeTitle(cpNodeTitle) + .selectTabLearnContent() + .chooseCP(cpTitle); + + //publish the course + courseEditor + .publish() + .quickPublish(); + + //open the course and see the CP + CoursePageFragment course = courseEditor + .clickToolbarBack(); + + course + .clickTree() + .selectWithTitle(cpNodeTitle); + + //check that the default title of CP (Lorem Ipsum) is visible in the iframe + WebElement cpIframe = browser.findElement(By.cssSelector("div.o_iframedisplay>iframe")); + browser.switchTo().frame(cpIframe); + browser.findElement(By.xpath("//h2[text()='Lorem Ipsum']")); + } + + /** + * This test an edge case where a course start automatically its first + * course element, which is a structure node which start itself its first + * element, which is a SCORM which launch itself automatically. + * + * @param loginPage + */ + @Test + @RunAsClient + public void courseWithSCORM_fullAuto(@InitialPage LoginPage loginPage) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + loginPage.loginAs(author.getLogin(), author.getPassword()); + + URL zipUrl = JunitTestHelper.class.getResource("file_resources/scorm/SCORM_course_full_auto.zip"); + File zipFile = new File(zipUrl.toURI()); + //go the authoring environment to import our course + String zipTitle = "SCORM - " + UUID.randomUUID(); + navBar + .openAuthoringEnvironment() + .uploadResource(zipTitle, zipFile); + + // publish the course + new RepositoryEditDescriptionPage(browser) + .clickToolbarBack(); + CoursePageFragment.getCourse(browser) + .edit() + .autoPublish(); + + //scorm is auto started -> back + ScormPage.getScormPage(browser) + .back(); + + //log out + new UserToolsPage(browser) + .logout(); + + //log in and resume test + loginPage + .loginAs(author.getLogin(), author.getPassword()) + .resume(); + // direct jump in SCORM content + ScormPage.getScormPage(browser) + .passVerySimpleScorm() + .back() + .assertOnScormPassed() + .assertOnScormScore(33); + } + + /** + * Create a course, create a wiki, go the the course editor, + * create a course element of type wiki, select the wiki which just created, + * close the course editor and select the index page of the wiki. + * + * @param loginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void createCourseWithWiki(@InitialPage LoginPage loginPage) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + loginPage.loginAs(author.getLogin(), author.getPassword()); + + //create a course + String courseTitle = "Course-With-Wiki-" + UUID.randomUUID().toString(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + //go the authoring environment to create a CP + String wikiTitle = "Wiki for a course - " + UUID.randomUUID().toString(); + navBar + .openAuthoringEnvironment() + .createWiki(wikiTitle) + .assertOnGeneralTab(); + + navBar.openCourse(courseTitle); + + String wikiNodeTitle = "Wiki-1"; + //create a course element of type CP with the CP that we create above + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit(); + courseEditor + .createNode("wiki") + .nodeTitle(wikiNodeTitle) + .selectTabLearnContent() + .chooseWiki(wikiTitle); + + //publish the course + courseEditor + .publish() + .quickPublish(); + + //open the course and see the CP + CoursePageFragment course = courseEditor + .clickToolbarBack(); + + course + .clickTree() + .selectWithTitle(wikiNodeTitle) + .selectWithTitle("Index"); + + //check that the title of the index article/page is visible + WebElement indexArticleTitle = browser.findElement(By.className("o_wikimod_heading")); + Assert.assertEquals("Index", indexArticleTitle.getText().trim()); + } + + /** + * Create a course, create a course element of type wiki. Open + * the resource chooser, create a wiki, close the editor, show the + * index page of the wiki. + * + * @param loginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void createCourseWithWiki_createInCourseEditor(@InitialPage LoginPage loginPage) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + loginPage.loginAs(author.getLogin(), author.getPassword()); + + //create a course + String courseTitle = "Course-With-Wiki-" + UUID.randomUUID().toString(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + String wikiNodeTitle = "Wiki-1"; + String wikiTitle = "Wiki for a course - " + UUID.randomUUID().toString(); + + //create a course element of type CP with the CP that we create above + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit(); + courseEditor + .createNode("wiki") + .nodeTitle(wikiNodeTitle) + .selectTabLearnContent() + .createWiki(wikiTitle); + + //publish the course + courseEditor + .publish() + .quickPublish(); + + //open the course and see the CP + CoursePageFragment course = courseEditor + .clickToolbarBack(); + + course + .clickTree() + .selectWithTitle(wikiNodeTitle) + .selectWithTitle("Index"); + + //check that the title of the index article/page is visible + WebElement indexArticleTitle = browser.findElement(By.className("o_wikimod_heading")); + Assert.assertEquals("Index", indexArticleTitle.getText().trim()); + } + + + @Test + @RunAsClient + public void createCourseWithQTITest(@InitialPage LoginPage loginPage) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + loginPage.loginAs(author.getLogin(), author.getPassword()); + + //create a course + String courseTitle = "Course-With-QTI-Test-1.2-" + UUID.randomUUID().toString(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + String testNodeTitle = "QTITest-1"; + String testTitle = "Test - " + UUID.randomUUID().toString(); + + //create a course element of type CP with the CP that we create above + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit(); + courseEditor + .createNode("iqtest") + .nodeTitle(testNodeTitle) + .selectTabLearnContent() + .createQTI12Test(testTitle); + + //publish the course + courseEditor + .publish() + .quickPublish(); + + //open the course and see the CP + CoursePageFragment course = courseEditor + .clickToolbarBack(); + + course + .clickTree() + .selectWithTitle(testNodeTitle); + + //check that the title of the start page of test is correct + WebElement testH2 = browser.findElement(By.cssSelector("div.o_course_run h2")); + Assert.assertEquals(testNodeTitle, testH2.getText().trim()); + } + + /** + * Create a course with a course element of type podcast. Create + * a podcast, publish the course, go the the course and configure + * the podcast to read an external feed. + * + * @param loginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void createCourseWithPodcast_externalFeed(@InitialPage LoginPage loginPage) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + loginPage.loginAs(author.getLogin(), author.getPassword()); + + //create a course + String courseTitle = "Course-With-Podcast-" + UUID.randomUUID(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + String podcastNodeTitle = "Podcats-1"; + String podcastTitle = "Podcast - " + UUID.randomUUID(); + + //create a course element of type podcast + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit(); + courseEditor + .createNode("podcast") + .nodeTitle(podcastNodeTitle) + .selectTabLearnContent() + .createFeed(podcastTitle); + + //publish the course + courseEditor + .publish() + .quickPublish(); + + //open the course and see the podcast + CoursePageFragment course = courseEditor + .clickToolbarBack(); + course + .clickTree() + .selectWithTitle(podcastNodeTitle); + + //check that the title of the podcast is correct + WebElement podcastH2 = browser.findElement(By.cssSelector("div.o_podcast_info>h2>i.o_FileResource-PODCAST_icon")); + Assert.assertNotNull(podcastH2); + //Assert.assertEquals(podcastTitle, podcastH2.getText().trim()); + + FeedPage feed = FeedPage.getFeedPage(browser); + feed.newExternalPodcast(podcastTitle, "http://podcasts.srf.ch/rock_special_mpx.xml"); + + //check only that the "episodes" title is visible + /* + By episodeTitleby = By.cssSelector("div.o_podcast_episodes>h4.o_title"); + OOGraphene.waitElement(episodeTitleby, 20, browser); + WebElement episodeH4 = browser.findElement(episodeTitleby); + Assert.assertNotNull(episodeH4); + */ + } + + @Test + @RunAsClient + public void createCourseWithBlog_externalFeed(@InitialPage LoginPage loginPage) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + loginPage.loginAs(author.getLogin(), author.getPassword()); + + //create a course + String courseTitle = "Course-With-Blog-" + UUID.randomUUID().toString(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + String blogNodeTitle = "Blog-1"; + String blogTitle = "Blog - " + UUID.randomUUID(); + + //create a course element of type blog + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit(); + courseEditor + .createNode("blog") + .nodeTitle(blogNodeTitle) + .selectTabLearnContent() + .createFeed(blogTitle); + + //publish the course + courseEditor + .publish() + .quickPublish(); + + //open the course and see the blog + CoursePageFragment course = courseEditor + .clickToolbarBack(); + course + .clickTree() + .selectWithTitle(blogNodeTitle); + + //check that the title of the podcast is correct + WebElement podcastH2 = browser.findElement(By.cssSelector("div.o_blog_info>h2>i.o_FileResource-BLOG_icon")); + Assert.assertNotNull(podcastH2); + //Assert.assertEquals(blogTitle, podcastH2.getText().trim()); + + FeedPage feed = FeedPage.getFeedPage(browser); + feed.newExternalBlog(blogTitle, "https://www.openolat.com/feed/"); + + //check only that the subscription link is visible + /* + By subscriptionBy = By.cssSelector("div.o_subscription>a"); + OOGraphene.waitElement(subscriptionBy, 20, browser); + WebElement subscriptionLink = browser.findElement(subscriptionBy); + Assert.assertTrue(subscriptionLink.isDisplayed()); + */ + } + + /** + * An author create a course with a blog, open it, add a post. A student + * open the course, see the blog post. The author add a new post, the + * student must see it. + * + * @param loginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void blogWithMultipleUsers(@InitialPage LoginPage loginPage, + @Drone @Participant WebDriver participantDrone) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("Ryomou"); + + loginPage.loginAs(author.getLogin(), author.getPassword()); + + //create a course with a blog + String courseTitle = "Course-Blog-1-" + UUID.randomUUID().toString(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + String blogNodeTitle = "Blog-RW-1"; + String blogTitle = "Blog - RW - " + UUID.randomUUID().toString(); + + //create a course element of type blog with a blog + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit(); + courseEditor + .createNode("blog") + .nodeTitle(blogNodeTitle) + .selectTabLearnContent() + .createFeed(blogTitle); + //publish the course + courseEditor + .publish() + .quickPublish(); + + //open the course and see the blog + CoursePageFragment course = courseEditor + .clickToolbarBack(); + course + .clickTree() + .selectWithTitle(blogNodeTitle); + + String postTitle = "Blog-RW-1-" + UUID.randomUUID(); + String postSummary = "Some explantations as teaser"; + String postContent = "Content of the post"; + FeedPage feed = FeedPage.getFeedPage(browser); + feed + .newBlog() + .fillPostForm(postTitle, postSummary, postContent) + .publishPost(); + + //participant go to the blog + participantDrone.navigate().to(deploymentUrl); + LoginPage participantLogin = LoginPage.getLoginPage(participantDrone, deploymentUrl); + participantLogin.loginAs(participant.getLogin(), participant.getPassword()); + //search the course in "My courses" + NavigationPage participantNavigation = new NavigationPage(participantDrone); + participantNavigation + .openMyCourses() + .openSearch() + .extendedSearch(courseTitle) + .select(courseTitle) + .start(); + //Navigate the course to the blog + CoursePageFragment participantCourse = new CoursePageFragment(participantDrone); + participantCourse + .clickTree() + .selectWithTitle(blogNodeTitle); + FeedPage participantFeed = FeedPage.getFeedPage(participantDrone); + participantFeed.assertOnBlogPost(postTitle); + + //the author publish a second post in its blog + String post2Title = "Blog-RW-2-" + UUID.randomUUID(); + String post2Summary = "Some explantations as teaser"; + String post2Content = "Content of the post"; + feed.addBlogPost() + .fillPostForm(post2Title, post2Summary, post2Content) + .publishPost(); + + //the participant must see the new post after some click + participantFeed + .clickFirstMonthOfPager() + .assertOnBlogPost(post2Title); + } + + + /** + * Login, create a course, select "Messages Course", insert an info message + * course element, publish the course, add messages, count if the messages + * are there, show older messages, count the messages, show current messages, + * count the messages, edit a message and delete an other, count the messages. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void createCourseWithInfoMessages(@InitialPage LoginPage authorLoginPage) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //go to authoring + AuthoringEnvPage authoringEnv = navBar + .assertOnNavigationPage() + .openAuthoringEnvironment(); + + String title = "Course Msg " + UUID.randomUUID().toString(); + //create course + authoringEnv + .openCreateDropDown() + .clickCreate(ResourceType.course) + .fillCreateForm(title) + .assertOnGeneralTab() + .clickToolbarBack(); + + String infoNodeTitle = "Infos - News"; + //open course editor + CoursePageFragment course = CoursePageFragment.getCourse(browser); + CourseEditorPageFragment editor = course + .assertOnCoursePage() + .assertOnTitle(title) + .openToolsMenu() + .edit() + .createNode("info") + .nodeTitle(infoNodeTitle); + + //configure the info messages + InfoMessageCEPage infoMsgConfig = new InfoMessageCEPage(browser); + infoMsgConfig + .selectConfiguration() + .configure(3); + + //publish + editor + .publish() + .quickPublish(UserAccess.registred); + editor.clickToolbarBack(); + + course + .clickTree() + .selectWithTitle(infoNodeTitle); + //set a message + infoMsgConfig + .createMessage() + .setMessage("Information 0", "A very important info") + .next() + .finish() + .assertOnMessageTitle("Information 0"); + + for(int i=1; i<=3; i++) { + infoMsgConfig.quickMessage("Information " + i, "More informations"); + } + + int numOfMessages = infoMsgConfig.countMessages(); + Assert.assertEquals(3, numOfMessages); + + // count old messages + int numOfOldMessages = infoMsgConfig + .oldMessages() + .countMessages(); + Assert.assertEquals(4, numOfOldMessages); + + //new messages + infoMsgConfig.newMessages(); + int numOfNewMessages = infoMsgConfig.countMessages(); + Assert.assertEquals(3, numOfNewMessages); + + //edit + infoMsgConfig + .oldMessages(); + infoMsgConfig + .editMessage("Information 2") + .setMessage("The latest information", "A very important info") + .save() + .assertOnMessageTitle("The latest information"); + + //delete + infoMsgConfig + .deleteMessage("Information 3") + .confirmDelete(); + + int numOfSurvivingMessages = infoMsgConfig.countMessages(); + Assert.assertEquals(3, numOfSurvivingMessages); + } + + /** + * An author create a course with a dialog course element. It + * add a participant to the course, a file to the dialog in + * the course element configuration and after publishing the course + * in the view of the dialog. It opens the forum of one of the files, + * create a new thread.<br> + * The participant log in, open the course and the dialog element. It + * reads the thread and make a reply. The author answers to the reply. + * + * @param loginPage + */ + @Test + @RunAsClient + public void createCourseWithDialog(@InitialPage LoginPage authorLoginPage, + @Drone @Participant WebDriver participantBrowser) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("Rei"); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //go to authoring + AuthoringEnvPage authoringEnv = navBar + .assertOnNavigationPage() + .openAuthoringEnvironment(); + + String title = "Course dialog " + UUID.randomUUID(); + //create course + authoringEnv + .openCreateDropDown() + .clickCreate(ResourceType.course) + .fillCreateForm(title) + .assertOnGeneralTab() + .clickToolbarBack(); + + //add a participant + MembersPage members = new CoursePageFragment(browser) + .members(); + members + .addMember() + .searchMember(participant, true) + .nextUsers() + .nextOverview() + .selectRepositoryEntryRole(false, false, true) + .nextPermissions() + .finish(); + members + .clickToolbarBack(); + + String dialogNodeTitle = "Dialog"; + //open course editor + CoursePageFragment course = CoursePageFragment.getCourse(browser); + CourseEditorPageFragment editor = course + .assertOnCoursePage() + .assertOnTitle(title) + .openToolsMenu() + .edit() + .createNode("dialog") + .nodeTitle(dialogNodeTitle); + + //upload a file in the configuration + URL imageUrl = JunitTestHelper.class.getResource("file_resources/IMG_1482.JPG"); + File imageFile = new File(imageUrl.toURI()); + DialogConfigurationPage dialogConfig = new DialogConfigurationPage(browser); + dialogConfig + .selectConfiguration() + .uploadFile(imageFile); + + //publish and go to the course element + editor + .publish() + .quickPublish(UserAccess.membersOnly); + editor + .clickToolbarBack(); + course + .clickTree() + .selectWithTitle(dialogNodeTitle); + + // upload a second file + URL imageRunUrl = JunitTestHelper.class.getResource("file_resources/IMG_1483.png"); + File imageRunFile = new File(imageRunUrl.toURI()); + DialogPage dialog = new DialogPage(browser); + dialog + .assertOnFile(imageFile.getName()) + .uploadFile(imageRunFile) + .assertOnFile(imageRunFile.getName()) + .openForum(imageRunFile.getName()) + .createThread("JPEG vs PNG", "Which is the best format", null); + + // The participant come in + LoginPage participantLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + participantLoginPage + .loginAs(participant.getLogin(), participant.getPassword()) + .resume(); + + // The participant find the course + NavigationPage participantNavBar = new NavigationPage(participantBrowser); + participantNavBar + .assertOnNavigationPage() + .openMyCourses() + .select(title); + // And opens the dialog course element + CoursePageFragment participantCourse = CoursePageFragment.getCourse(participantBrowser); + participantCourse + .clickTree() + .selectWithTitle(dialogNodeTitle); + DialogPage participantDialog = new DialogPage(participantBrowser); + participantDialog + .assertOnFile(imageRunFile.getName()) + .openForum(imageRunFile.getName()) + .openThread("JPEG vs PNG") + .replyToMessage("JPEG vs PNG", "PNG for sure", "Not a loosy format"); + + //The author reload the messages + dialog + .openForum(imageRunFile.getName()) + .openThread("JPEG vs PNG") + .assertMessageBody("Not a loosy format") + .replyToMessage("PNG for sure", "JPEG smaller", "JPEG is smaller"); + + //The participant check the reply + participantDialog + .openForum(imageRunFile.getName()) + .openThread("JPEG vs PNG") + .assertMessageBody("JPEG is smaller"); + } + + + /** + * An author create a course with a member list course element. + * It add two participants and a coach. It publish the course and + * check that it sees the authors, coaches and participants.<br> + * After that, it edits the course and change the settins to only + * show the participants. It checks that only the participants are + * visible.<br> + * At least, it changes the settings a second time to only show + * the course coaches. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void createCourseWithMemberList(@InitialPage LoginPage authorLoginPage) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO coach = new UserRestClient(deploymentUrl).createRandomUser("Rei"); + UserVO participant1 = new UserRestClient(deploymentUrl).createRandomUser("Kanu"); + UserVO participant2 = new UserRestClient(deploymentUrl).createRandomUser("Ryomou"); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //go to authoring + AuthoringEnvPage authoringEnv = navBar + .assertOnNavigationPage() + .openAuthoringEnvironment(); + + String title = "Course partilist " + UUID.randomUUID(); + //create course + authoringEnv + .openCreateDropDown() + .clickCreate(ResourceType.course) + .fillCreateForm(title) + .assertOnGeneralTab() + .clickToolbarBack(); + + //add 2 participants + CoursePageFragment course = new CoursePageFragment(browser); + MembersPage members = course + .members(); + members + .importMembers() + .setMembers(participant1, participant2) + .nextUsers() + .nextOverview() + .nextPermissions() + .finish(); + //add a coach + course + .members() + .addMember() + .searchMember(coach, true) + .nextUsers() + .nextOverview() + .selectRepositoryEntryRole(false, true, false) + .nextPermissions() + .finish(); + members + .clickToolbarBack(); + + String memberListTitle = "MemberList"; + //open course editor + CourseEditorPageFragment editor = course + .assertOnCoursePage() + .assertOnTitle(title) + .openToolsMenu() + .edit() + .createNode("cmembers") + .nodeTitle(memberListTitle); + //publish + editor + .publish() + .quickPublish(UserAccess.registred); + editor + .clickToolbarBack(); + + course + .clickTree() + .selectWithTitle(memberListTitle); + + //check the default configuration with authors, coaches and participants + MemberListPage memberList = new MemberListPage(browser); + memberList + .assertOnOwner(author.getFirstName()) + .assertOnCoach(coach.getFirstName()) + .assertOnParticipant(participant1.getFirstName()) + .assertOnParticipant(participant2.getFirstName()); + + //the author is not satisfied with the configuration + editor = course + .openToolsMenu() + .edit() + .selectNode(memberListTitle); + MemberListConfigurationPage memberListConfig = new MemberListConfigurationPage(browser); + memberListConfig + .selectSettings() + .setOwners(Boolean.FALSE) + .setCoaches(Boolean.FALSE) + .save(); + + //go check the results + course = editor + .autoPublish(); + course + .clickTree() + .selectWithTitle(memberListTitle); + + memberList + .assertOnMembers() + .assertOnNotOwner(author.getFirstName()) + .assertOnNotCoach(coach.getFirstName()) + .assertOnParticipant(participant1.getFirstName()) + .assertOnParticipant(participant2.getFirstName()); + + // perhaps only the coaches + editor = course + .openToolsMenu() + .edit() + .selectNode(memberListTitle); + memberListConfig = new MemberListConfigurationPage(browser); + memberListConfig + .selectSettings() + .setCoaches(Boolean.TRUE) + .setCourseCoachesOnly() + .setParticipants(Boolean.FALSE) + .save(); + + //go check that we see only the coaches results + course = editor + .autoPublish(); + course + .clickTree() + .selectWithTitle(memberListTitle); + + memberList + .assertOnMembers() + .assertOnNotOwner(author.getFirstName()) + .assertOnCoach(coach.getFirstName()) + .assertOnNotParticipant(participant1.getFirstName()) + .assertOnNotParticipant(participant2.getFirstName()); + } + + /** + * An author create a course with a participant folder course + * element. It add a participant to the course and upload file + * in the return box of this participant.<br> + * The participant come in and open the course, see the file + * uploaded by the author in its return box and it uploads an + * image in its drop box. The author go the see the image. + * + * @param authorLoginPage + * @param participantBrowser + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void createCourseWithParticipantFolder(@InitialPage LoginPage authorLoginPage, + @Drone @Participant WebDriver participantBrowser) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("Ryomou"); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //go to authoring + AuthoringEnvPage authoringEnv = navBar + .assertOnNavigationPage() + .openAuthoringEnvironment(); + + String title = "Course partilist " + UUID.randomUUID(); + //create course + authoringEnv + .openCreateDropDown() + .clickCreate(ResourceType.course) + .fillCreateForm(title) + .assertOnGeneralTab() + .clickToolbarBack(); + + String participantFolderTitle = "ParticipantList"; + //open course editor + CoursePageFragment course = CoursePageFragment.getCourse(browser); + CourseEditorPageFragment editor = course + .assertOnCoursePage() + .assertOnTitle(title) + .openToolsMenu() + .edit() + .createNode("pf") + .nodeTitle(participantFolderTitle); + //publish + editor + .publish() + .quickPublish(UserAccess.membersOnly); + editor + .clickToolbarBack(); + + //add a participant + MembersPage members = new CoursePageFragment(browser) + .members(); + members + .addMember() + .searchMember(participant, true) + .nextUsers() + .nextOverview() + .selectRepositoryEntryRole(false, false, true) + .nextPermissions() + .finish(); + members + .clickToolbarBack(); + + //go to the course element + course + .clickTree() + .selectWithTitle(participantFolderTitle); + // open the return box of the participant and upload a file + URL coachImageUrl = JunitTestHelper.class.getResource("file_resources/IMG_1482.JPG"); + File coachImageFile = new File(coachImageUrl.toURI()); + ParticipantFolderPage folder = new ParticipantFolderPage(browser); + folder + .assertOnParticipantsList() + .assertOnParticipant(participant.getFirstName()) + .openParticipantFolder(participant.getFirstName()); + FolderPage directory = folder + .openReturnBox() + .uploadFile(coachImageFile) + .assertOnFile(coachImageFile.getName()); + + // The participant come in + LoginPage participantLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + participantLoginPage + .loginAs(participant.getLogin(), participant.getPassword()) + .resume(); + + // The participant find the course + NavigationPage participantNavBar = new NavigationPage(participantBrowser); + participantNavBar + .assertOnNavigationPage() + .openMyCourses() + .select(title); + // And opens the participant folder + CoursePageFragment participantCourse = CoursePageFragment.getCourse(participantBrowser); + participantCourse + .clickTree() + .selectWithTitle(participantFolderTitle); + ParticipantFolderPage participantFolder = new ParticipantFolderPage(participantBrowser); + participantFolder + .openReturnBox() + .assertOnFile(coachImageFile.getName()) + .selectRootDirectory(); + // Participant upload a file in its drop box + URL participantImageUrl = JunitTestHelper.class.getResource("file_resources/IMG_1482.JPG"); + File participantImageFile = new File(participantImageUrl.toURI()); + participantFolder + .openDropBox() + .uploadFile(participantImageFile) + .assertOnFile(participantImageFile.getName()); + + //Author check the image in the participant drop box + directory + .selectRootDirectory(); + folder.openDropBox() + .assertOnFile(participantImageFile.getName()); + } + + + /** + * An author creates a course with a forum, publish it, open a new thread. + * A first user come to see the thread. A second come via the peekview. + * The three make a reply at the same time. And they check that they see + * the replies, and the ones of the others. + * + * @param loginPage + * @param kanuBrowser + * @param reiBrowser + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void forumConcurrent(@InitialPage LoginPage loginPage, + @Drone @Participant WebDriver kanuBrowser, + @Drone @Student WebDriver reiBrowser) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO kanu = new UserRestClient(deploymentUrl).createRandomUser("Kanu"); + UserVO rei = new UserRestClient(deploymentUrl).createRandomUser("Rei"); + loginPage.loginAs(author.getLogin(), author.getPassword()); + + //create a course + String courseTitle = "Course FO " + UUID.randomUUID(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + //go the authoring environment to create a forum + String foTitle = "FO - " + UUID.randomUUID(); + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit(); + courseEditor + .createNode("fo") + .nodeTitle(foTitle) + //publish the course + .publish() + .quickPublish(UserAccess.registred); + + //go to the forum + courseEditor + .clickToolbarBack() + .clickTree() + .selectWithTitle(foTitle.substring(0, 20)); + + ForumPage authorForum = ForumPage + .getCourseForumPage(browser); + authorForum + .createThread("The best anime ever", "What is the best anime ever?", null); + + //First user go to the course + LoginPage kanuLoginPage = LoginPage.getLoginPage(kanuBrowser, deploymentUrl); + kanuLoginPage + .loginAs(kanu.getLogin(), kanu.getPassword()) + .resume(); + + NavigationPage kanuNavBar = new NavigationPage(kanuBrowser); + kanuNavBar + .openMyCourses() + .openSearch() + .extendedSearch(courseTitle) + .select(courseTitle) + .start(); + + //go to the forum + new CoursePageFragment(kanuBrowser) + .clickTree() + .selectWithTitle(foTitle.substring(0, 20)); + + ForumPage kanuForum = ForumPage + .getCourseForumPage(kanuBrowser) + .openThread("The best anime ever"); + + //First user go to the course + LoginPage reiLoginPage = LoginPage.getLoginPage(reiBrowser, deploymentUrl); + reiLoginPage + .loginAs(rei) + .resume(); + + NavigationPage reiNavBar = new NavigationPage(reiBrowser); + reiNavBar + .openMyCourses() + .openSearch() + .extendedSearch(courseTitle) + .select(courseTitle) + .start(); + //select the thread in peekview + ForumPage reiForum = new ForumPage(reiBrowser) + .openThreadInPeekview("The best anime ever"); + + //concurrent reply + String kanuReply = "Ikki Touzen"; + String reiReply = "Neon Genesis Evangelion"; + String authorReply = "Lain, serial experiment"; + + authorForum + .replyToMessageNoWait("The best anime ever", null, authorReply); + reiForum + .replyToMessageNoWait("The best anime ever", null, reiReply); + kanuForum + .replyToMessageNoWait("The best anime ever", null, kanuReply); + + //wait the responses + OOGraphene.waitBusy(browser); + OOGraphene.waitBusy(kanuBrowser); + OOGraphene.waitBusy(reiBrowser); + + //check own responses + authorForum.assertMessageBody(authorReply); + kanuForum.assertMessageBody(kanuReply); + reiForum.assertMessageBody(reiReply); + + //check others responses + authorForum + .flatView() + .waitMessageBody(kanuReply); + reiForum + .flatView() + .waitMessageBody(kanuReply); + kanuForum + .flatView() + .waitMessageBody(reiReply); + } + + + /** + * An administrator create a category in catalog. It creates a new course + * with a forum open to guests. it publish the course in the + * catalog.<br> + * The guest find the course, create a new thread. The administrator reply + * to the message, the guest to its reply.<br> + * The administrator checks the last message in its new messages, click + * back, use the list of users to see the messages of the guest. It clicks + * back to the threads list and checks the thread has 3 messages. + * + * @param loginPage + * @param guestBrowser + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void forumWithGuest(@InitialPage LoginPage loginPage, + @Drone @User WebDriver guestBrowser) + throws IOException, URISyntaxException { + + loginPage + .loginAs("administrator", "openolat") + .resume(); + + String node1 = "Forums " + UUID.randomUUID(); + navBar + .openCatalogAdministration() + .addCatalogNode(node1, "First level of the catalog"); + + //create a course + String courseTitle = "Guest FO " + UUID.randomUUID(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + //go the authoring environment to create a forum + String foTitle = "GFO - " + UUID.randomUUID(); + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit(); + courseEditor + .createNode("fo") + .nodeTitle(foTitle); + //configure for guest + ForumCEPage forumConfig = new ForumCEPage(browser); + forumConfig + .selectConfiguration() + .allowGuest(); + + //publish the course + courseEditor + .publish() + .nextSelectNodes() + .selectAccess(UserAccess.guest) + .nextAccess() + .selectCatalog(true) + .selectCategory(null, node1) + .nextCatalog() // -> no problem found + .finish(); + //back in course + courseEditor.clickToolbarBack(); + + // guest go to the catalog and find the course + LoginPage guestLogin = LoginPage.getLoginPage(guestBrowser, deploymentUrl); + guestLogin + .asGuest(); + + NavigationPage guestNavBar = new NavigationPage(guestBrowser); + guestNavBar + .openCatalog() + .selectCatalogEntry(node1) + .select(courseTitle) + .start(); + + //go to the forum + new CoursePageFragment(guestBrowser) + .clickTree() + .selectWithTitle(foTitle.substring(0, 20)); + + String guestAlias = "Guest-" + UUID.randomUUID(); + ForumPage guestForum = ForumPage + .getCourseForumPage(guestBrowser) + .createThread("Your favorite author", "Name your favorite author", guestAlias); + + // admin go to the forum + new CoursePageFragment(browser) + .clickTree() + .selectWithTitle(foTitle.substring(0, 20)); + //admin reply to the thread of guest + ForumPage adminForum = ForumPage + .getCourseForumPage(browser) + .openThread("Your favorite author") + .assertOnGuestPseudonym(guestAlias) + .newMessages() + .assertOnGuestPseudonym(guestAlias) + .replyToMessage("Your favorite author", "Huxley is my favorite author", "My favorite author is Huxley"); + + //guest refresh the view and reply to admin + guestForum + .flatView() + .assertMessageBody("Huxley") + .replyToMessage("Huxley is my favorite author", " I prefer Orwell", "Orwell is my favorite author"); + + //admin see its new messages, see the list of users, select the guest and its messages + OOGraphene.waitingALittleLonger();//JMS message need to be delivered + adminForum + .newMessages() + .assertMessageBody("Orwell") + .clickBack() + .userFilter() + .selectFilteredUser(guestAlias) + .assertMessageBody("Orwell") + .clickBack() + .clickBack() + .assertThreadListOnNumber("Your favorite author", 3); + } + + + + + + /** + * An author setup a course with a LTI course element with score enabled. + * A participant take the course and see the LTI content. The back channel + * need the url of the OpenOLAT instance which is currently difficult + * for a selenium test. The grading is not tested until a LTI server + * can be installed on localhost. + * + * @param authorLoginPage + * @param participantBrowser + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void createCourseWithLTI(@InitialPage LoginPage authorLoginPage, + @Drone @User WebDriver participantBrowser) + throws IOException, URISyntaxException { + + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("Ryomou"); + + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //create a course + String courseTitle = "Course-LTI-" + UUID.randomUUID(); + navBar + .openAuthoringEnvironment() + .createCourse(courseTitle) + .clickToolbarBack(); + + //create a course element of type Test with the test that we create above + String ltiTitle = "LTI"; + CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) + .edit() + .createNode("lti") + .nodeTitle(ltiTitle); + + //configure assessment + LTIConfigurationPage ltiConfig = new LTIConfigurationPage(browser); + ltiConfig + .selectConfiguration() + .setLtiPage("http://lti.frentix.com/tool.php", "123456", "secret") + .enableScore(10.0d, 5.0d) + .save(); + //set the score / passed calculation in root node and publish + courseEditor + .selectRoot() + .selectTabScore() + .enableRootScoreByNodes() + .autoPublish() + .accessConfiguration() + .setUserAccess(UserAccess.registred); + + //go to members management + CoursePageFragment courseRuntime = courseEditor.clickToolbarBack(); + MembersPage members = courseRuntime + .members(); + members + .addMember() + .searchMember(participant, true) + .nextUsers() + .nextOverview() + .nextPermissions() + .finish(); + + //Participant login + LoginPage participantLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + participantLoginPage + .loginAs(participant.getLogin(), participant.getPassword()) + .resume(); + + NavigationPage participantNavBar = new NavigationPage(participantBrowser); + participantNavBar + .openMyCourses() + .openSearch() + .extendedSearch(courseTitle) + .select(courseTitle); + + CoursePageFragment participantCourse = new CoursePageFragment(participantBrowser); + participantCourse + .clickTree() + .selectWithTitle(ltiTitle); + LTIPage lti = new LTIPage(participantBrowser); + lti + .start() + .outcomeToolProvider(); + //.sendGrade(0.8d); + } +} diff --git a/src/test/java/org/olat/selenium/CourseTest.java b/src/test/java/org/olat/selenium/CourseTest.java index ab7d40f77114cba0f9e6ac7a9c2b120bfe15ab51..b60c7d017177405b01e085e623acd2515afeb7d0 100644 --- a/src/test/java/org/olat/selenium/CourseTest.java +++ b/src/test/java/org/olat/selenium/CourseTest.java @@ -57,23 +57,20 @@ import org.olat.selenium.page.course.AssessmentToolPage; import org.olat.selenium.page.course.CourseEditorPageFragment; import org.olat.selenium.page.course.CoursePageFragment; import org.olat.selenium.page.course.CourseWizardPage; -import org.olat.selenium.page.course.DialogConfigurationPage; -import org.olat.selenium.page.course.DialogPage; -import org.olat.selenium.page.course.ForumCEPage; -import org.olat.selenium.page.course.InfoMessageCEPage; import org.olat.selenium.page.course.MembersPage; import org.olat.selenium.page.course.PublisherPageFragment; import org.olat.selenium.page.course.RemindersPage; -import org.olat.selenium.page.forum.ForumPage; import org.olat.selenium.page.graphene.OOGraphene; +import org.olat.selenium.page.lecture.LectureListRepositoryPage; +import org.olat.selenium.page.lecture.LectureRepositoryAdminPage; +import org.olat.selenium.page.lecture.RollCallInterceptorPage; +import org.olat.selenium.page.lecture.TeacherRollCallPage; import org.olat.selenium.page.repository.AuthoringEnvPage; import org.olat.selenium.page.repository.AuthoringEnvPage.ResourceType; import org.olat.selenium.page.repository.CPPage; -import org.olat.selenium.page.repository.FeedPage; import org.olat.selenium.page.repository.RepositoryAccessPage; import org.olat.selenium.page.repository.RepositoryAccessPage.UserAccess; import org.olat.selenium.page.repository.RepositoryEditDescriptionPage; -import org.olat.selenium.page.repository.ScormPage; import org.olat.selenium.page.user.UserToolsPage; import org.olat.test.ArquillianDeployments; import org.olat.test.JunitTestHelper; @@ -535,495 +532,6 @@ public class CourseTest { .assertOnTitle(newCourseName); } - /** - * Create a course, create a CP, go the the course editor, - * create a course element of type CP, select the CP which just created, - * close the course editor and check the presence of the CP with the - * default title of the first page. - * - * @param loginPage - * @throws IOException - * @throws URISyntaxException - */ - @Test - @RunAsClient - public void createCourseWithCP(@InitialPage LoginPage loginPage) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - loginPage.loginAs(author.getLogin(), author.getPassword()); - - //create a course - String courseTitle = "Course-With-CP-" + UUID.randomUUID().toString(); - navBar - .openAuthoringEnvironment() - .createCourse(courseTitle) - .clickToolbarBack(); - - //go the authoring environment to create a CP - String cpTitle = "CP for a course - " + UUID.randomUUID().toString(); - navBar - .openAuthoringEnvironment() - .createCP(cpTitle) - .assertOnGeneralTab(); - - navBar.openCourse(courseTitle); - - String cpNodeTitle = "CP-1"; - //create a course element of type CP with the CP that we create above - CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) - .edit(); - courseEditor - .createNode("cp") - .nodeTitle(cpNodeTitle) - .selectTabLearnContent() - .chooseCP(cpTitle); - - //publish the course - courseEditor - .publish() - .quickPublish(); - - //open the course and see the CP - CoursePageFragment course = courseEditor - .clickToolbarBack(); - - course - .clickTree() - .selectWithTitle(cpNodeTitle); - - //check that the default title of CP (Lorem Ipsum) is visible in the iframe - WebElement cpIframe = browser.findElement(By.cssSelector("div.o_iframedisplay>iframe")); - browser.switchTo().frame(cpIframe); - browser.findElement(By.xpath("//h2[text()='Lorem Ipsum']")); - } - - /** - * This test an edge case where a course start automatically its first - * course element, which is a structure node which start itself its first - * element, which is a SCORM which launch itself automatically. - * - * @param loginPage - */ - @Test - @RunAsClient - public void courseWithSCORM_fullAuto(@InitialPage LoginPage loginPage) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - loginPage.loginAs(author.getLogin(), author.getPassword()); - - URL zipUrl = JunitTestHelper.class.getResource("file_resources/scorm/SCORM_course_full_auto.zip"); - File zipFile = new File(zipUrl.toURI()); - //go the authoring environment to import our course - String zipTitle = "SCORM - " + UUID.randomUUID(); - navBar - .openAuthoringEnvironment() - .uploadResource(zipTitle, zipFile); - - // publish the course - new RepositoryEditDescriptionPage(browser) - .clickToolbarBack(); - CoursePageFragment.getCourse(browser) - .edit() - .autoPublish(); - - //scorm is auto started -> back - ScormPage.getScormPage(browser) - .back(); - - //log out - new UserToolsPage(browser) - .logout(); - - //log in and resume test - loginPage - .loginAs(author.getLogin(), author.getPassword()) - .resume(); - // direct jump in SCORM content - ScormPage.getScormPage(browser) - .passVerySimpleScorm() - .back() - .assertOnScormPassed() - .assertOnScormScore(33); - } - - /** - * Create a course, create a wiki, go the the course editor, - * create a course element of type wiki, select the wiki which just created, - * close the course editor and select the index page of the wiki. - * - * @param loginPage - * @throws IOException - * @throws URISyntaxException - */ - @Test - @RunAsClient - public void createCourseWithWiki(@InitialPage LoginPage loginPage) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - loginPage.loginAs(author.getLogin(), author.getPassword()); - - //create a course - String courseTitle = "Course-With-Wiki-" + UUID.randomUUID().toString(); - navBar - .openAuthoringEnvironment() - .createCourse(courseTitle) - .clickToolbarBack(); - - //go the authoring environment to create a CP - String wikiTitle = "Wiki for a course - " + UUID.randomUUID().toString(); - navBar - .openAuthoringEnvironment() - .createWiki(wikiTitle) - .assertOnGeneralTab(); - - navBar.openCourse(courseTitle); - - String wikiNodeTitle = "Wiki-1"; - //create a course element of type CP with the CP that we create above - CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) - .edit(); - courseEditor - .createNode("wiki") - .nodeTitle(wikiNodeTitle) - .selectTabLearnContent() - .chooseWiki(wikiTitle); - - //publish the course - courseEditor - .publish() - .quickPublish(); - - //open the course and see the CP - CoursePageFragment course = courseEditor - .clickToolbarBack(); - - course - .clickTree() - .selectWithTitle(wikiNodeTitle) - .selectWithTitle("Index"); - - //check that the title of the index article/page is visible - WebElement indexArticleTitle = browser.findElement(By.className("o_wikimod_heading")); - Assert.assertEquals("Index", indexArticleTitle.getText().trim()); - } - - /** - * Create a course, create a course element of type wiki. Open - * the resource chooser, create a wiki, close the editor, show the - * index page of the wiki. - * - * @param loginPage - * @throws IOException - * @throws URISyntaxException - */ - @Test - @RunAsClient - public void createCourseWithWiki_createInCourseEditor(@InitialPage LoginPage loginPage) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - loginPage.loginAs(author.getLogin(), author.getPassword()); - - //create a course - String courseTitle = "Course-With-Wiki-" + UUID.randomUUID().toString(); - navBar - .openAuthoringEnvironment() - .createCourse(courseTitle) - .clickToolbarBack(); - - String wikiNodeTitle = "Wiki-1"; - String wikiTitle = "Wiki for a course - " + UUID.randomUUID().toString(); - - //create a course element of type CP with the CP that we create above - CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) - .edit(); - courseEditor - .createNode("wiki") - .nodeTitle(wikiNodeTitle) - .selectTabLearnContent() - .createWiki(wikiTitle); - - //publish the course - courseEditor - .publish() - .quickPublish(); - - //open the course and see the CP - CoursePageFragment course = courseEditor - .clickToolbarBack(); - - course - .clickTree() - .selectWithTitle(wikiNodeTitle) - .selectWithTitle("Index"); - - //check that the title of the index article/page is visible - WebElement indexArticleTitle = browser.findElement(By.className("o_wikimod_heading")); - Assert.assertEquals("Index", indexArticleTitle.getText().trim()); - } - - @Test - @RunAsClient - public void createCourseWithQTITest(@InitialPage LoginPage loginPage) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - loginPage.loginAs(author.getLogin(), author.getPassword()); - - //create a course - String courseTitle = "Course-With-QTI-Test-1.2-" + UUID.randomUUID().toString(); - navBar - .openAuthoringEnvironment() - .createCourse(courseTitle) - .clickToolbarBack(); - - String testNodeTitle = "QTITest-1"; - String testTitle = "Test - " + UUID.randomUUID().toString(); - - //create a course element of type CP with the CP that we create above - CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) - .edit(); - courseEditor - .createNode("iqtest") - .nodeTitle(testNodeTitle) - .selectTabLearnContent() - .createQTI12Test(testTitle); - - //publish the course - courseEditor - .publish() - .quickPublish(); - - //open the course and see the CP - CoursePageFragment course = courseEditor - .clickToolbarBack(); - - course - .clickTree() - .selectWithTitle(testNodeTitle); - - //check that the title of the start page of test is correct - WebElement testH2 = browser.findElement(By.cssSelector("div.o_course_run h2")); - Assert.assertEquals(testNodeTitle, testH2.getText().trim()); - } - - /** - * Create a course with a course element of type podcast. Create - * a podcast, publish the course, go the the course and configure - * the podcast to read an external feed. - * - * @param loginPage - * @throws IOException - * @throws URISyntaxException - */ - @Test - @RunAsClient - public void createCourseWithPodcast_externalFeed(@InitialPage LoginPage loginPage) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - loginPage.loginAs(author.getLogin(), author.getPassword()); - - //create a course - String courseTitle = "Course-With-Podcast-" + UUID.randomUUID(); - navBar - .openAuthoringEnvironment() - .createCourse(courseTitle) - .clickToolbarBack(); - - String podcastNodeTitle = "Podcats-1"; - String podcastTitle = "Podcast - " + UUID.randomUUID(); - - //create a course element of type podcast - CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) - .edit(); - courseEditor - .createNode("podcast") - .nodeTitle(podcastNodeTitle) - .selectTabLearnContent() - .createFeed(podcastTitle); - - //publish the course - courseEditor - .publish() - .quickPublish(); - - //open the course and see the podcast - CoursePageFragment course = courseEditor - .clickToolbarBack(); - course - .clickTree() - .selectWithTitle(podcastNodeTitle); - - //check that the title of the podcast is correct - WebElement podcastH2 = browser.findElement(By.cssSelector("div.o_podcast_info>h2>i.o_FileResource-PODCAST_icon")); - Assert.assertNotNull(podcastH2); - //Assert.assertEquals(podcastTitle, podcastH2.getText().trim()); - - FeedPage feed = FeedPage.getFeedPage(browser); - feed.newExternalPodcast(podcastTitle, "http://podcasts.srf.ch/rock_special_mpx.xml"); - - //check only that the "episodes" title is visible - /* - By episodeTitleby = By.cssSelector("div.o_podcast_episodes>h4.o_title"); - OOGraphene.waitElement(episodeTitleby, 20, browser); - WebElement episodeH4 = browser.findElement(episodeTitleby); - Assert.assertNotNull(episodeH4); - */ - } - - @Test - @RunAsClient - public void createCourseWithBlog_externalFeed(@InitialPage LoginPage loginPage) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - loginPage.loginAs(author.getLogin(), author.getPassword()); - - //create a course - String courseTitle = "Course-With-Blog-" + UUID.randomUUID().toString(); - navBar - .openAuthoringEnvironment() - .createCourse(courseTitle) - .clickToolbarBack(); - - String blogNodeTitle = "Blog-1"; - String blogTitle = "Blog - " + UUID.randomUUID(); - - //create a course element of type blog - CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) - .edit(); - courseEditor - .createNode("blog") - .nodeTitle(blogNodeTitle) - .selectTabLearnContent() - .createFeed(blogTitle); - - //publish the course - courseEditor - .publish() - .quickPublish(); - - //open the course and see the blog - CoursePageFragment course = courseEditor - .clickToolbarBack(); - course - .clickTree() - .selectWithTitle(blogNodeTitle); - - //check that the title of the podcast is correct - WebElement podcastH2 = browser.findElement(By.cssSelector("div.o_blog_info>h2>i.o_FileResource-BLOG_icon")); - Assert.assertNotNull(podcastH2); - //Assert.assertEquals(blogTitle, podcastH2.getText().trim()); - - FeedPage feed = FeedPage.getFeedPage(browser); - feed.newExternalBlog(blogTitle, "https://www.openolat.com/feed/"); - - //check only that the subscription link is visible - /* - By subscriptionBy = By.cssSelector("div.o_subscription>a"); - OOGraphene.waitElement(subscriptionBy, 20, browser); - WebElement subscriptionLink = browser.findElement(subscriptionBy); - Assert.assertTrue(subscriptionLink.isDisplayed()); - */ - } - - /** - * An author create a course with a blog, open it, add a post. A student - * open the course, see the blog post. The author add a new post, the - * student must see it. - * - * @param loginPage - * @throws IOException - * @throws URISyntaxException - */ - @Test - @RunAsClient - public void blogWithMultipleUsers(@InitialPage LoginPage loginPage, - @Drone @Participant WebDriver participantDrone) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("Ryomou"); - - loginPage.loginAs(author.getLogin(), author.getPassword()); - - //create a course with a blog - String courseTitle = "Course-Blog-1-" + UUID.randomUUID().toString(); - navBar - .openAuthoringEnvironment() - .createCourse(courseTitle) - .clickToolbarBack(); - - String blogNodeTitle = "Blog-RW-1"; - String blogTitle = "Blog - RW - " + UUID.randomUUID().toString(); - - //create a course element of type blog with a blog - CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) - .edit(); - courseEditor - .createNode("blog") - .nodeTitle(blogNodeTitle) - .selectTabLearnContent() - .createFeed(blogTitle); - //publish the course - courseEditor - .publish() - .quickPublish(); - - //open the course and see the blog - CoursePageFragment course = courseEditor - .clickToolbarBack(); - course - .clickTree() - .selectWithTitle(blogNodeTitle); - - String postTitle = "Blog-RW-1-" + UUID.randomUUID(); - String postSummary = "Some explantations as teaser"; - String postContent = "Content of the post"; - FeedPage feed = FeedPage.getFeedPage(browser); - feed - .newBlog() - .fillPostForm(postTitle, postSummary, postContent) - .publishPost(); - - //participant go to the blog - participantDrone.navigate().to(deploymentUrl); - LoginPage participantLogin = LoginPage.getLoginPage(participantDrone, deploymentUrl); - participantLogin.loginAs(participant.getLogin(), participant.getPassword()); - //search the course in "My courses" - NavigationPage participantNavigation = new NavigationPage(participantDrone); - participantNavigation - .openMyCourses() - .openSearch() - .extendedSearch(courseTitle) - .select(courseTitle) - .start(); - //Navigate the course to the blog - CoursePageFragment participantCourse = new CoursePageFragment(participantDrone); - participantCourse - .clickTree() - .selectWithTitle(blogNodeTitle); - FeedPage participantFeed = FeedPage.getFeedPage(participantDrone); - participantFeed.assertOnBlogPost(postTitle); - - //the author publish a second post in its blog - String post2Title = "Blog-RW-2-" + UUID.randomUUID(); - String post2Summary = "Some explantations as teaser"; - String post2Content = "Content of the post"; - feed.addBlogPost() - .fillPostForm(post2Title, post2Summary, post2Content) - .publishPost(); - - //the participant must see the new post after some click - participantFeed - .clickFirstMonthOfPager() - .assertOnBlogPost(post2Title); - } - /** * * Create a catalog, create a course, while publishing add the @@ -1088,253 +596,23 @@ public class CourseTest { //the course LoginPage userLogin = LoginPage.getLoginPage(userBrowser, deploymentUrl); userLogin - .loginAs(user.getLogin(), user.getPassword()) - .resume(); - - NavigationPage userNavBar = new NavigationPage(userBrowser); - userNavBar - .openMyCourses() - .openCatalog() - .selectCatalogEntry(node1) - .selectCatalogEntry(node2_2) - .select(courseTitle)//go to the details page - .start(); - - By courseTitleBy = By.cssSelector("div.o_course_run h2"); - WebElement courseTitleEl = userBrowser.findElement(courseTitleBy); - Assert.assertTrue(courseTitleEl.getText().contains(courseTitle)); - } - - /** - * Login, create a course, select "Messages Course", insert an info message - * course element, publish the course, add messages, count if the messages - * are there, show older messages, count the messages, show current messages, - * count the messages, edit a message and delete an other, count the messages. - * - * @param authorLoginPage - * @throws IOException - * @throws URISyntaxException - */ - @Test - @RunAsClient - public void createCourseWithInfoMessages(@InitialPage LoginPage authorLoginPage) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - authorLoginPage.loginAs(author.getLogin(), author.getPassword()); - - //go to authoring - AuthoringEnvPage authoringEnv = navBar - .assertOnNavigationPage() - .openAuthoringEnvironment(); - - String title = "Course Msg " + UUID.randomUUID().toString(); - //create course - authoringEnv - .openCreateDropDown() - .clickCreate(ResourceType.course) - .fillCreateForm(title) - .assertOnGeneralTab() - .clickToolbarBack(); - - String infoNodeTitle = "Infos - News"; - //open course editor - CoursePageFragment course = CoursePageFragment.getCourse(browser); - CourseEditorPageFragment editor = course - .assertOnCoursePage() - .assertOnTitle(title) - .openToolsMenu() - .edit() - .createNode("info") - .nodeTitle(infoNodeTitle); - - //configure the info messages - InfoMessageCEPage infoMsgConfig = new InfoMessageCEPage(browser); - infoMsgConfig - .selectConfiguration() - .configure(3); - - //publish - editor - .publish() - .quickPublish(UserAccess.registred); - editor.clickToolbarBack(); - - course - .clickTree() - .selectWithTitle(infoNodeTitle); - //set a message - infoMsgConfig - .createMessage() - .setMessage("Information 0", "A very important info") - .next() - .finish() - .assertOnMessageTitle("Information 0"); - - for(int i=1; i<=3; i++) { - infoMsgConfig.quickMessage("Information " + i, "More informations"); - } - - int numOfMessages = infoMsgConfig.countMessages(); - Assert.assertEquals(3, numOfMessages); - - // count old messages - int numOfOldMessages = infoMsgConfig - .oldMessages() - .countMessages(); - Assert.assertEquals(4, numOfOldMessages); - - //new messages - infoMsgConfig.newMessages(); - int numOfNewMessages = infoMsgConfig.countMessages(); - Assert.assertEquals(3, numOfNewMessages); - - //edit - infoMsgConfig - .oldMessages(); - infoMsgConfig - .editMessage("Information 2") - .setMessage("The latest information", "A very important info") - .save() - .assertOnMessageTitle("The latest information"); - - //delete - infoMsgConfig - .deleteMessage("Information 3") - .confirmDelete(); - - int numOfSurvivingMessages = infoMsgConfig.countMessages(); - Assert.assertEquals(3, numOfSurvivingMessages); - } - - /** - * An author create a course with a dialog course element. It - * add a participant to the course, a file to the dialog in - * the course element configuration and after publishing the course - * in the view of the dialog. It opens the forum of one of the files, - * create a new thread.<br> - * The participant log in, open the course and the dialog element. It - * reads the thread and make a reply. The author answers to the reply. - * - * @param loginPage - */ - @Test - @RunAsClient - public void createCourseWithDialog(@InitialPage LoginPage authorLoginPage, - @Drone @Participant WebDriver participantBrowser) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - UserVO participant = new UserRestClient(deploymentUrl).createRandomUser("Rei"); - authorLoginPage.loginAs(author.getLogin(), author.getPassword()); - - //go to authoring - AuthoringEnvPage authoringEnv = navBar - .assertOnNavigationPage() - .openAuthoringEnvironment(); - - String title = "Course dialog " + UUID.randomUUID(); - //create course - authoringEnv - .openCreateDropDown() - .clickCreate(ResourceType.course) - .fillCreateForm(title) - .assertOnGeneralTab() - .clickToolbarBack(); - - //add a participant - MembersPage members = new CoursePageFragment(browser) - .members(); - members - .addMember() - .searchMember(participant, true) - .nextUsers() - .nextOverview() - .selectRepositoryEntryRole(false, false, true) - .nextPermissions() - .finish(); - members - .clickToolbarBack(); - - String dialogNodeTitle = "Dialog"; - //open course editor - CoursePageFragment course = CoursePageFragment.getCourse(browser); - CourseEditorPageFragment editor = course - .assertOnCoursePage() - .assertOnTitle(title) - .openToolsMenu() - .edit() - .createNode("dialog") - .nodeTitle(dialogNodeTitle); - - //upload a file in the configuration - URL imageUrl = JunitTestHelper.class.getResource("file_resources/IMG_1482.JPG"); - File imageFile = new File(imageUrl.toURI()); - DialogConfigurationPage dialogConfig = new DialogConfigurationPage(browser); - dialogConfig - .selectConfiguration() - .uploadFile(imageFile); - - //publish and go to the course element - editor - .publish() - .quickPublish(UserAccess.membersOnly); - editor - .clickToolbarBack(); - course - .clickTree() - .selectWithTitle(dialogNodeTitle); - - // upload a second file - URL imageRunUrl = JunitTestHelper.class.getResource("file_resources/IMG_1483.png"); - File imageRunFile = new File(imageRunUrl.toURI()); - DialogPage dialog = new DialogPage(browser); - dialog - .assertOnFile(imageFile.getName()) - .uploadFile(imageRunFile) - .assertOnFile(imageRunFile.getName()) - .openForum(imageRunFile.getName()) - .createThread("JPEG vs PNG", "Which is the best format", null); - - // The participant come in - LoginPage participantLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); - participantLoginPage - .loginAs(participant.getLogin(), participant.getPassword()) + .loginAs(user.getLogin(), user.getPassword()) .resume(); - - // The participant find the course - NavigationPage participantNavBar = new NavigationPage(participantBrowser); - participantNavBar - .assertOnNavigationPage() + + NavigationPage userNavBar = new NavigationPage(userBrowser); + userNavBar .openMyCourses() - .select(title); - // And opens the dialog course element - CoursePageFragment participantCourse = CoursePageFragment.getCourse(participantBrowser); - participantCourse - .clickTree() - .selectWithTitle(dialogNodeTitle); - DialogPage participantDialog = new DialogPage(participantBrowser); - participantDialog - .assertOnFile(imageRunFile.getName()) - .openForum(imageRunFile.getName()) - .openThread("JPEG vs PNG") - .replyToMessage("JPEG vs PNG", "PNG for sure", "Not a loosy format"); - - //The author reload the messages - dialog - .openForum(imageRunFile.getName()) - .openThread("JPEG vs PNG") - .assertMessageBody("Not a loosy format") - .replyToMessage("PNG for sure", "JPEG smaller", "JPEG is smaller"); - - //The participant check the reply - participantDialog - .openForum(imageRunFile.getName()) - .openThread("JPEG vs PNG") - .assertMessageBody("JPEG is smaller"); + .openCatalog() + .selectCatalogEntry(node1) + .selectCatalogEntry(node2_2) + .select(courseTitle)//go to the details page + .start(); + + By courseTitleBy = By.cssSelector("div.o_course_run h2"); + WebElement courseTitleEl = userBrowser.findElement(courseTitleBy); + Assert.assertTrue(courseTitleEl.getText().contains(courseTitle)); } - /** * Create a course with a calendar element, add a recurring event * all day, modify an occurence to an event between 13h and 15h. @@ -1671,6 +949,7 @@ public class CourseTest { reminders .addReminder() .setDescription(reminderTitle) + .setSubject(reminderTitle) .setTimeBasedRule(1, "RepositoryEntryLifecycleAfterValidFromRuleSPI", 5, "day") .addRule(1) .setRoleBasedRule(2, "RepositoryEntryRoleRuleSPI", "participant") @@ -1820,251 +1099,6 @@ public class CourseTest { .assertOnTitle(infoTitle); } - /** - * An author creates a course with a forum, publish it, open a new thread. - * A first user come to see the thread. A second come via the peekview. - * The three make a reply at the same time. And they check that they see - * the replies, and the ones of the others. - * - * @param loginPage - * @param kanuBrowser - * @param reiBrowser - * @throws IOException - * @throws URISyntaxException - */ - @Test - @RunAsClient - public void forumConcurrent(@InitialPage LoginPage loginPage, - @Drone @Participant WebDriver kanuBrowser, - @Drone @Student WebDriver reiBrowser) - throws IOException, URISyntaxException { - - UserVO author = new UserRestClient(deploymentUrl).createAuthor(); - UserVO kanu = new UserRestClient(deploymentUrl).createRandomUser("Kanu"); - UserVO rei = new UserRestClient(deploymentUrl).createRandomUser("Rei"); - loginPage.loginAs(author.getLogin(), author.getPassword()); - - //create a course - String courseTitle = "Course FO " + UUID.randomUUID(); - navBar - .openAuthoringEnvironment() - .createCourse(courseTitle) - .clickToolbarBack(); - - //go the authoring environment to create a forum - String foTitle = "FO - " + UUID.randomUUID(); - CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) - .edit(); - courseEditor - .createNode("fo") - .nodeTitle(foTitle) - //publish the course - .publish() - .quickPublish(UserAccess.registred); - - //go to the forum - courseEditor - .clickToolbarBack() - .clickTree() - .selectWithTitle(foTitle.substring(0, 20)); - - ForumPage authorForum = ForumPage - .getCourseForumPage(browser); - authorForum - .createThread("The best anime ever", "What is the best anime ever?", null); - - //First user go to the course - LoginPage kanuLoginPage = LoginPage.getLoginPage(kanuBrowser, deploymentUrl); - kanuLoginPage - .loginAs(kanu.getLogin(), kanu.getPassword()) - .resume(); - - NavigationPage kanuNavBar = new NavigationPage(kanuBrowser); - kanuNavBar - .openMyCourses() - .openSearch() - .extendedSearch(courseTitle) - .select(courseTitle) - .start(); - - //go to the forum - new CoursePageFragment(kanuBrowser) - .clickTree() - .selectWithTitle(foTitle.substring(0, 20)); - - ForumPage kanuForum = ForumPage - .getCourseForumPage(kanuBrowser) - .openThread("The best anime ever"); - - //First user go to the course - LoginPage reiLoginPage = LoginPage.getLoginPage(reiBrowser, deploymentUrl); - reiLoginPage - .loginAs(rei) - .resume(); - - NavigationPage reiNavBar = new NavigationPage(reiBrowser); - reiNavBar - .openMyCourses() - .openSearch() - .extendedSearch(courseTitle) - .select(courseTitle) - .start(); - //select the thread in peekview - ForumPage reiForum = new ForumPage(reiBrowser) - .openThreadInPeekview("The best anime ever"); - - //concurrent reply - String kanuReply = "Ikki Touzen"; - String reiReply = "Neon Genesis Evangelion"; - String authorReply = "Lain, serial experiment"; - - authorForum - .replyToMessageNoWait("The best anime ever", null, authorReply); - reiForum - .replyToMessageNoWait("The best anime ever", null, reiReply); - kanuForum - .replyToMessageNoWait("The best anime ever", null, kanuReply); - - //wait the responses - OOGraphene.waitBusy(browser); - OOGraphene.waitBusy(kanuBrowser); - OOGraphene.waitBusy(reiBrowser); - - //check own responses - authorForum.assertMessageBody(authorReply); - kanuForum.assertMessageBody(kanuReply); - reiForum.assertMessageBody(reiReply); - - //check others responses - authorForum - .flatView() - .waitMessageBody(kanuReply); - reiForum - .flatView() - .waitMessageBody(kanuReply); - kanuForum - .flatView() - .waitMessageBody(reiReply); - } - - - /** - * An administrator create a category in catalog. It creates a new course - * with a forum open to guests. it publish the course in the - * catalog.<br> - * The guest find the course, create a new thread. The administrator reply - * to the message, the guest to its reply.<br> - * The administrator checks the last message in its new messages, click - * back, use the list of users to see the messages of the guest. It clicks - * back to the threads list and checks the thread has 3 messages. - * - * @param loginPage - * @param guestBrowser - * @throws IOException - * @throws URISyntaxException - */ - @Test - @RunAsClient - public void forumWithGuest(@InitialPage LoginPage loginPage, - @Drone @User WebDriver guestBrowser) - throws IOException, URISyntaxException { - - loginPage - .loginAs("administrator", "openolat") - .resume(); - - String node1 = "Forums " + UUID.randomUUID(); - navBar - .openCatalogAdministration() - .addCatalogNode(node1, "First level of the catalog"); - - //create a course - String courseTitle = "Guest FO " + UUID.randomUUID(); - navBar - .openAuthoringEnvironment() - .createCourse(courseTitle) - .clickToolbarBack(); - - //go the authoring environment to create a forum - String foTitle = "GFO - " + UUID.randomUUID(); - CourseEditorPageFragment courseEditor = CoursePageFragment.getCourse(browser) - .edit(); - courseEditor - .createNode("fo") - .nodeTitle(foTitle); - //configure for guest - ForumCEPage forumConfig = new ForumCEPage(browser); - forumConfig - .selectConfiguration() - .allowGuest(); - - //publish the course - courseEditor - .publish() - .nextSelectNodes() - .selectAccess(UserAccess.guest) - .nextAccess() - .selectCatalog(true) - .selectCategory(null, node1) - .nextCatalog() // -> no problem found - .finish(); - //back in course - courseEditor.clickToolbarBack(); - - // guest go to the catalog and find the course - LoginPage guestLogin = LoginPage.getLoginPage(guestBrowser, deploymentUrl); - guestLogin - .asGuest(); - - NavigationPage guestNavBar = new NavigationPage(guestBrowser); - guestNavBar - .openCatalog() - .selectCatalogEntry(node1) - .select(courseTitle) - .start(); - - //go to the forum - new CoursePageFragment(guestBrowser) - .clickTree() - .selectWithTitle(foTitle.substring(0, 20)); - - String guestAlias = "Guest-" + UUID.randomUUID(); - ForumPage guestForum = ForumPage - .getCourseForumPage(guestBrowser) - .createThread("Your favorite author", "Name your favorite author", guestAlias); - - // admin go to the forum - new CoursePageFragment(browser) - .clickTree() - .selectWithTitle(foTitle.substring(0, 20)); - //admin reply to the thread of guest - ForumPage adminForum = ForumPage - .getCourseForumPage(browser) - .openThread("Your favorite author") - .assertOnGuestPseudonym(guestAlias) - .newMessages() - .assertOnGuestPseudonym(guestAlias) - .replyToMessage("Your favorite author", "Huxley is my favorite author", "My favorite author is Huxley"); - - //guest refresh the view and reply to admin - guestForum - .flatView() - .assertMessageBody("Huxley") - .replyToMessage("Huxley is my favorite author", " I prefer Orwell", "Orwell is my favorite author"); - - //admin see its new messages, see the list of users, select the guest and its messages - OOGraphene.waitingALittleLonger();//JMS message need to be delivered - adminForum - .newMessages() - .assertMessageBody("Orwell") - .clickBack() - .userFilter() - .selectFilteredUser(guestAlias) - .assertMessageBody("Orwell") - .clickBack() - .clickBack() - .assertThreadListOnNumber("Your favorite author", 3); - } /** * An author creates a course with 4 course elements. A folder @@ -2444,4 +1478,240 @@ public class CourseTest { .uploadResource(zipTitle, zipFile) .assertOnResourceType(); } + + /** + * An author create a course, enable the absence management, + * create a lecture block, add a coach and two participants.<br> + * The coach login in, see the interceptor to start the roll call. + * It starts the roll call, set an absence and close.<br> + * The participant with an absence log in, use the lectures user's + * tool to see that it has an absence. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void lecturesRollCall(@InitialPage LoginPage authorLoginPage, + @Drone @User WebDriver coachBrowser, @Drone @Participant WebDriver participantBrowser) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO coach = new UserRestClient(deploymentUrl).createRandomUser("Rei"); + UserVO participant1 = new UserRestClient(deploymentUrl).createRandomUser("Kanu"); + UserVO participant2 = new UserRestClient(deploymentUrl).createRandomUser("Rymou"); + + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //go to authoring + AuthoringEnvPage authoringEnv = navBar + .assertOnNavigationPage() + .openAuthoringEnvironment(); + + String title = "Lecture " + UUID.randomUUID(); + //create course + authoringEnv + .openCreateDropDown() + .clickCreate(ResourceType.course) + .fillCreateForm(title) + .assertOnGeneralTab() + .clickToolbarBack(); + + //set access + CoursePageFragment course = new CoursePageFragment(browser); + course + .accessConfiguration() + .setUserAccess(UserAccess.registred) + .clickToolbarBack(); + + //add a coach + course + .members() + .addMember() + .searchMember(coach, true) + .nextUsers() + .nextOverview() + .selectRepositoryEntryRole(false, true, false) + .nextPermissions() + .finish(); + //add the participants + course + .members() + .importMembers() + .setMembers(participant1, participant2) + .nextUsers() + .nextOverview() + .nextPermissions() + .finish(); + + //enable the lectures + LectureRepositoryAdminPage lecturesAdmin = course + .lecturesAdministration(); + lecturesAdmin + .settings() + .enableLectures() + .overrideDefaultSettings() + .saveSettings(); + + LectureListRepositoryPage lectureList = lecturesAdmin + .lectureList(); + + Calendar cal = Calendar.getInstance(); + int today = cal.get(Calendar.DATE); + int hour = cal.get(Calendar.HOUR_OF_DAY); + String lectureTitle = "1. Lecture"; + lectureList + .newLectureBlock() + .setTitle(lectureTitle) + .setTeacher(coach) + .setDate(today, hour, 0, hour, 59) + .save(); + + //coach at work + LoginPage coachLoginPage = LoginPage.getLoginPage(coachBrowser, deploymentUrl); + coachLoginPage + .loginAs(coach); + new RollCallInterceptorPage(coachBrowser) + .start() + .setAbsence(participant1, "1") + .closeRollCall() + .confirmCloseRollCall() + .assertOnClosedTable(); + + //participant check it roll call + LoginPage participantLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + participantLoginPage + .loginAs(participant1) + .resume(); + UserToolsPage participantUserTools = new UserToolsPage(participantBrowser); + participantUserTools + .openUserToolsMenu() + .openLectures() + .assertOnParticipantLecturesList() + .selectCourseAsParticipant(title) + .assertOnParticipantLectureBlocks() + .assertOnParticipantLectureBlockAbsent(coach, lectureTitle, title); + } + + + /** + * An author create a course, enable the absence management, + * create a lecture block, add a coach and two participants.<br> + * The coach login in, see the interceptor to start the roll call + * version mobile.<br> + * It starts the roll call, set an absence and close.<br> + * The participant with an absence log in, use the lectures user's + * tool to see that it has an absence. + * + * @param authorLoginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void lectureMobileRollCall(@InitialPage LoginPage authorLoginPage, + @Drone @User WebDriver coachBrowser, @Drone @User WebDriver participantBrowser) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO coach = new UserRestClient(deploymentUrl).createRandomUser("Rei"); + UserVO participant1 = new UserRestClient(deploymentUrl).createRandomUser("Kanu"); + UserVO participant2 = new UserRestClient(deploymentUrl).createRandomUser("Rymou"); + + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + //go to authoring + AuthoringEnvPage authoringEnv = navBar + .assertOnNavigationPage() + .openAuthoringEnvironment(); + + String title = "Lecture " + UUID.randomUUID(); + //create course + authoringEnv + .openCreateDropDown() + .clickCreate(ResourceType.course) + .fillCreateForm(title) + .assertOnGeneralTab() + .clickToolbarBack(); + + //set access + CoursePageFragment course = new CoursePageFragment(browser); + course + .accessConfiguration() + .setUserAccess(UserAccess.registred) + .clickToolbarBack(); + + //add a coach + course + .members() + .addMember() + .searchMember(coach, true) + .nextUsers() + .nextOverview() + .selectRepositoryEntryRole(false, true, false) + .nextPermissions() + .finish(); + //add the participants + course + .members() + .importMembers() + .setMembers(participant1, participant2) + .nextUsers() + .nextOverview() + .nextPermissions() + .finish(); + + //enable the lectures + LectureRepositoryAdminPage lecturesAdmin = course + .lecturesAdministration(); + lecturesAdmin + .settings() + .enableLectures() + .overrideDefaultSettings() + .saveSettings(); + + LectureListRepositoryPage lectureList = lecturesAdmin + .lectureList(); + + Calendar cal = Calendar.getInstance(); + int today = cal.get(Calendar.DATE); + int hour = cal.get(Calendar.HOUR_OF_DAY); + String lectureTitle = "2.Lecture"; + lectureList + .newLectureBlock() + .setTitle(lectureTitle) + .setTeacher(coach) + .setDate(today, hour, 0, hour, 59) + .save(); + + //coach at work + LoginPage coachLoginPage = LoginPage.getLoginPage(coachBrowser, deploymentUrl); + coachLoginPage + .loginAs(coach); + new RollCallInterceptorPage(coachBrowser) + .startMobile() + .setAbsence("1") + .saveAndNext() + .setAbsence("1") + .setAbsence("2") + .saveAndNext() + .closeRollCall(); + //check that a roll call at least is closed + new TeacherRollCallPage(coachBrowser) + .assertOnClosedTable(); + + + //participant check it roll call + LoginPage participantLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + participantLoginPage + .loginAs(participant1) + .resume(); + UserToolsPage participantUserTools = new UserToolsPage(participantBrowser); + participantUserTools + .openUserToolsMenu() + .openLectures() + .assertOnParticipantLecturesList() + .selectCourseAsParticipant(title) + .assertOnParticipantLectureBlocks() + .assertOnParticipantLectureBlockAbsent(coach, lectureTitle, title); + } } diff --git a/src/test/java/org/olat/selenium/ImsQTI21Test.java b/src/test/java/org/olat/selenium/ImsQTI21Test.java index 3737fd88e439622f4c4d74f234905880958f05e3..fb0503c341cac1b53a3cdd4aa32262bd449e73d2 100644 --- a/src/test/java/org/olat/selenium/ImsQTI21Test.java +++ b/src/test/java/org/olat/selenium/ImsQTI21Test.java @@ -1611,7 +1611,193 @@ public class ImsQTI21Test { .assertOnAssessmentTestScore(10);// 4 points from the first question, 6 from the second } - + /** + * An author make a test with 2 matches. A match with "multiple selection" + * and score "all answers", a second with "single selection" and score + * "per answers". They are distractors, the assessed user must let them blank.<br> + * A first user make the test, but doesn't answer all questions + * correctly, log out and a second user make the perfect test. + * + * @param authorLoginPage + * @param participantBrowser + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21EditorMatch_distractors(@InitialPage LoginPage authorLoginPage, + @Drone @User WebDriver participantBrowser) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO rei = new UserRestClient(deploymentUrl).createRandomUser("Rei"); + UserVO melissa = new UserRestClient(deploymentUrl).createRandomUser("Melissa"); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + String qtiTestTitle = "Match QTI 2.1 " + UUID.randomUUID(); + navBar + .openAuthoringEnvironment() + .createQTI21Test(qtiTestTitle) + .clickToolbarBack(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + QTI21EditorPage qtiEditor = qtiPage + .edit(); + //start a blank test + qtiEditor + .selectNode("Single choice") + .deleteNode(); + + //add a match, multiple selection + QTI21MatchEditorPage matchEditor = qtiEditor + .addMatch(); + matchEditor + .setSource(0, "Eclipse") + .setSource(1, "nano") + .setTarget(0, "IDE") + .setTarget(1, "WordProcessor") + .addColumn() + .setTarget(2, "CAD") + .save(); + // change max score + matchEditor + .selectScores() + .setMaxScore("4") + .save(); + // set some feedbacks + matchEditor + .selectFeedbacks() + .setHint("Hint", "This is only an hint") + .setCorrectSolution("Correct solution", "This is the correct solution") + .setCorrectFeedback("Correct feedback", "This is correct") + .setIncorrectFeedback("Incorrect", "Your answer is not correct") + .save(); + + // second match + matchEditor = qtiEditor + .addMatch() + .setSingleChoices() + .setSource(0, "Java") + .setSource(1, "C") + .addRow() + .setSource(2, "PHP") + .setTarget(0, "Lynx") + .setTarget(1, "Netscape") + .addColumn() + .setTarget(2, "Pixel") + .save(); + // select score "per answer" and set the scores + matchEditor + .selectScores() + .selectAssessmentMode(ScoreEvaluation.perAnswer) + .setMaxScore("6") + .setScore(0, 0, "0.0") + .setScore(0, 1, "0.0") + .setScore(0, 2, "1.0") + .setScore(1, 0, "0.0") + .setScore(1, 1, "1.0") + .setScore(1, 2, "0.0") + .setScore(2, 0, "2.0") + .setScore(2, 1, "0.0") + .setScore(2, 2, "-0.5") + .save(); + matchEditor + .selectFeedbacks() + .setHint("Hint", "The hint") + .setCorrectSolution("Correct solution", "This is the correct solution") + .setCorrectFeedback("Correct feedback", "This is correct") + .setIncorrectFeedback("Incorrect", "Your answer is not correct") + .save(); + + qtiPage + .clickToolbarBack(); + // access to all + qtiPage + .accessConfiguration() + .setUserAccess(UserAccess.guest) + .clickToolbarBack(); + // show results + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + + //a user search the content package + LoginPage reiLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + reiLoginPage + .loginAs(rei.getLogin(), rei.getPassword()) + .resume(); + NavigationPage reiNavBar = new NavigationPage(participantBrowser); + reiNavBar + .openMyCourses() + .openSearch() + .extendedSearch(qtiTestTitle) + .select(qtiTestTitle) + .start(); + + // make the test + QTI21Page reiQtiPage = QTI21Page + .getQTI12Page(participantBrowser); + reiQtiPage + .assertOnAssessmentItem() + .answerMatch("Eclipse", "WordProcessor", true) + .answerMatch("nano", "CAD", true) + .saveAnswer() + .assertFeedback("Incorrect") + .assertCorrectSolution("Correct solution") + .hint() + .assertFeedback("Hint") + .answerMatch("nano", "CAD", false) + .answerMatch("Eclipse", "WordProcessor", false) + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerMatch("Java", "Pixel", true) + .answerMatch("C", "Lynx", true) + .answerMatch("PHP", "Pixel", true) + .saveAnswer() + .assertCorrectSolution("Correct solution") + .assertFeedback("Incorrect") + .endTest() + .assertOnAssessmentResults() + .assertOnAssessmentTestScore("4.5");// 4 points from the first question, 0.5 from the second + + //a second user search the content package + LoginPage melLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + melLoginPage + .loginAs(melissa.getLogin(), melissa.getPassword()) + .resume(); + NavigationPage melNavBar = new NavigationPage(participantBrowser); + melNavBar + .openMyCourses() + .openSearch() + .extendedSearch(qtiTestTitle) + .select(qtiTestTitle) + .start(); + + // make the test + QTI21Page + .getQTI12Page(participantBrowser) + .assertOnAssessmentItem() + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerMatch("Java", "Pixel", true) + .answerMatch("C", "Pixel", true) + .answerMatch("PHP", "Lynx", true) + .saveAnswer() + .assertFeedback("Incorrect") + .assertCorrectSolution("Correct solution") + .answerMatch("Java", "Pixel", false) + .answerMatch("C", "Pixel", false) + .answerMatch("PHP", "Lynx", false) + .saveAnswer() + .assertFeedback("Correct feedback") + .endTest() + .assertOnAssessmentResults() + .assertOnAssessmentTestScore(10);// 4 points from the first question, 6 from the second + } + /** * An author make a test with 2 match of the drag and drop variety * with feedbacks.<br> @@ -1801,6 +1987,193 @@ public class ImsQTI21Test { .assertOnAssessmentTestScore(11);// 4 points from the first question, 7 from the second } + /** + * An author make a test with 2 match of the drag and drop variety + * with feedbacks but as distractor. The assessed user need to let them + * blank to have the max. score.<br> + * A first user make the test, check the feedbacks but make an error + * and score the maximum. A second user answers all the questions + * correctly. + * + * @param authorLoginPage + * @param participantBrowser + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void qti21EditorMatchDragAndDrop_distractors(@InitialPage LoginPage authorLoginPage, + @Drone @User WebDriver participantBrowser) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor(); + UserVO asuka = new UserRestClient(deploymentUrl).createRandomUser("Asuka"); + UserVO chara = new UserRestClient(deploymentUrl).createRandomUser("Chara"); + authorLoginPage.loginAs(author.getLogin(), author.getPassword()); + + String qtiTestTitle = "Match DnD QTI 2.1 " + UUID.randomUUID(); + navBar + .openAuthoringEnvironment() + .createQTI21Test(qtiTestTitle) + .clickToolbarBack(); + + QTI21Page qtiPage = QTI21Page + .getQTI12Page(browser); + QTI21EditorPage qtiEditor = qtiPage + .edit(); + //start a blank test + qtiEditor + .selectNode("Single choice") + .deleteNode(); + + //add a match, multiple selection + QTI21MatchEditorPage matchEditor = qtiEditor + .addMatchDragAndDrop(); + matchEditor + .setSource(0, "Einstein") + .setSource(1, "Planck") + .addRow() + .setSource(2, "Euler") + .setTarget(0, "Chemistry") + .setTarget(1, "Philosophy") + .save(); + // change max score + matchEditor + .selectScores() + .setMaxScore("4") + .save(); + // set some feedbacks + matchEditor + .selectFeedbacks() + .setHint("Hint", "Euler come from Switzerland") + .setCorrectSolution("Correct solution", "The correct solution is simple") + .setCorrectFeedback("Correct feedback", "You are right") + .setIncorrectFeedback("Incorrect", "Your answer is not exactly correct") + .save(); + + // second match + matchEditor = qtiEditor + .addMatchDragAndDrop() + .setSingleChoices() + .setSource(0, "Euler") + .setSource(1, "Broglie") + .addRow() + .setSource(2, "Konrad") + .setTarget(0, "Chemistry") + .setTarget(1, "Biology") + .addColumn() + .setTarget(2, "Astrology") + .save(); + // select score "per answer" and set the scores + matchEditor + .selectScores() + .selectAssessmentMode(ScoreEvaluation.perAnswer) + .setMaxScore("8") + .setScore(0, 0, "1.0") + .setScore(0, 1, "0.0") + .setScore(0, 2, "0.0") + .setScore(1, 0, "0.0") + .setScore(1, 1, "0.0") + .setScore(1, 2, "-0.5") + .setScore(2, 0, "0.0") + .setScore(2, 1, "2.0") + .setScore(2, 2, "0.0") + .save(); + matchEditor + .selectFeedbacks() + .setHint("Hint", "The hint") + .setCorrectSolution("Correct solution", "This is the correct solution") + .setCorrectFeedback("Correct feedback", "This is correct") + .setIncorrectFeedback("Incorrect", "Your answer is not correct") + .save(); + + //close editor + qtiPage + .clickToolbarBack(); + // access to all + qtiPage + .accessConfiguration() + .setUserAccess(UserAccess.guest) + .clickToolbarBack(); + // show results + qtiPage + .options() + .showResults(Boolean.TRUE, QTI21AssessmentResultsOptions.allOptions()) + .save(); + + //a user search the content package + LoginPage asukaLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + asukaLoginPage + .loginAs(asuka.getLogin(), asuka.getPassword()) + .resume(); + NavigationPage asukaNavBar = new NavigationPage(participantBrowser); + asukaNavBar + .openMyCourses() + .openSearch() + .extendedSearch(qtiTestTitle) + .select(qtiTestTitle) + .start(); + + // make the test + QTI21Page asukaQtiPage = QTI21Page + .getQTI12Page(participantBrowser); + asukaQtiPage + .assertOnAssessmentItem() + .answerMatchDropSourceToTarget("Einstein", "Chemistry") + .answerMatchDropSourceToTarget("Planck", "Philosophy") + .saveAnswer() + .assertFeedback("Incorrect") + .assertCorrectSolution("Correct solution") + .hint() + .assertFeedback("Hint") + .answerMatchDetarget("Planck") + .answerMatchDetarget("Einstein") + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerMatchDropSourceToTarget("Broglie", "Astrology") // -0.5 points + .answerMatchDropSourceToTarget("Euler", "Chemistry") // 1 points + .answerMatchDropSourceToTarget("Konrad", "Chemistry") // 0 points + .saveAnswer() + .assertCorrectSolution("Correct solution") + .assertFeedback("Incorrect") + .endTest() + .assertOnAssessmentResults() + .assertOnAssessmentTestScore("4.5"); + + //a second user search the content package + LoginPage charaLoginPage = LoginPage.getLoginPage(participantBrowser, deploymentUrl); + charaLoginPage + .loginAs(chara.getLogin(), chara.getPassword()) + .resume(); + NavigationPage charaNavBar = new NavigationPage(participantBrowser); + charaNavBar + .openMyCourses() + .openSearch() + .extendedSearch(qtiTestTitle) + .select(qtiTestTitle) + .start(); + + // make the test + QTI21Page + .getQTI12Page(participantBrowser) + .saveAnswer() + .assertFeedback("Correct feedback") + .nextAnswer() + .answerMatchDropSourceToTarget("Broglie", "Chemistry") // 2 points + .answerMatchDropSourceToTarget("Euler", "Astrology") // 2 points + .answerMatchDropSourceToTarget("Konrad", "Astrology") // 3 points + .saveAnswer() + .assertCorrectSolution("Correct solution") + .assertFeedback("Incorrect") + .answerMatchDetarget("Broglie") + .answerMatchDetarget("Euler") + .answerMatchDetarget("Konrad") + .saveAnswer() + .endTest() + .assertOnAssessmentResults() + .assertOnAssessmentTestScore(12);// 4 points from the first question, 8 from the second + } + /** * An author make a test with 1 upload and feedbacks.<br> * A user make the test, test hint and upload the file. diff --git a/src/test/java/org/olat/selenium/PortfolioV2Test.java b/src/test/java/org/olat/selenium/PortfolioV2Test.java index b548b0d8410174adc6ae8644e9463274f69e979d..52e1f74ecd572eee557b385f295e4cf7c8865714 100644 --- a/src/test/java/org/olat/selenium/PortfolioV2Test.java +++ b/src/test/java/org/olat/selenium/PortfolioV2Test.java @@ -683,7 +683,7 @@ public class PortfolioV2Test { AssessmentCEConfigurationPage assessmentConfig = new AssessmentCEConfigurationPage(browser); assessmentConfig .selectConfiguration() - .setScoreAuto(0.1f, 10.0f, 5.0f); + .setScoreAuto(0.0f, 10.0f, 5.0f); courseEditor .publish() .quickPublish(UserAccess.membersOnly); diff --git a/src/test/java/org/olat/selenium/page/core/FolderPage.java b/src/test/java/org/olat/selenium/page/core/FolderPage.java index 3ffdfde9b753136b82f124da4ac29c29b6b689de..783937b01eb7695c38b714ca19fec856d57dc140 100644 --- a/src/test/java/org/olat/selenium/page/core/FolderPage.java +++ b/src/test/java/org/olat/selenium/page/core/FolderPage.java @@ -19,6 +19,7 @@ */ package org.olat.selenium.page.core; +import java.io.File; import java.util.List; import org.junit.Assert; @@ -100,6 +101,28 @@ public class FolderPage { return this; } + public FolderPage uploadFile(File file) { + By newFileBy = By.className("o_bc_upload"); + browser.findElement(newFileBy).click(); + OOGraphene.waitModalDialog(browser); + + By inputBy = By.cssSelector("div.modal-dialog div.o_fileinput input[type='file']"); + OOGraphene.uploadFile(inputBy, file, browser); + OOGraphene.waitBusy(browser); + + By saveButtonBy = By.cssSelector("div.o_sel_upload_buttons button.btn-primary"); + browser.findElement(saveButtonBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + public FolderPage selectRootDirectory() { + By rootBy = By.xpath("//div[@class='o_briefcase_folder']//ol[@class='breadcrumb']/li[1]/a"); + browser.findElement(rootBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + public FolderPage assertOnFile(String filename) { By fileBy = By.xpath("//table[contains(@class,'o_bc_table')]//a[contains(text(),'" + filename + "')]"); List<WebElement> fileEls = browser.findElements(fileBy); diff --git a/src/test/java/org/olat/selenium/page/core/IMPage.java b/src/test/java/org/olat/selenium/page/core/IMPage.java index df0bd09488ce219304747837dfb955655f40eddb..645ae41495721b30428c85f8b582babb4de35f44 100644 --- a/src/test/java/org/olat/selenium/page/core/IMPage.java +++ b/src/test/java/org/olat/selenium/page/core/IMPage.java @@ -88,9 +88,9 @@ public class IMPage { Graphene.waitModel().withTimeout(10, TimeUnit.SECONDS).until(new Function<WebDriver,Boolean>(){ @Override - public Boolean apply(WebDriver browser) { + public Boolean apply(WebDriver bbrowser) { boolean found = false; - List<WebElement> history = browser.findElements(historyBy); + List<WebElement> history = bbrowser.findElements(historyBy); for(WebElement m:history) { if(m.getText().contains(message)) { found = true; diff --git a/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java b/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java index 34c8b8fccafe23d2cdaf2c1cd604a6ac89d8bde3..87c4845a8736bbaeef8a9302ecdd0c7c6eed466e 100644 --- a/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java +++ b/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java @@ -220,8 +220,13 @@ public class CourseEditorPageFragment { OOGraphene.waitModalDialog(browser); By node = By.xpath("//div[@id='o_course_editor_choose_nodetype']//a[contains(@class,'o_sel_course_editor_node-" + nodeAlias + "')]"); - browser.findElement(node).click(); - OOGraphene.waitBusy(browser); + if("lti".equals(nodeAlias)) { + OOGraphene.clickAndWait(node, browser); + + } else { + browser.findElement(node).click(); + OOGraphene.waitBusy(browser); + } return this; } @@ -255,13 +260,13 @@ public class CourseEditorPageFragment { By openerBy = By.cssSelector("a.o_opener"); browser.findElement(openerBy).click(); - By urlBy = By.cssSelector("div.o_copy_code"); + By urlBy = By.cssSelector("div.o_copy_code input"); OOGraphene.waitElement(urlBy, browser); String url = null; List<WebElement> urlEls = browser.findElements(urlBy); for(WebElement urlEl:urlEls) { - String text = urlEl.getText(); + String text = urlEl.getAttribute("value"); if(text.contains("http")) { url = text.trim(); break; diff --git a/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java b/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java index 049b43233cf18da54620d07892a3102ff775bf44..7bdf574c818efd523c13434003be3aec01a9cd0f 100644 --- a/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java +++ b/src/test/java/org/olat/selenium/page/course/CoursePageFragment.java @@ -27,6 +27,7 @@ import org.olat.restapi.support.vo.CourseVO; import org.olat.selenium.page.core.BookingPage; import org.olat.selenium.page.core.MenuTreePageFragment; import org.olat.selenium.page.graphene.OOGraphene; +import org.olat.selenium.page.lecture.LectureRepositoryAdminPage; import org.olat.selenium.page.repository.RepositoryAccessPage; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; @@ -55,6 +56,7 @@ public class CoursePageFragment { public static final By membersCourseBy = By.className("o_sel_course_members"); public static final By treeContainerBy = By.id("o_main_left_content"); public static final By efficiencyStatementsBy = By.className("o_sel_course_options_certificates"); + public static final By lecturesAdministrationBy = By.className("o_sel_course_lectures_admin"); private final WebDriver browser; @@ -271,6 +273,16 @@ public class CoursePageFragment { return new EfficiencyStatementConfigurationPage(browser); } + public LectureRepositoryAdminPage lecturesAdministration() { + if(!browser.findElement(settingsMenu).isDisplayed()) { + openSettingsMenu(); + } + browser.findElement(lecturesAdministrationBy).click(); + OOGraphene.waitBusy(browser); + return new LectureRepositoryAdminPage(browser) + .assertOnAdminPage(); + } + public BookingPage bookingTool() { if(!browser.findElement(toolsMenu).isDisplayed()) { openToolsMenu(); diff --git a/src/test/java/org/olat/selenium/page/course/DialogConfigurationPage.java b/src/test/java/org/olat/selenium/page/course/DialogConfigurationPage.java index e16a8a66eb9f7797f25b79bfa53b24bc79506922..549a6ea5c87436035edc3d98d18abc7859334b7d 100644 --- a/src/test/java/org/olat/selenium/page/course/DialogConfigurationPage.java +++ b/src/test/java/org/olat/selenium/page/course/DialogConfigurationPage.java @@ -1,3 +1,22 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ package org.olat.selenium.page.course; import java.io.File; diff --git a/src/test/java/org/olat/selenium/page/course/DialogPage.java b/src/test/java/org/olat/selenium/page/course/DialogPage.java index 3cd14fe30ba2b5cb255f6215048fcacf7eb5d8c2..9665b84710e57c1336173e3432774d1c170c9582 100644 --- a/src/test/java/org/olat/selenium/page/course/DialogPage.java +++ b/src/test/java/org/olat/selenium/page/course/DialogPage.java @@ -1,3 +1,22 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ package org.olat.selenium.page.course; import java.io.File; diff --git a/src/test/java/org/olat/selenium/page/course/GroupTaskToCoachPage.java b/src/test/java/org/olat/selenium/page/course/GroupTaskToCoachPage.java index b084083bbbb6364ece82040d52e9bcce11a7089b..deb15a7fbd32118ffef2c7213e1dc76f623960e1 100644 --- a/src/test/java/org/olat/selenium/page/course/GroupTaskToCoachPage.java +++ b/src/test/java/org/olat/selenium/page/course/GroupTaskToCoachPage.java @@ -95,7 +95,12 @@ public class GroupTaskToCoachPage { public GroupTaskToCoachPage needRevision() { By reviewBy = By.cssSelector("#o_step_review_content .o_sel_course_gta_need_revision"); OOGraphene.clickAndWait(reviewBy, browser); - return confirm(); + + OOGraphene.waitModalDialog(browser); + By okBy = By.xpath("//div[contains(@class,'modal-dialog')]//button"); + browser.findElement(okBy).click(); + OOGraphene.waitBusy(browser); + return this; } public GroupTaskToCoachPage closeRevisions() { diff --git a/src/test/java/org/olat/selenium/page/course/LTIConfigurationPage.java b/src/test/java/org/olat/selenium/page/course/LTIConfigurationPage.java new file mode 100644 index 0000000000000000000000000000000000000000..b7fbf5dd1c130cfc627664a724d5b3339fd750a6 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/course/LTIConfigurationPage.java @@ -0,0 +1,85 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.course; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 21 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LTIConfigurationPage { + + private final WebDriver browser; + + public LTIConfigurationPage(WebDriver browser) { + this.browser = browser; + } + + public LTIConfigurationPage selectConfiguration() { + By configBy = By.cssSelector("fieldset.o_sel_lti_config_form"); + OOGraphene.selectTab(CourseEditorPageFragment.navBarNodeConfiguration, configBy, browser); + return this; + } + + public LTIConfigurationPage setLtiPage(String url, String key, String password) { + By urlBy = By.cssSelector("div.o_sel_lti_config_title input[type=text]"); + browser.findElement(urlBy).sendKeys(url); + + By keyBy = By.cssSelector("div.o_sel_lti_config_key input[type=text]"); + browser.findElement(keyBy).sendKeys(key); + + By passwordBy = By.cssSelector("div.o_sel_lti_config_pass input[type=text]"); + browser.findElement(passwordBy).sendKeys(password); + + return this; + } + + public LTIConfigurationPage enableScore(double scale, double cutValue) { + By assessableBy = By.xpath("//div[contains(@class,'o_sel_lti_config_assessable')]//input[@type='checkbox']"); + By assessableLabelBy = By.xpath("//div[contains(@class,'o_sel_lti_config_assessable')]//label[input[@type='checkbox']]"); + WebElement assessableEl = browser.findElement(assessableBy); + WebElement assessableLabelEl = browser.findElement(assessableLabelBy); + OOGraphene.check(assessableLabelEl, assessableEl, Boolean.TRUE); + + By scaleBy = By.cssSelector("div.o_sel_lti_config_scale input[type=text]"); + OOGraphene.waitElement(scaleBy, browser); + WebElement scaleEl = browser.findElement(scaleBy); + scaleEl.clear(); + scaleEl.sendKeys(Double.toString(scale)); + + By cutValueBy = By.cssSelector("div.o_sel_lti_config_cutval input[type=text]"); + browser.findElement(cutValueBy).sendKeys(Double.toString(cutValue)); + return this; + } + + public LTIConfigurationPage save() { + By saveBy = By.cssSelector("fieldset.o_sel_lti_config_form button.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/course/LTIPage.java b/src/test/java/org/olat/selenium/page/course/LTIPage.java new file mode 100644 index 0000000000000000000000000000000000000000..09e34b2f86a41410146b27e6342607338b247611 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/course/LTIPage.java @@ -0,0 +1,93 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.course; + +import java.util.List; + +import org.junit.Assert; +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * Attention! The browser instance is dependent of the location. Jump + * to the iframe need a jump back to OpenOLAT. + * + * + * Initial date: 21 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LTIPage { + + private WebDriver browser; + + public LTIPage(WebDriver browser) { + this.browser = browser; + } + + public LTIPage start() { + By startBy = By.xpath("//div[contains(@class,'o_button_group')]/a[contains(@onclick,'start')]"); + OOGraphene.waitElement(startBy, browser); + browser.findElement(startBy).click(); + + By iframeBy = By.cssSelector(".o_iframedisplay iframe"); + OOGraphene.waitElement(iframeBy, browser); + + List<WebElement> iframes = browser.findElements(iframeBy); + browser = browser.switchTo().frame(iframes.get(0)); + + By launchedBy = By.xpath("//p[contains(text(),'Launch Validated.')]"); + OOGraphene.waitElement(launchedBy, browser); + + return this; + } + + public LTIPage outcomeToolProvider() { + By outcomeToolLinkBy = By.xpath("//a[contains(@href,'tool_provider_outcome.php')]"); + OOGraphene.waitElement(outcomeToolLinkBy, browser); + browser.findElement(outcomeToolLinkBy).click(); + return this; + } + + public LTIPage sendGrade(double grade) { + By gradeBy = By.cssSelector("input[type=text][name=grade]"); + OOGraphene.waitElement(gradeBy, browser); + browser.findElement(gradeBy).sendKeys(Double.toString(grade)); + + By sendGradeBy = By.cssSelector("input[type=submit][value='Send Grade']"); + browser.findElement(sendGradeBy).click(); + + By preBy = By.tagName("pre"); + OOGraphene.waitElement(preBy, browser); + List<WebElement> preEls = browser.findElements(preBy); + boolean success = true; + for(WebElement preEl:preEls) { + String text = preEl.getText(); + if(text.contains("<imsx_codeMajor>success</imsx_codeMajor>")) { + success |= true; + } + } + Assert.assertTrue(success); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/course/MemberListConfigurationPage.java b/src/test/java/org/olat/selenium/page/course/MemberListConfigurationPage.java new file mode 100644 index 0000000000000000000000000000000000000000..8ba503f455816dd6b66a898dea331cadba8e3137 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/course/MemberListConfigurationPage.java @@ -0,0 +1,82 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.course; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 7 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class MemberListConfigurationPage { + + private final WebDriver browser; + + public MemberListConfigurationPage(WebDriver browser) { + this.browser = browser; + } + + public MemberListConfigurationPage selectSettings() { + By configBy = By.cssSelector("fieldset.o_sel_cmembers_settings"); + OOGraphene.selectTab(CourseEditorPageFragment.navBarNodeConfiguration, configBy, browser); + return this; + } + + public MemberListConfigurationPage setOwners(Boolean visible) { + return setMembers(visible, "members.owners"); + } + + public MemberListConfigurationPage setCoaches(Boolean visible) { + return setMembers(visible, "coaches"); + } + + public MemberListConfigurationPage setParticipants(Boolean visible) { + return setMembers(visible, "participants"); + } + + private MemberListConfigurationPage setMembers(Boolean visible, String type) { + By checkboxBy = By.xpath("//fieldset[contains(@class,'o_sel_cmembers_settings')]//input[@type='checkbox'][@name='" + type + "']"); + By labelBy = By.xpath("//fieldset[contains(@class,'o_sel_cmembers_settings')]//label[input[@type='checkbox'][@name='" + type + "']]"); + WebElement checkboxEl = browser.findElement(checkboxBy); + WebElement labelEl = browser.findElement(labelBy); + OOGraphene.check(labelEl, checkboxEl, visible); + return this; + } + + public MemberListConfigurationPage setCourseCoachesOnly() { + By courseCoachBy = By.xpath("//fieldset[contains(@class,'o_sel_cmembers_settings')]//input[@type='radio'][@name='coachesChoice'][@value='course']"); + OOGraphene.waitElement(courseCoachBy, browser); + browser.findElement(courseCoachBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + public MemberListConfigurationPage save() { + By configBy = By.cssSelector("fieldset.o_sel_cmembers_settings button.btn-primary"); + OOGraphene.click(configBy, browser); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/course/MemberListPage.java b/src/test/java/org/olat/selenium/page/course/MemberListPage.java new file mode 100644 index 0000000000000000000000000000000000000000..250d2f6322f1ac6fd07b9321303b660f62d447dc --- /dev/null +++ b/src/test/java/org/olat/selenium/page/course/MemberListPage.java @@ -0,0 +1,89 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.course; + +import java.util.List; + +import org.junit.Assert; +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + + +/** + * + * Initial date: 7 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class MemberListPage { + + private final WebDriver browser; + + public MemberListPage(WebDriver browser) { + this.browser = browser; + } + + public MemberListPage assertOnMembers() { + By membersBy = By.cssSelector("div.o_cmembers"); + OOGraphene.waitElement(membersBy, browser); + return this; + } + + public MemberListPage assertOnOwner(String name) { + By ownerBy = By.xpath("//div[contains(@class,'o_sel_owners')]//div[@class='o_cmember_info_wrapper']/a/span[contains(text(),'" + name + "')]"); + OOGraphene.waitElement(ownerBy, browser); + return this; + } + + public MemberListPage assertOnNotOwner(String name) { + By ownerBy = By.xpath("//div[contains(@class,'o_sel_owners')]//div[@class='o_cmember_info_wrapper']/a/span[contains(text(),'" + name + "')]"); + List<WebElement> ownersEl = browser.findElements(ownerBy); + Assert.assertEquals(0, ownersEl.size()); + return this; + } + + public MemberListPage assertOnCoach(String name) { + By coachBy = By.xpath("//div[contains(@class,'o_sel_coaches')]//div[@class='o_cmember_info_wrapper']/a/span[contains(text(),'" + name + "')]"); + OOGraphene.waitElement(coachBy, browser); + return this; + } + + public MemberListPage assertOnNotCoach(String name) { + By coachBy = By.xpath("//div[contains(@class,'o_sel_coaches')]//div[@class='o_cmember_info_wrapper']/a/span[contains(text(),'" + name + "')]"); + List<WebElement> coachEls = browser.findElements(coachBy); + Assert.assertEquals(0, coachEls.size()); + return this; + } + + public MemberListPage assertOnParticipant(String name) { + By participantBy = By.xpath("//div[contains(@class,'o_sel_participants')]//div[@class='o_cmember_info_wrapper']/a/span[contains(text(),'" + name + "')]"); + OOGraphene.waitElement(participantBy, browser); + return this; + } + + public MemberListPage assertOnNotParticipant(String name) { + By participantBy = By.xpath("//div[contains(@class,'o_sel_participants')]//div[@class='o_cmember_info_wrapper']/a/span[contains(text(),'" + name + "')]"); + List<WebElement> participantEls = browser.findElements(participantBy); + Assert.assertEquals(0, participantEls.size()); + return this; + } +} diff --git a/src/test/java/org/olat/selenium/page/course/ParticipantFolderPage.java b/src/test/java/org/olat/selenium/page/course/ParticipantFolderPage.java new file mode 100644 index 0000000000000000000000000000000000000000..0675681e280c0ded99caa489067601b1d3b01c0e --- /dev/null +++ b/src/test/java/org/olat/selenium/page/course/ParticipantFolderPage.java @@ -0,0 +1,78 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.course; + +import org.olat.selenium.page.core.FolderPage; +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +/** + * + * Initial date: 5 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ParticipantFolderPage { + + private final WebDriver browser; + + public ParticipantFolderPage(WebDriver browser) { + this.browser = browser; + } + + public ParticipantFolderPage assertOnParticipantsList() { + By listBy = By.cssSelector("div.o_sel_pf_participants_list table"); + OOGraphene.waitElement(listBy, browser); + return this; + } + + public ParticipantFolderPage assertOnParticipant(String firstName) { + By inListBy = By.xpath("//div[contains(@class,'o_sel_pf_participants_list')]//table//td/a[contains(text(),'" + firstName + "')]"); + OOGraphene.waitElement(inListBy, browser); + return this; + } + + public ParticipantFolderPage openParticipantFolder(String firstName) { + By inListBy = By.xpath("//div[contains(@class,'o_sel_pf_participants_list')]//table//tr[td/a[contains(text(),'" + firstName + "')]]/td/a[contains(@href,'open.box')][i]"); + OOGraphene.waitElement(inListBy, browser); + browser.findElement(inListBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + public FolderPage openReturnBox() { + By returnBoxBy = By.xpath("//div[@class='o_briefcase_folder']//table/tbody/tr[1]/td/a[i[contains(@class,'o_filetype_folder')]]"); + OOGraphene.waitElement(returnBoxBy, browser); + browser.findElement(returnBoxBy).click(); + OOGraphene.waitBusy(browser); + return new FolderPage(browser); + } + + public FolderPage openDropBox() { + By returnBoxBy = By.xpath("//div[@class='o_briefcase_folder']//table/tbody/tr[2]/td/a[i[contains(@class,'o_filetype_folder')]]"); + OOGraphene.waitElement(returnBoxBy, browser); + browser.findElement(returnBoxBy).click(); + OOGraphene.waitBusy(browser); + return new FolderPage(browser); + } + + +} diff --git a/src/test/java/org/olat/selenium/page/course/RemindersPage.java b/src/test/java/org/olat/selenium/page/course/RemindersPage.java index 7d643ff547c75d307afe9f459cc345eb35642974..1bcdd1edb2733aacf82b890f62590dc560c3cf39 100644 --- a/src/test/java/org/olat/selenium/page/course/RemindersPage.java +++ b/src/test/java/org/olat/selenium/page/course/RemindersPage.java @@ -163,6 +163,12 @@ public class RemindersPage { browser.findElement(descBy).sendKeys(text); return this; } + + public RemindersPage setSubject(String text) { + By subjectBy = By.cssSelector(".o_sel_course_reminder_subject input[type='text']"); + browser.findElement(subjectBy).sendKeys(text); + return this; + } public RemindersPage setTimeBasedRule(int pos, String type, int time, String unit) { //select type diff --git a/src/test/java/org/olat/selenium/page/graphene/OOGraphene.java b/src/test/java/org/olat/selenium/page/graphene/OOGraphene.java index 44f0290a64f50f3765d5844fe383688949f35252..ec91e6a35122e32069685449889b7f6fe2961fa0 100644 --- a/src/test/java/org/olat/selenium/page/graphene/OOGraphene.java +++ b/src/test/java/org/olat/selenium/page/graphene/OOGraphene.java @@ -49,7 +49,6 @@ public class OOGraphene { private static final long defaultTimeout = 5;//seconds private static final By closeBlueBoxButtonBy = By.cssSelector("div.o_alert_info div.o_sel_info_message a.o_alert_close.o_sel_info_close"); - private static final By closeModalDialogButtonBy = By.cssSelector("div.modal-dialog div.modal-header button.close"); public static final By wizardNextBy = By.xpath("//div[contains(@class,'modal-footer')]//a[contains(@class,'o_wizard_button_next')]"); public static final By wizardFinishBy = By.xpath("//div[contains(@class,'modal-footer')]//a[contains(@class,'o_wizard_button_finish') and not(contains(@class,'o_disabled'))]"); @@ -80,6 +79,12 @@ public class OOGraphene { .pollingEvery(200, TimeUnit.MILLISECONDS).until().element(modalBy).is().visible(); } + public static void waitModalDialogDisappears(WebDriver browser) { + By modalBy = By.xpath("//div[not(@id='o_form_dirty_message')]/div[contains(@class,'modal-dialog')]/div[contains(@class,'modal-content')]"); + Graphene.waitModel(browser).withTimeout(5, TimeUnit.SECONDS) + .pollingEvery(200, TimeUnit.MILLISECONDS).until().element(modalBy).is().not().present(); + } + public static void waitCallout(WebDriver browser) { By calloutBy = By.cssSelector("div.popover-content div.o_callout_content"); waitElement(calloutBy, 5, browser); @@ -405,11 +410,10 @@ public class OOGraphene { public static final void closeErrorBox(WebDriver browser) { By errorBoxBy = By.cssSelector(".modal-body.alert.alert-danger"); waitElement(errorBoxBy, 5, browser); - By closeButtonBy = By.cssSelector("div.modal-dialog button.close"); + By closeButtonBy = By.xpath("//div[not(@id='o_form_dirty_message')]/div[contains(@class,'modal-dialog')]//button[@class='close']"); waitElement(closeButtonBy, 5, browser); browser.findElement(closeButtonBy).click(); - By dialogBy = By.cssSelector("div.modal-dialog"); - OOGraphene.waitElementDisappears(dialogBy, 2, browser); + waitModalDialogDisappears(browser); } public static final void waitAndCloseBlueMessageWindow(WebDriver browser) { @@ -455,6 +459,7 @@ public class OOGraphene { } public static final void closeModalDialogWindow(WebDriver browser) { + By closeModalDialogButtonBy = By.xpath("//div[not(@id='o_form_dirty_message')]/div[contains(@class,'modal-dialog')]//div[contains(@class,'modal-header')]/button[@class='close']"); List<WebElement> closeButtons = browser.findElements(closeModalDialogButtonBy); for(WebElement closeButton:closeButtons) { if(closeButton.isDisplayed()) { @@ -474,8 +479,7 @@ public class OOGraphene { private static final void clickModalDialogCloseButton(WebDriver browser, WebElement closeButton) { try { closeButton.click(); - By dialogBy = By.cssSelector("div.modal-dialog"); - OOGraphene.waitElementDisappears(dialogBy, 2, browser); + waitModalDialogDisappears(browser); } catch (ElementNotVisibleException e) { //e.printStackTrace(); } diff --git a/src/test/java/org/olat/selenium/page/group/GroupPage.java b/src/test/java/org/olat/selenium/page/group/GroupPage.java index a8fd278704a6a0f21c50fcf785320de939d8d0be..2d2c236b09d6b53f1d3e72d9e045b1d9848ebdce 100644 --- a/src/test/java/org/olat/selenium/page/group/GroupPage.java +++ b/src/test/java/org/olat/selenium/page/group/GroupPage.java @@ -187,9 +187,9 @@ public class GroupPage { * @return */ public String getGroupURL() { - By urlBy = By.cssSelector("p.o_sel_group_url"); + By urlBy = By.cssSelector("p.o_sel_group_url input"); WebElement urlEl = browser.findElement(urlBy); - String url = urlEl.getText(); + String url = urlEl.getAttribute("value"); return url; } diff --git a/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java b/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java index 2e0a7609c220bc93f4bab505a1ac4259cd221726..d6472287646de1125522cc37c155e104b749887b 100644 --- a/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java +++ b/src/test/java/org/olat/selenium/page/group/MembersWizardPage.java @@ -127,12 +127,10 @@ public class MembersWizardPage { OOGraphene.waitBusyAndScrollTop(browser); } - if(participant) { - By participantBy = By.cssSelector("label input[name='repoRights'][type='checkbox'][value='participant']"); - WebElement participantEl = browser.findElement(participantBy); - OOGraphene.check(participantEl, new Boolean(participant)); - OOGraphene.waitBusyAndScrollTop(browser); - } + By participantBy = By.cssSelector("label input[name='repoRights'][type='checkbox'][value='participant']"); + WebElement participantEl = browser.findElement(participantBy); + OOGraphene.check(participantEl, new Boolean(participant)); + OOGraphene.waitBusyAndScrollTop(browser); return this; } diff --git a/src/test/java/org/olat/selenium/page/lecture/EditLectureBlockPage.java b/src/test/java/org/olat/selenium/page/lecture/EditLectureBlockPage.java new file mode 100644 index 0000000000000000000000000000000000000000..72bb6b29589e0913edaf9c444950e9b32af473cc --- /dev/null +++ b/src/test/java/org/olat/selenium/page/lecture/EditLectureBlockPage.java @@ -0,0 +1,95 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.lecture; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.olat.user.restapi.UserVO; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 17 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class EditLectureBlockPage { + + private WebDriver browser; + + public EditLectureBlockPage(WebDriver browser) { + this.browser = browser; + } + + public EditLectureBlockPage setTitle(String title) { + By titleBy = By.cssSelector("fieldset.o_sel_repo_edit_lecture_form div.o_sel_repo_lecture_title input[type=text]"); + browser.findElement(titleBy).sendKeys(title); + return this; + } + + public EditLectureBlockPage setTeacher(UserVO user) { + By checkboxBy = By.xpath("//div[contains(@class,'o_sel_repo_lecture_teachers')]//input[@type='checkbox'][@value='" + user.getKey() + "']"); + WebElement checkboxEl = browser.findElement(checkboxBy); + By labelBy = By.xpath("//div[contains(@class,'o_sel_repo_lecture_teachers')]//label[input[@type='checkbox'][@value='" + user.getKey() + "']]"); + WebElement labelEl = browser.findElement(labelBy); + OOGraphene.check(labelEl, checkboxEl, Boolean.TRUE); + return this; + } + + public EditLectureBlockPage setDate(int day, int startHour, int startMinute, int endHour, int endMinute) { + String dateMsXpath = "//fieldset[contains(@class,'o_sel_repo_edit_lecture_form')]//div[contains(@class,'o_date_ms')]/input[@type='text']"; + By startHourBy = By.xpath(dateMsXpath + "[1]"); + browser.findElement(startHourBy).sendKeys(Integer.toString(startHour)); + By startMinuteBy = By.xpath(dateMsXpath + "[2]"); + browser.findElement(startMinuteBy).sendKeys(Integer.toString(startMinute)); + By endHourBy = By.xpath(dateMsXpath + "[3]"); + browser.findElement(endHourBy).sendKeys(Integer.toString(endHour)); + By endMinuteBy = By.xpath(dateMsXpath + "[4]"); + browser.findElement(endMinuteBy).sendKeys(Integer.toString(endMinute)); + + By untilAltBy = By.cssSelector("fieldset.o_sel_repo_edit_lecture_form div.o_sel_repo_lecture_date span.input-group-addon i"); + browser.findElement(untilAltBy).click(); + OOGraphene.waitGui(browser); + selectDayInDatePicker(day); + return this; + } + + private EditLectureBlockPage selectDayInDatePicker(int day) { + By datePickerBy = By.id("ui-datepicker-div"); + OOGraphene.waitElement(datePickerBy, 5, browser); + + By dayBy = By.xpath("//div[@id='ui-datepicker-div']//td//a[normalize-space(text())='" + day + "']"); + OOGraphene.waitElement(dayBy, 5, browser); + browser.findElement(dayBy).click(); + + OOGraphene.waitElementUntilNotVisible(datePickerBy, 5, browser); + //OOGraphene.waitingALittleBit(); + return this; + } + + public EditLectureBlockPage save() { + By saveBy = By.cssSelector("fieldset.o_sel_repo_edit_lecture_form button.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/lecture/LectureListRepositoryPage.java b/src/test/java/org/olat/selenium/page/lecture/LectureListRepositoryPage.java new file mode 100644 index 0000000000000000000000000000000000000000..8088354b914745ab6fa4cd0a338f2ec5096b0c52 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/lecture/LectureListRepositoryPage.java @@ -0,0 +1,55 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.lecture; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +/** + * + * Initial date: 15 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LectureListRepositoryPage { + + private WebDriver browser; + + public LectureListRepositoryPage(WebDriver browser) { + this.browser = browser; + } + + public LectureListRepositoryPage asssertOnLectureList() { + By lecturesBy = By.cssSelector("div.o_sel_repo_lectures_list"); + OOGraphene.waitElement(lecturesBy, browser); + return this; + } + + public EditLectureBlockPage newLectureBlock() { + By addLectureBy = By.cssSelector("div.o_sel_repo_lectures_list a.o_sel_repo_add_lecture"); + browser.findElement(addLectureBy).click(); + OOGraphene.waitModalDialog(browser); + return new EditLectureBlockPage(browser); + } + + + +} diff --git a/src/test/java/org/olat/selenium/page/lecture/LectureRepositoryAdminPage.java b/src/test/java/org/olat/selenium/page/lecture/LectureRepositoryAdminPage.java new file mode 100644 index 0000000000000000000000000000000000000000..5663601c75308efc49b8d23e5e45b30e8bf1bfdf --- /dev/null +++ b/src/test/java/org/olat/selenium/page/lecture/LectureRepositoryAdminPage.java @@ -0,0 +1,70 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.lecture; + +import java.util.List; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 15 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LectureRepositoryAdminPage { + + private WebDriver browser; + + public LectureRepositoryAdminPage(WebDriver browser) { + this.browser = browser; + } + + public LectureRepositoryAdminPage assertOnAdminPage() { + By adminBy = By.cssSelector("div.o_sel_repo_lectures_admin"); + OOGraphene.waitElement(adminBy, browser); + return this; + } + + public LectureRepositorySettingsPage settings() { + By enableBy = By.xpath("//label/input[@name='lecture.admin.enabled' and @value='on']"); + List<WebElement> enableEls = browser.findElements(enableBy); + if(enableEls.isEmpty()) { + By settingBy = By.xpath("//div[contains(@class,'o_sel_repo_lectures_admin')]//a[contains(@onclick,'repo.settings')]"); + browser.findElement(settingBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitElement(enableBy, browser); + } + return new LectureRepositorySettingsPage(browser); + } + + public LectureListRepositoryPage lectureList() { + By lecturesBy = By.xpath("//div[contains(@class,'o_sel_repo_lectures_admin')]//a[contains(@onclick,'repo.lectures.block')]"); + browser.findElement(lecturesBy).click(); + OOGraphene.waitBusy(browser); + return new LectureListRepositoryPage(browser) + .asssertOnLectureList(); + } + + +} diff --git a/src/test/java/org/olat/selenium/page/lecture/LectureRepositorySettingsPage.java b/src/test/java/org/olat/selenium/page/lecture/LectureRepositorySettingsPage.java new file mode 100644 index 0000000000000000000000000000000000000000..d4b1117ad200a9df6b08828269fb11b3e85c6dc9 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/lecture/LectureRepositorySettingsPage.java @@ -0,0 +1,71 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.lecture; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 15 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LectureRepositorySettingsPage { + + private WebDriver browser; + + public LectureRepositorySettingsPage(WebDriver browser) { + this.browser = browser; + } + + public LectureRepositorySettingsPage enableLectures() { + By enableBy = By.xpath("//label/input[@name='lecture.admin.enabled' and @value='on']"); + By enableLabelBy = By.xpath("//label[input[@name='lecture.admin.enabled' and @value='on']]"); + OOGraphene.waitElement(enableBy, browser); + + WebElement checkboxEl = browser.findElement(enableBy); + WebElement labelEl = browser.findElement(enableLabelBy); + OOGraphene.check(labelEl, checkboxEl, Boolean.TRUE); + OOGraphene.waitBusy(browser); + + By overrideBy = By.cssSelector("div.o_sel_repo_lecture_override input[type=radio]"); + OOGraphene.waitElement(overrideBy, browser); + return this; + } + + public LectureRepositorySettingsPage overrideDefaultSettings() { + By overrideBy = By.xpath("//label[input[@name='config.override' and @value='yes']]"); + OOGraphene.waitElement(overrideBy, browser); + browser.findElement(overrideBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + public LectureRepositorySettingsPage saveSettings() { + By saveBy = By.cssSelector("fieldset.o_sel_repo_lecture_settings_form button.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/lecture/LecturesToolPage.java b/src/test/java/org/olat/selenium/page/lecture/LecturesToolPage.java new file mode 100644 index 0000000000000000000000000000000000000000..49e231c212231ae011f3b382df2db111375ec112 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/lecture/LecturesToolPage.java @@ -0,0 +1,67 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.lecture; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.olat.user.restapi.UserVO; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +/** + * + * Initial date: 26 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LecturesToolPage { + + private final WebDriver browser; + + public LecturesToolPage(WebDriver browser) { + this.browser = browser; + } + + public LecturesToolPage assertOnParticipantLecturesList() { + By overviewBy = By.cssSelector("fieldset.o_sel_lecture_participant_overview"); + OOGraphene.waitElement(overviewBy, browser); + return this; + } + + public LecturesToolPage selectCourseAsParticipant(String course) { + By selectBy = By.xpath("//table//tr/td/a[contains(@href,'details')][contains(text(),'" + course + "')]"); + OOGraphene.waitElement(selectBy, browser); + browser.findElement(selectBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + public LecturesToolPage assertOnParticipantLectureBlocks() { + By blocks = By.cssSelector("div.o_sel_lecture_participant_blocks table"); + OOGraphene.waitElement(blocks, browser); + return this; + } + + public LecturesToolPage assertOnParticipantLectureBlockAbsent(UserVO teacher, String block, String course) { + By blocks = By.xpath("//div[contains(@class,'o_sel_lecture_participant_blocks')]//table//tr[td[contains(text(),'" + course + "')]][td[contains(text(),'" + block + "')]][td[contains(text(),'" + teacher.getLastName() + "')]]/td/span/i[contains(@class,'o_lectures_rollcall_danger')]"); + OOGraphene.waitElement(blocks, browser); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/lecture/RollCallInterceptorPage.java b/src/test/java/org/olat/selenium/page/lecture/RollCallInterceptorPage.java new file mode 100644 index 0000000000000000000000000000000000000000..00c4bc7ba6c7fa36ffe1ab549a0db1ba700e48ca --- /dev/null +++ b/src/test/java/org/olat/selenium/page/lecture/RollCallInterceptorPage.java @@ -0,0 +1,59 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.lecture; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +/** + * + * Initial date: 26 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class RollCallInterceptorPage { + + private final WebDriver browser; + + public RollCallInterceptorPage(WebDriver browser) { + this.browser = browser; + } + + public TeacherRollCallPage start() { + By formBy = By.cssSelector("div.o_sel_lecture_start_wizard"); + OOGraphene.waitElement(formBy, browser); + By startBy = By.cssSelector("div.o_sel_lecture_start_wizard button.btn-primary"); + browser.findElement(startBy).click(); + OOGraphene.waitBusy(browser); + return new TeacherRollCallPage(browser) + .assertOnRollCall(); + } + + public TeacherRollCallWizardPage startMobile() { + By formBy = By.cssSelector("div.o_sel_lecture_start_wizard"); + OOGraphene.waitElement(formBy, browser); + By startWizardBy = By.cssSelector("div.o_sel_lecture_start_wizard a.o_sel_lecture_start_wizard"); + browser.findElement(startWizardBy).click(); + OOGraphene.waitBusy(browser); + return new TeacherRollCallWizardPage(browser); + } + +} diff --git a/src/test/java/org/olat/selenium/page/lecture/TeacherRollCallPage.java b/src/test/java/org/olat/selenium/page/lecture/TeacherRollCallPage.java new file mode 100644 index 0000000000000000000000000000000000000000..986215d55a4bb49074638d6dc4d2e4fe631a7763 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/lecture/TeacherRollCallPage.java @@ -0,0 +1,91 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.lecture; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.olat.user.restapi.UserVO; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 26 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class TeacherRollCallPage { + + private final WebDriver browser; + + public TeacherRollCallPage(WebDriver browser) { + this.browser = browser; + } + + public TeacherRollCallPage assertOnRollCall() { + By rollCallBy = By.cssSelector("div.o_lectures_rollcall>fieldset"); + OOGraphene.waitElement(rollCallBy, browser); + return this; + } + + public TeacherRollCallPage assertOnClosedTable() { + By tableBy = By.cssSelector("fieldset.o_sel_lecture_table_closed table.table"); + OOGraphene.waitElement(tableBy, browser); + return this; + } + + /** + * Set an absence per user and lecture + * @param user The user to set an absence + * @param col The lecture number + * @return Itself + */ + public TeacherRollCallPage setAbsence(UserVO user, String col) { + String name = user.getFirstName(); + //div[contains(@class,'o_rollcall_table')]//table//tr[td[contains(text(),'Kanu-Rnd-34a2154f8-7d48-4a97-8aad-740bff74bd2a')]]/td[count(//div[contains(@class,'o_rollcall_table')]//table//tr/th[a[text()='1']]/preceding-sibling::th)+1]/div/label/input + By checkBy = By.xpath("//div[contains(@class,'o_rollcall_table')]//table//tr[td[contains(text(),'" + name + "')]]/td[count(//div[contains(@class,'o_rollcall_table')]//table//tr/th[a[text()='" + col + "']]/preceding-sibling::th)+1]/div/label/input"); + WebElement checkEl = browser.findElement(checkBy); + OOGraphene.check(checkEl, Boolean.TRUE); + OOGraphene.waitBusy(browser); + return this; + } + + /** + * The close button in the roll call list. + * @return Itself + */ + public TeacherRollCallPage closeRollCall() { + By closeBy = By.cssSelector("div.o_lectures_rollcall a.o_sel_lecture_close"); + browser.findElement(closeBy).click(); + OOGraphene.waitModalDialog(browser); + return this; + } + + /** + * Simply confirm the clsoing of the roll call. + * @return Itself + */ + public TeacherRollCallPage confirmCloseRollCall() { + By confirmCloseBy = By.cssSelector("fieldset.o_sel_lecture_confirm_close_form button.btn-primary"); + browser.findElement(confirmCloseBy).click(); + OOGraphene.waitBusy(browser); + return this; + } +} diff --git a/src/test/java/org/olat/selenium/page/lecture/TeacherRollCallWizardPage.java b/src/test/java/org/olat/selenium/page/lecture/TeacherRollCallWizardPage.java new file mode 100644 index 0000000000000000000000000000000000000000..7d383a3f6a9a422c862aff0d7858ee837ef067e3 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/lecture/TeacherRollCallWizardPage.java @@ -0,0 +1,76 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.lecture; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 26 août 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class TeacherRollCallWizardPage { + + private final WebDriver browser; + + public TeacherRollCallWizardPage(WebDriver browser) { + this.browser = browser; + } + + public TeacherRollCallWizardPage assertOnRollCallWizard() { + By portraitBy = By.cssSelector("div.o_rollcall_wizard"); + OOGraphene.waitElement(portraitBy, browser); + return this; + } + + public TeacherRollCallWizardPage setAbsence(String lecture) { + By checkBy = By.xpath("//div[contains(@class,'o_rollcall_wizard')]//table//tr[1]/td[count(//div[contains(@class,'o_rollcall_wizard')]//table//tr/th[a[text()='" + lecture + "']]/preceding-sibling::th)+1]/div/label/input"); + WebElement checkEl = browser.findElement(checkBy); + OOGraphene.check(checkEl, Boolean.TRUE); + OOGraphene.waitBusy(browser); + return this; + } + + public TeacherRollCallWizardPage next() { + By nextBy = By.cssSelector("a.o_sel_next"); + browser.findElement(nextBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + public TeacherRollCallWizardPage saveAndNext() { + By saveBy = By.cssSelector("div.o_rollcall_wizard button.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + public TeacherRollCallWizardPage closeRollCall() { + By closeBy = By.cssSelector("fieldset.o_sel_lecture_confirm_close_form button.btn-primary"); + browser.findElement(closeBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/portfolio/BinderPublicationPage.java b/src/test/java/org/olat/selenium/page/portfolio/BinderPublicationPage.java index ad27c7922ed47301da03b049aafb52ac715537c8..7bcc7f97d5363fcf685a02dcaaa95e5ae05ee8e7 100644 --- a/src/test/java/org/olat/selenium/page/portfolio/BinderPublicationPage.java +++ b/src/test/java/org/olat/selenium/page/portfolio/BinderPublicationPage.java @@ -101,11 +101,8 @@ public class BinderPublicationPage { browser.findElement(submitBy).click(); OOGraphene.waitBusy(browser); - By closeMailErrorBy = By.cssSelector("div.modal-dialog div.modal-header button"); - OOGraphene.waitElement(closeMailErrorBy, 5, browser); - browser.findElement(closeMailErrorBy).click(); - OOGraphene.waitBusy(browser); - + //close error smtp + OOGraphene.closeErrorBox(browser); return this; } } diff --git a/src/test/java/org/olat/selenium/page/portfolio/EntryPage.java b/src/test/java/org/olat/selenium/page/portfolio/EntryPage.java index 171fdbda04ff2c224027d3e6908f5ab842601e34..ef85ea2342eb535f02170654b5880d1ea0927873 100644 --- a/src/test/java/org/olat/selenium/page/portfolio/EntryPage.java +++ b/src/test/java/org/olat/selenium/page/portfolio/EntryPage.java @@ -103,7 +103,7 @@ public class EntryPage { public EntryPage assertOnImage(File image) { String filename = image.getName(); - By titleBy = By.xpath("//div[contains(@class,'o_image')]//img[contains(@src,'" + filename + "')]"); + By titleBy = By.xpath("//figure[contains(@class,'o_image')]//img[contains(@src,'" + filename + "')]"); OOGraphene.waitElement(titleBy, 5, browser); return this; } @@ -153,7 +153,7 @@ public class EntryPage { } public EntryPage assertOnCitation(String citation) { - By citationBy = By.xpath("//blockquote[contains(@class,'o_quote')]/p[contains(text(),'" + citation + "')]"); + By citationBy = By.xpath("//blockquote[contains(@class,'o_quote')]//p[contains(text(),'" + citation + "')]"); OOGraphene.waitElement(citationBy, 5, browser); return this; } diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21CSVImportWizard.java b/src/test/java/org/olat/selenium/page/qti/QTI21CSVImportWizard.java index dcc9ea8a12c216c6edad946263abe27efde28288..2a1fbdc6e1fd06f78b588edabfd41b650296b719 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21CSVImportWizard.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21CSVImportWizard.java @@ -73,7 +73,7 @@ public class QTI21CSVImportWizard { log.error("", ex); } - By importAreaBy = By.cssSelector(".modal-content textarea"); + By importAreaBy = By.cssSelector(".modal-content .o_wizard_steps_current_content textarea"); WebElement importAreaEl = browser.findElement(importAreaBy); OOGraphene.textarea(importAreaEl, sb.toString(), browser); return this; @@ -104,8 +104,7 @@ public class QTI21CSVImportWizard { public QTI21CSVImportWizard finish() { browser.findElement(finishBy).click(); OOGraphene.waitBusy(browser); - OOGraphene.waitElementDisappears(By.cssSelector(".modal-content"), 5, browser); + OOGraphene.waitElementDisappears(By.cssSelector(".modal-content .wizard"), 5, browser); return this; } - } diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21FeedbacksEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21FeedbacksEditorPage.java index c4554d328d560c949adbcbd69432995eb69203f2..79479a1d862f4e7ffbb84b112d9e54e320d16931 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21FeedbacksEditorPage.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21FeedbacksEditorPage.java @@ -19,9 +19,11 @@ */ package org.olat.selenium.page.qti; +import org.junit.Assert; import org.olat.selenium.page.graphene.OOGraphene; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; /** * @@ -38,35 +40,95 @@ public class QTI21FeedbacksEditorPage { } public QTI21FeedbacksEditorPage setHint(String title, String hint) { + openAddFeedbacksMenu().addFeedback("o_sel_add_hint"); + By titleBy = By.cssSelector("div.o_sel_assessment_item_hint_title input[type='text']"); + OOGraphene.waitElement(titleBy, browser); browser.findElement(titleBy).sendKeys(title); - OOGraphene.tinymce(hint, "div.o_sel_assessment_item_hint", browser); + + By hintBy = By.cssSelector("div.o_sel_assessment_item_hint_feedback input[type='text']"); + browser.findElement(hintBy).sendKeys(hint); return this; } public QTI21FeedbacksEditorPage setCorrectSolution(String title, String correctSolution) { - By titleBy = By.cssSelector("div.o_sel_assessment_item_correct_solution_title input[type='text']"); + openAddFeedbacksMenu().addFeedback("o_sel_add_correct_solution"); + + By titleBy = By.cssSelector("div.o_sel_assessment_item_correctSolution_title input[type='text']"); + OOGraphene.waitElement(titleBy, browser); browser.findElement(titleBy).sendKeys(title); - OOGraphene.tinymce(correctSolution, "div.o_sel_assessment_item_correct_solution", browser); + + By correctBy = By.cssSelector("div.o_sel_assessment_item_correctSolution_feedback input[type='text']"); + browser.findElement(correctBy).sendKeys(correctSolution); return this; } public QTI21FeedbacksEditorPage setCorrectFeedback(String title, String feedback) { - By titleBy = By.cssSelector("div.o_sel_assessment_item_correct_feedback_title input[type='text']"); + openAddFeedbacksMenu().addFeedback("o_sel_add_correct"); + + By titleBy = By.cssSelector("div.o_sel_assessment_item_correct_title input[type='text']"); + OOGraphene.waitElement(titleBy, browser); browser.findElement(titleBy).sendKeys(title); - OOGraphene.tinymce(feedback, "div.o_sel_assessment_item_correct_feedback", browser); + + By correctBy = By.cssSelector("div.o_sel_assessment_item_correct_feedback input[type='text']"); + browser.findElement(correctBy).sendKeys(feedback); return this; } public QTI21FeedbacksEditorPage setIncorrectFeedback(String title, String feedback) { - By titleBy = By.cssSelector("div.o_sel_assessment_item_incorrect_feedback_title input[type='text']"); + openAddFeedbacksMenu().addFeedback("o_sel_add_incorrect"); + + By titleBy = By.cssSelector("div.o_sel_assessment_item_incorrect_title input[type='text']"); + OOGraphene.waitElement(titleBy, browser); + browser.findElement(titleBy).sendKeys(title); + + By correctBy = By.cssSelector("div.o_sel_assessment_item_incorrect_feedback input[type='text']"); + browser.findElement(correctBy).sendKeys(feedback); + return this; + } + + public QTI21FeedbacksEditorPage setAnsweredFeedback(String title, String feedback) { + openAddFeedbacksMenu().addFeedback("o_sel_add_answered"); + + By titleBy = By.cssSelector("div.o_sel_assessment_item_answered_title input[type='text']"); + browser.findElement(titleBy).sendKeys(title); + + By answeredBy = By.cssSelector("div.o_sel_assessment_item_answered_feedback input[type='text']"); + browser.findElement(answeredBy).sendKeys(feedback); + return this; + } + + public QTI21FeedbacksEditorPage setEmpytFeedback(String title, String feedback) { + openAddFeedbacksMenu().addFeedback("o_sel_add_empty"); + + By titleBy = By.cssSelector("div.o_sel_assessment_item_empty_title input[type='text']"); browser.findElement(titleBy).sendKeys(title); - OOGraphene.tinymce(feedback, "div.o_sel_assessment_item_incorrect_feedback", browser); + + By emptyBy = By.cssSelector("div.o_sel_assessment_item_empty_feedback input[type='text']"); + browser.findElement(emptyBy).sendKeys(feedback); + return this; + } + + private QTI21FeedbacksEditorPage addFeedback(String cssSelector) { + By addFeedbackBy = By.cssSelector("a." + cssSelector); + browser.findElement(addFeedbackBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + private QTI21FeedbacksEditorPage openAddFeedbacksMenu() { + By addMenuCaretBy = By.cssSelector("button.o_sel_add_feedbacks"); + WebElement addMenuCaret = browser.findElement(addMenuCaretBy); + Assert.assertTrue(addMenuCaret.isDisplayed()); + addMenuCaret.click(); + + By addMenuBy = By.cssSelector("ul.o_sel_add_feedbacks"); + OOGraphene.waitElement(addMenuBy, 5, browser); return this; } public QTI21FeedbacksEditorPage save() { - By saveBy = By.cssSelector("fieldset.o_sel_assessment_item_feedbacks button.btn.btn-primary"); + By saveBy = By.cssSelector("div.o_sel_assessment_item_feedbacks button.btn.btn-primary"); browser.findElement(saveBy).click(); OOGraphene.waitBusy(browser); return this; diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21KprimEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21KprimEditorPage.java index 65fcfd985edb3c2d7b03f6a7911fd1a19d9850af..546db77bad725a0c62022d77a3c2e5f15a01fb45 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21KprimEditorPage.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21KprimEditorPage.java @@ -22,6 +22,7 @@ package org.olat.selenium.page.qti; import org.olat.selenium.page.graphene.OOGraphene; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; /** * @@ -55,8 +56,10 @@ public class QTI21KprimEditorPage extends QTI21AssessmentItemEditorPage { } public QTI21KprimEditorPage setAnswer(int position, String answer) { - String containerCssSelector = "div.o_sel_choice_" + position; - OOGraphene.tinymce(answer, containerCssSelector, browser); + By answerBy = By.cssSelector("div.o_sel_choice_" + position + " input[type='text']"); + WebElement answerEl = browser.findElement(answerBy); + answerEl.clear(); + answerEl.sendKeys(answer); return this; } diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java index 6c6820e987632f2cfa65bbeea2f2bd777a3b6e74..7ae7f1c77f8fe0547c0248ef4d78e7d0511907ed 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21LobEditorPage.java @@ -62,8 +62,8 @@ public class QTI21LobEditorPage extends QTI21AssessmentItemEditorPage { return new QTI21MinimalScoreEditorPage(browser); } - public QTI21LobFeedbacksEditorPage selectFeedbacks() { + public QTI21FeedbacksEditorPage selectFeedbacks() { selectTab(By.className("o_sel_assessment_item_feedbacks")); - return new QTI21LobFeedbacksEditorPage(browser); + return new QTI21FeedbacksEditorPage(browser); } } diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21LobFeedbacksEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21LobFeedbacksEditorPage.java deleted file mode 100644 index 85cdb06111fb39210de31d6296267238224377b8..0000000000000000000000000000000000000000 --- a/src/test/java/org/olat/selenium/page/qti/QTI21LobFeedbacksEditorPage.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * <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> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.selenium.page.qti; - -import org.olat.selenium.page.graphene.OOGraphene; -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; - -/** - * - * Drive the feedbackabck editor with the special empty / answered - * feedbacks. - * - * Initial date: 12 mai 2017<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class QTI21LobFeedbacksEditorPage { - - private final WebDriver browser; - - public QTI21LobFeedbacksEditorPage(WebDriver browser) { - this.browser = browser; - } - - public QTI21LobFeedbacksEditorPage setHint(String title, String hint) { - By titleBy = By.cssSelector("div.o_sel_assessment_item_hint_title input[type='text']"); - browser.findElement(titleBy).sendKeys(title); - OOGraphene.tinymce(hint, "div.o_sel_assessment_item_hint", browser); - return this; - } - - public QTI21LobFeedbacksEditorPage setCorrectSolution(String title, String correctSolution) { - By titleBy = By.cssSelector("div.o_sel_assessment_item_correct_solution_title input[type='text']"); - browser.findElement(titleBy).sendKeys(title); - OOGraphene.tinymce(correctSolution, "div.o_sel_assessment_item_correct_solution", browser); - return this; - } - - public QTI21LobFeedbacksEditorPage setAnsweredFeedback(String title, String feedback) { - By titleBy = By.cssSelector("div.o_sel_assessment_item_answered_feedback_title input[type='text']"); - browser.findElement(titleBy).sendKeys(title); - OOGraphene.tinymce(feedback, "div.o_sel_assessment_item_answered_feedback", browser); - return this; - } - - public QTI21LobFeedbacksEditorPage setEmpytFeedback(String title, String feedback) { - By titleBy = By.cssSelector("div.o_sel_assessment_item_empty_feedback_title input[type='text']"); - browser.findElement(titleBy).sendKeys(title); - OOGraphene.tinymce(feedback, "div.o_sel_assessment_item_empty_feedback", browser); - return this; - } - - public QTI21LobFeedbacksEditorPage save() { - By saveBy = By.cssSelector("fieldset.o_sel_assessment_item_feedbacks button.btn.btn-primary"); - browser.findElement(saveBy).click(); - OOGraphene.waitBusy(browser); - return this; - } -} diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21MultipleChoiceEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21MultipleChoiceEditorPage.java index e191a816cb5a1888be26ea5a610a144e27d4f88d..a1f34b97709ace4364853ef4feddd6f46addc861 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21MultipleChoiceEditorPage.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21MultipleChoiceEditorPage.java @@ -62,8 +62,14 @@ public class QTI21MultipleChoiceEditorPage extends QTI21AssessmentItemEditorPage } public QTI21MultipleChoiceEditorPage setAnswer(int position, String answer) { - String containerCssSelector = "div.o_sel_choice_" + position; - OOGraphene.tinymce(answer, containerCssSelector, browser); + By oneLineInputBy = By.cssSelector("div.o_sel_choice_" + position + " input[type='text']"); + OOGraphene.waitElement(oneLineInputBy, browser); + WebElement oneLineInputEl = browser.findElement(oneLineInputBy); + oneLineInputEl.clear(); + oneLineInputEl.sendKeys(answer); + + //String containerCssSelector = "div.o_sel_choice_" + position; + //OOGraphene.tinymce(answer, containerCssSelector, browser); return this; } diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java index b553cd5162e84304f44c445f8eb94b3420945e1e..d412a936960095ba8ca7fb5c4286d2f0f4611a33 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java @@ -179,7 +179,7 @@ public class QTI21Page { By sourceBy = By.xpath("//li[contains(@class,'o_match_dnd_source')]/p[contains(text(),'" + source + "')]"); OOGraphene.waitElement(sourceBy, 5, browser); WebElement sourceEl = browser.findElement(sourceBy); - By targetBy = By.xpath("//li[contains(@class,'o_match_dnd_target')]/p[contains(text(),'" + target + "')]"); + By targetBy = By.xpath("//li[contains(@class,'o_match_dnd_target')]/div[@class='clearfix']/p[contains(text(),'" + target + "')]"); WebElement targetEl = browser.findElement(targetBy); new Actions(browser) .moveToElement(sourceEl, 30, 30) @@ -197,7 +197,7 @@ public class QTI21Page { public QTI21Page answerMatchDropTargetToTarget(String source, String target) { By sourceDroppedBy = By.xpath("//ul[contains(@class,'o_match_dnd_target_drop_zone')]/li[contains(@class,'o_match_dnd_source')]/p[contains(text(),'" + source + "')]"); WebElement sourceEl = browser.findElement(sourceDroppedBy); - By targetBy = By.xpath("//li[contains(@class,'o_match_dnd_target')]/p[contains(text(),'" + target + "')]"); + By targetBy = By.xpath("//li[contains(@class,'o_match_dnd_target')]/div[@class='clearfix']/p[contains(text(),'" + target + "')]"); WebElement targetEl = browser.findElement(targetBy); new Actions(browser) .moveToElement(sourceEl, 30, 30) @@ -384,6 +384,12 @@ public class QTI21Page { return this; } + public QTI21Page assertOnAssessmentTestScore(String score) { + By resultsBy = By.xpath("//div[contains(@class,'o_sel_results_details')]//tr[contains(@class,'o_sel_assessmenttest_scores')]/td/div/span[contains(@class,'o_sel_assessmenttest_score')][contains(text(),'" + score + "')]"); + OOGraphene.waitElement(resultsBy, 5, browser); + return this; + } + public QTI21Page assertOnAssessmentTestPassed() { By notPassedBy = By.cssSelector("div.o_sel_results_details tr.o_qti_stateinfo.o_passed"); OOGraphene.waitElement(notPassedBy, 5, browser); diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21SingleChoiceEditorPage.java b/src/test/java/org/olat/selenium/page/qti/QTI21SingleChoiceEditorPage.java index 81a56b119d2047c2c34a598df25946238ae115f7..38bfbea5ae28afbd3ce9a23df352b16094b5afce 100644 --- a/src/test/java/org/olat/selenium/page/qti/QTI21SingleChoiceEditorPage.java +++ b/src/test/java/org/olat/selenium/page/qti/QTI21SingleChoiceEditorPage.java @@ -22,6 +22,7 @@ package org.olat.selenium.page.qti; import org.olat.selenium.page.graphene.OOGraphene; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; /** * @@ -57,8 +58,14 @@ public class QTI21SingleChoiceEditorPage extends QTI21AssessmentItemEditorPage { } public QTI21SingleChoiceEditorPage setAnswer(int position, String answer) { - String containerCssSelector = "div.o_sel_choice_" + position; - OOGraphene.tinymce(answer, containerCssSelector, browser); + By oneLineInputBy = By.cssSelector("div.o_sel_choice_" + position + " input[type='text']"); + OOGraphene.waitElement(oneLineInputBy, browser); + WebElement oneLineInputEl = browser.findElement(oneLineInputBy); + oneLineInputEl.clear(); + oneLineInputEl.sendKeys(answer); + + //String containerCssSelector = "div.o_sel_choice_" + position; + //OOGraphene.tinymce(answer, containerCssSelector, browser); return this; } diff --git a/src/test/java/org/olat/selenium/page/user/UserToolsPage.java b/src/test/java/org/olat/selenium/page/user/UserToolsPage.java index e60c248399f3b802ac110b4a8cbac5bd7a66b5d7..22111c8a3d55e44593b8965a6e58f6757400a599 100644 --- a/src/test/java/org/olat/selenium/page/user/UserToolsPage.java +++ b/src/test/java/org/olat/selenium/page/user/UserToolsPage.java @@ -25,6 +25,7 @@ import org.junit.Assert; import org.olat.selenium.page.LoginPage; import org.olat.selenium.page.core.FolderPage; import org.olat.selenium.page.graphene.OOGraphene; +import org.olat.selenium.page.lecture.LecturesToolPage; import org.olat.selenium.page.portfolio.PortfolioV2HomePage; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; @@ -157,6 +158,13 @@ public class UserToolsPage { return page; } + public LecturesToolPage openLectures() { + By myLecturesBy = By.className("o_sel_user_tools-mylectures"); + browser.findElement(myLecturesBy).click(); + OOGraphene.waitBusy(browser); + return new LecturesToolPage(browser); + } + /** * Log out and wait until the login form appears */ diff --git a/src/test/java/org/olat/shibboleth/handler/DoNothingHandlerTest.java b/src/test/java/org/olat/shibboleth/handler/DoNothingHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c8d6d87d84c9f6e7555185c7f5fd0455589a180e --- /dev/null +++ b/src/test/java/org/olat/shibboleth/handler/DoNothingHandlerTest.java @@ -0,0 +1,44 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class DoNothingHandlerTest { + + private DoNothingHandler sut = new DoNothingHandler(); + + @Test + public void parseShouldReturnTheSameString() { + String input = "input"; + + String parsed = sut.parse(input); + + assertThat(parsed).isEqualTo(input); + } +} diff --git a/src/test/java/org/olat/shibboleth/handler/FirstValueHandlerTest.java b/src/test/java/org/olat/shibboleth/handler/FirstValueHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c4e36edba17bd72ab0c9ac804e7a0ef6aeda8ab4 --- /dev/null +++ b/src/test/java/org/olat/shibboleth/handler/FirstValueHandlerTest.java @@ -0,0 +1,61 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class FirstValueHandlerTest { + + FirstValueHandler sut = new FirstValueHandler(); + + @Test + public void parseShoudReturnFirstValueIfMultipleVales() { + String expected = "abc"; + String input = expected + ";abc;222;a;erer;sdfsfd"; + + String parsed = sut.parse(input); + + assertThat(parsed).isEqualTo(expected); + } + + @Test + public void parseShoudReturnFirstValueIfOneValue() { + String input = "abc"; + + String parsed = sut.parse(input); + + assertThat(parsed).isEqualTo(input); + } + + @Test + public void parseShoudReturnFirstValueIfNull() { + String parsed = sut.parse(null); + + assertThat(parsed).isNull(); + } +} diff --git a/src/test/java/org/olat/shibboleth/handler/SchacGenderHandlerTest.java b/src/test/java/org/olat/shibboleth/handler/SchacGenderHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..555a650da955d5f10eec913a71eb269184005be8 --- /dev/null +++ b/src/test/java/org/olat/shibboleth/handler/SchacGenderHandlerTest.java @@ -0,0 +1,72 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * + * Initial date: 21.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class SchacGenderHandlerTest { + + private static final String OLAT_DEFAULT = "-"; + private SchacGenderHandler sut = new SchacGenderHandler(); + + @Test + public void parseShouldHandleMale() { + String schacMale = "1"; + String olatMale = "male"; + + String parsed = sut.parse(schacMale); + + assertThat(parsed).isEqualTo(olatMale); + } + + @Test + public void parseShouldHandleFemale() { + String schacFemale = "2"; + String olatFemale = "female"; + + String parsed = sut.parse(schacFemale); + + assertThat(parsed).isEqualTo(olatFemale); + } + + @Test + public void parseShouldHandleOther() { + String randomValue = "abc"; + + String parsed = sut.parse(randomValue); + + assertThat(parsed).isEqualTo(OLAT_DEFAULT); + } + + @Test + public void parseShouldHandleNull() { + String parsed = sut.parse(null); + + assertThat(parsed).isEqualTo(OLAT_DEFAULT); + } +} diff --git a/src/test/java/org/olat/shibboleth/handler/SpringShibbolethAttributeHandlerFactoryTest.java b/src/test/java/org/olat/shibboleth/handler/SpringShibbolethAttributeHandlerFactoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cc32c3b0a1b893af1620a8d911d2691c5a6521e5 --- /dev/null +++ b/src/test/java/org/olat/shibboleth/handler/SpringShibbolethAttributeHandlerFactoryTest.java @@ -0,0 +1,62 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.handler; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import org.olat.test.OlatTestCase; + +/** + * + * Initial date: 05.08.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class SpringShibbolethAttributeHandlerFactoryTest extends OlatTestCase { + + SpringShibbolethAttributeHandlerFactory sut = new SpringShibbolethAttributeHandlerFactory(); + + @Test + public void shouldGetHandlerFromSpring() { + String nameOFExistingHandler = "FirstValue"; + + ShibbolethAttributeHandler handler = sut.getHandler(nameOFExistingHandler); + + assertThat(handler).isInstanceOf(FirstValueHandler.class); + } + + @Test + public void shouldReturnDoNothingHandlerIfNoSpringComponentFound() { + String nameOfNotExistingHandler = "notExisting"; + + ShibbolethAttributeHandler handler = sut.getHandler(nameOfNotExistingHandler); + + assertThat(handler).isInstanceOf(DoNothingHandler.class); + } + + @Test + public void shouldReturnDoNothingHandlerIfHandlerNotConfigurated() { + ShibbolethAttributeHandler handler = sut.getHandler(null); + + assertThat(handler).isInstanceOf(DoNothingHandler.class); + } +} diff --git a/src/test/java/org/olat/shibboleth/manager/DifferenceCheckerTest.java b/src/test/java/org/olat/shibboleth/manager/DifferenceCheckerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ac5931ca86a6d2725843fd660203aba70a9f917b --- /dev/null +++ b/src/test/java/org/olat/shibboleth/manager/DifferenceCheckerTest.java @@ -0,0 +1,134 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Answers; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.shibboleth.ShibbolethModule; + +/** + * + * Initial date: 10.08.2017<br> + * + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class DifferenceCheckerTest { + + private static final String ATTRIBUTE_NAME = "attributeName"; + private static final String THE_SAME = "theSame"; + private static final String SHIBBOLETH_ONLY = "shibbolethOnly"; + private static final String OLAT_ONLY = "olatOnly"; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + ShibbolethModule shibbolethModuleMock; + + @InjectMocks + private DifferenceChecker sut; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void shouldBeDifferentWhenShibOlatFalse() { + shouldReturnDifferent(SHIBBOLETH_ONLY, OLAT_ONLY, false); + } + + @Test + public void shouldBeDifferentWhenShibOlatTrue() { + shouldReturnDifferent(SHIBBOLETH_ONLY, OLAT_ONLY, true); + } + + @Test + public void shouldBeDifferentWhenShibNullFalse() { + shouldReturnDifferent(SHIBBOLETH_ONLY, null, false); + } + + @Test + public void shouldBeDifferentWhenShibNullTrue() { + shouldReturnDifferent(SHIBBOLETH_ONLY, null, true); + } + + @Test + public void shouldBeDifferentWhenNullOlatTrue() { + shouldReturnDifferent(null, OLAT_ONLY, true); + } + + @Test + public void shouldBeNotDifferentWhenNullOlatfalse() { + shouldReturnNotDifferent(null, OLAT_ONLY, false); + } + + @Test + public void shouldBeNotDifferentWhenSameSameFalse() { + shouldReturnNotDifferent(THE_SAME, THE_SAME, false); + } + + @Test + public void shouldBeNotDifferentWhenSameSameTrue() { + shouldReturnNotDifferent(THE_SAME, THE_SAME, false); + } + + @Test + public void shouldBeNotDifferentWhenNullNullFalse() { + shouldReturnNotDifferent(null, null, false); + } + + @Test + public void shouldBeNotDifferentWhenNullNullTrue() { + shouldReturnNotDifferent(null, null, true); + } + + private void shouldReturnDifferent(String shibbolethAttributeName, String userPropertyValue, boolean deleteIfNull) { + boolean isDiferent = prepareAndRunChceck(shibbolethAttributeName, userPropertyValue, deleteIfNull); + + assertThat(isDiferent).isTrue(); + } + + private void shouldReturnNotDifferent(String shibbolethAttributeName, String userPropertyValue, boolean deleteIfNull) { + boolean isDiferent = prepareAndRunChceck(shibbolethAttributeName, userPropertyValue, deleteIfNull); + + assertThat(isDiferent).isFalse(); + } + + private boolean prepareAndRunChceck(String shibbolethAttributeName, String userPropertyValue, boolean deleteIfNull) { + when(shibbolethModuleMock.getDeleteIfNull().get(ATTRIBUTE_NAME)).thenReturn(deleteIfNull); + + return sut.isDifferent(ATTRIBUTE_NAME, shibbolethAttributeName, userPropertyValue); + } + + @Test + public void shouldDeleteNullIfNotConfigured() { + when(shibbolethModuleMock.getDeleteIfNull().get(ATTRIBUTE_NAME)).thenThrow(Exception.class); + + boolean isDifferent = sut.isDifferent(ATTRIBUTE_NAME, null, OLAT_ONLY); + + assertThat(isDifferent).isTrue(); + } +} diff --git a/src/test/java/org/olat/shibboleth/manager/ShibbolethAttributesTest.java b/src/test/java/org/olat/shibboleth/manager/ShibbolethAttributesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..268078c536c45da427df4c2b6812b2bac27dc1dc --- /dev/null +++ b/src/test/java/org/olat/shibboleth/manager/ShibbolethAttributesTest.java @@ -0,0 +1,383 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.AdditionalAnswers.returnsFirstArg; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.core.id.User; +import org.olat.core.id.UserConstants; +import org.olat.shibboleth.ShibbolethModule; +import org.olat.shibboleth.handler.ShibbolethAttributeHandler; +import org.olat.shibboleth.handler.ShibbolethAttributeHandlerFactory; +import org.olat.user.UserImpl; +import org.springframework.test.util.ReflectionTestUtils; + + +/** + * + * Initial date: 06.08.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class ShibbolethAttributesTest { + + private static final String SHIB_UID_KEY = "shibUidKey"; + private static final String SHIB_UID_VALUE = "shibUidValue"; + private static final String SHIB_LANG_KEY = "shibLangKey"; + private static final String SHIB_LANG_VALUE = "shibLangValue"; + private static final String USER_EMAIL_KEY = UserConstants.EMAIL; + private static final String SHIB_EMAIL_KEY = "shibEmailKey"; + private static final String SHIB_EMAIL_VALUE = "shibEmailValue"; + private static final String USER_NAME_KEY = UserConstants.LASTNAME; + private static final String SHIB_NAME_KEY = "shibName"; + private static final String SHIB_NAME_VALUE = "Smith"; + private static final String USER_GENDER_KEY = UserConstants.GENDER; + private static final String SHIB_GENDER_KEY = "shibGender"; + private static final String SHIB_GENDER_VALUE = "female"; + private static final String USER_CITY_KEY = UserConstants.CITY; + private static final String SHIB_CITY_KEY = "shibCity"; + private static final String SHIB_CITY_VALUE_NULL = null; + private static final String USER_OLD_VALUE = "old"; + private static final String SHIB_AC_IDENTIFIER_KEY = "adIdenitfierKey"; + private static final String SHIB_AC_IDENTIFIER_VALUE = "adIdenitfierValue"; + + @Mock + private ShibbolethModule shibbolethModuleMock; + @Mock + private ShibbolethAttributeHandlerFactory shibbolethAttributeHandlerFactoryMock; + @Mock + private ShibbolethAttributeHandler shibbolethAttributeHandlerMock; + @Mock + private DifferenceChecker differenceCheckerMock; + + private ShibbolethAttributes sut; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + sut = new ShibbolethAttributes(); + + ReflectionTestUtils.setField(sut, "shibbolethModule", shibbolethModuleMock); + Map<String, String> shibbolethUserMapping = initUserMapping(); + when(shibbolethModuleMock.getUserMapping()).thenReturn(shibbolethUserMapping); + when(shibbolethModuleMock.getShibbolethAttributeNames()).thenReturn(initShibbolethMap().keySet()); + when(shibbolethModuleMock.getUIDAttributeName()).thenReturn(SHIB_UID_KEY); + when(shibbolethModuleMock.getPreferredLanguageAttributeName()).thenReturn(SHIB_LANG_KEY); + when(shibbolethModuleMock.getAcAutoAttributeName()).thenReturn(SHIB_AC_IDENTIFIER_KEY); + + // ShibbolethAttributeHandler.parse() does not modify the value + ReflectionTestUtils.setField(sut, "shibbolethAttributeHandlerFactory", shibbolethAttributeHandlerFactoryMock); + when(shibbolethAttributeHandlerFactoryMock.getHandler(anyString())).thenReturn(shibbolethAttributeHandlerMock); + when(shibbolethAttributeHandlerFactoryMock.getHandler(isNull())).thenReturn(shibbolethAttributeHandlerMock); + when(shibbolethAttributeHandlerMock.parse(anyString())).then(returnsFirstArg()); + + ReflectionTestUtils.setField(sut, "differenceChecker", differenceCheckerMock); + + Map<String, String> shibbolethKeysValues = initShibbolethMap(); + sut.init(shibbolethKeysValues); + } + + private Map<String, String> initShibbolethMap() { + Map<String, String> shibbolethMap = new HashMap<>(); + shibbolethMap.put(SHIB_UID_KEY, SHIB_UID_VALUE); + shibbolethMap.put(SHIB_LANG_KEY, SHIB_LANG_VALUE); + shibbolethMap.put(SHIB_EMAIL_KEY, SHIB_EMAIL_VALUE); + shibbolethMap.put(SHIB_NAME_KEY, SHIB_NAME_VALUE); + shibbolethMap.put(SHIB_GENDER_KEY, SHIB_GENDER_VALUE); + shibbolethMap.put(SHIB_CITY_KEY, SHIB_CITY_VALUE_NULL); + shibbolethMap.put(SHIB_AC_IDENTIFIER_KEY, SHIB_AC_IDENTIFIER_VALUE); + return shibbolethMap; + } + + private Map<String, String> initUserMapping() { + Map<String, String> shibbolethUserMapping = new HashMap<>(); + shibbolethUserMapping.put(SHIB_EMAIL_KEY, USER_EMAIL_KEY); + shibbolethUserMapping.put(SHIB_NAME_KEY, USER_NAME_KEY); + shibbolethUserMapping.put(SHIB_GENDER_KEY, USER_GENDER_KEY); + shibbolethUserMapping.put(SHIB_CITY_KEY, USER_CITY_KEY); + return shibbolethUserMapping; + } + + private User getIdenticalOlatUser() { + User user = new TestableUser(); + user.setProperty(USER_EMAIL_KEY, SHIB_EMAIL_VALUE); + user.setProperty(USER_NAME_KEY, SHIB_NAME_VALUE); + user.setProperty(USER_GENDER_KEY, SHIB_GENDER_VALUE); + user.setProperty(USER_CITY_KEY, SHIB_CITY_VALUE_NULL); + return user; + } + + @Test + public void shouldParseValuesWhenInit() { + verify(shibbolethAttributeHandlerMock, times(6)).parse(anyString()); + verify(shibbolethAttributeHandlerMock, times(1)).parse(isNull()); + } + + @Test + public void shouldReturnUniqueIdentifier() { + String uid = sut.getUID(); + + assertThat(uid).isEqualTo(SHIB_UID_VALUE); + } + + @Test + public void shouldReturnPreferredLanguage() { + String lang = sut.getPreferredLanguage(); + + assertThat(lang).isEqualTo(SHIB_LANG_VALUE); + } + + @Test + public void shouldReturnAcIdentifierValues() { + String acName = sut.getAcRawValues(); + + assertThat(acName).isEqualTo(SHIB_AC_IDENTIFIER_VALUE); + } + + @Test + public void shouldReplaceValueByUserPropertyName() { + String newValue = "newValue"; + + sut.setValueForUserPropertyName(USER_NAME_KEY, newValue); + + assertThat(sut.getValueForUserPropertyName(USER_NAME_KEY)).isEqualTo(newValue); + } + + @Test + public void shouldNotSetPropertValueWhenNoMappingExits() { + String keyNotPresent = "keyNotPresent"; + String newValue = "newValue"; + + sut.setValueForUserPropertyName(keyNotPresent, newValue); + + assertThat(sut.getValueForUserPropertyName(keyNotPresent)).isNull(); + } + + @Test + public void shouldNotParseValueWhenSet() { + sut.setValueForUserPropertyName(USER_NAME_KEY, "newValue"); + + verify(shibbolethAttributeHandlerMock, times(initUserMapping().size() + 2)).parse(anyString()); + } + + @Test + public void shouldReturnACopyOfTheInternalMap() { + Map<String, String> copiedttributes = sut.toMap(); + + Map<String, String> initMap = initShibbolethMap(); + Set<String> initKeys = initMap.keySet(); + assertThat(copiedttributes).isNotSameAs(initMap).containsKeys(initKeys.toArray(new String[initKeys.size()])); + } + + @Test + public void shouldReturnValueForAShibbolethAttributeName() { + String shibbolethValue = sut.getValueForAttributeName(SHIB_EMAIL_KEY); + + assertThat(shibbolethValue).isEqualTo(SHIB_EMAIL_VALUE); + } + + @Test + public void shouldReturnNullIfNoEntryPresentForShibbolethAttributeName() { + String keyNotPresent = "keyNotPresent"; + + String shibbolethValue = sut.getValueForAttributeName(keyNotPresent); + + assertThat(shibbolethValue).isNull(); + } + + @Test + public void shouldReturnValueForAUserPropertyName() { + String shibbolethValue = sut.getValueForUserPropertyName(USER_EMAIL_KEY); + + assertThat(shibbolethValue).isEqualTo(SHIB_EMAIL_VALUE); + } + + @Test + public void shouldReturnNullIfNoEntryPresentForUserPropertyName() { + String keyNotPresent = "keyNotPresent"; + + String shibbolethValue = sut.getValueForUserPropertyName(keyNotPresent); + + assertThat(shibbolethValue).isNull(); + } + + @Test + public void shouldReturnTrueIfManyAttributesHaveChanged() { + User user = getIdenticalOlatUser(); + when(differenceCheckerMock.isDifferent(SHIB_NAME_KEY, SHIB_NAME_VALUE, SHIB_NAME_VALUE)).thenReturn(true); + when(differenceCheckerMock.isDifferent(SHIB_GENDER_KEY, SHIB_GENDER_VALUE, SHIB_GENDER_VALUE)).thenReturn(true); + + boolean hasDifference = sut.hasDifference(user); + + assertThat(hasDifference).isTrue(); + } + + @Test + public void shouldReturnTrueIfOneAttributeHaveChanged() { + User user = getIdenticalOlatUser(); + when(differenceCheckerMock.isDifferent(SHIB_NAME_KEY, SHIB_NAME_VALUE, SHIB_NAME_VALUE)).thenReturn(true); + + boolean hasDifference = sut.hasDifference(user); + + assertThat(hasDifference).isTrue(); + } + + @Test + public void shouldReturnFalseIfNoAttributeHasChanged() { + User user = getIdenticalOlatUser(); + + boolean hasDifference = sut.hasDifference(user); + + assertThat(hasDifference).isFalse(); + } + + @Test + public void shouldNotChangeProperyOfSyncedUserIfSameValue() { + User user = getIdenticalOlatUser(); + + User syncedUser = sut.syncUser(user); + + assertThat(syncedUser.getProperty(USER_EMAIL_KEY, null)).isEqualTo(SHIB_EMAIL_VALUE); + } + + @Test + public void shouldChangeChangedPropertyOfSyncedUser() { + User user = getIdenticalOlatUser(); + user.setProperty(USER_NAME_KEY, USER_OLD_VALUE); + + User syncedUser = sut.syncUser(user); + + assertThat(syncedUser.getProperty(USER_CITY_KEY, null)).isEqualTo(SHIB_CITY_VALUE_NULL); + } + + @Test + public void shouldChangePropertyOfSyncedUserIfItWasNotPresent() { + User user = getIdenticalOlatUser(); + user.setProperty(USER_NAME_KEY, null); + + User syncedUser = sut.syncUser(user); + + assertThat(syncedUser.getProperty(USER_CITY_KEY, null)).isEqualTo(SHIB_CITY_VALUE_NULL); + } + + @Test + public void shouldNotChangeNullValueOfSyncedUser() { + User user = getIdenticalOlatUser(); + sut.setValueForUserPropertyName(USER_EMAIL_KEY, null); + when(differenceCheckerMock.isDifferent(SHIB_EMAIL_KEY, null, SHIB_EMAIL_VALUE)).thenReturn(false); + String newGenderValue = "changedValue"; + sut.setValueForUserPropertyName(USER_GENDER_KEY, newGenderValue); + when(differenceCheckerMock.isDifferent(SHIB_GENDER_KEY, newGenderValue, SHIB_GENDER_VALUE)).thenReturn(true); + + User syncedUser = sut.syncUser(user); + + assertThat(syncedUser.getProperty(USER_EMAIL_KEY, null)).isEqualTo(SHIB_EMAIL_VALUE); + assertThat(syncedUser.getProperty(USER_CITY_KEY, null)).isEqualTo(SHIB_CITY_VALUE_NULL); + assertThat(syncedUser.getProperty(USER_GENDER_KEY, null)).isEqualTo(newGenderValue); + } + + @Test + public void shouldRemovePropertyFromSyncedUserIfNotPresentInShibboleth() { + User user = getIdenticalOlatUser(); + user.setProperty(USER_CITY_KEY, USER_OLD_VALUE); + when(differenceCheckerMock.isDifferent(SHIB_CITY_KEY, SHIB_CITY_VALUE_NULL, USER_OLD_VALUE)).thenReturn(true); + + User syncedUser = sut.syncUser(user); + + assertThat(syncedUser.getProperty(USER_CITY_KEY, null)).isEqualTo(SHIB_CITY_VALUE_NULL); + } + + @Test + public void shouldNotBeAnAuthorIfAuthorMappingIsDisabled() { + when(shibbolethModuleMock.isAuthorMappingEnabled()).thenReturn(false); + + boolean isAuthor = sut.isAuthor(); + + assertThat(isAuthor).isFalse(); + } + + @Test + public void shouldNotBeAnAuthorIfAttributeDoesNotContainValue() { + when(shibbolethModuleMock.isAuthorMappingEnabled()).thenReturn(true); + when(shibbolethModuleMock.getAuthorMappingAttributeName()).thenReturn(SHIB_NAME_KEY); + when(shibbolethModuleMock.getAuthorMappingContains()).thenReturn(Arrays.<String>asList("notContained")); + + boolean isAuthor = sut.isAuthor(); + + assertThat(isAuthor).isFalse(); + } + + @Test + public void shouldBeAnAuthorIfAttributeContainsValue() { + when(shibbolethModuleMock.isAuthorMappingEnabled()).thenReturn(true); + when(shibbolethModuleMock.getAuthorMappingAttributeName()).thenReturn(SHIB_NAME_KEY); + when(shibbolethModuleMock.getAuthorMappingContains()).thenReturn(Arrays.<String>asList("mi")); + + boolean isAuthor = sut.isAuthor(); + + assertThat(isAuthor).isTrue(); + } + + @Test + public void shouldBeAnAuthorIfAttributeContainsOneOfManyValue() { + when(shibbolethModuleMock.isAuthorMappingEnabled()).thenReturn(true); + when(shibbolethModuleMock.getAuthorMappingAttributeName()).thenReturn(SHIB_NAME_KEY); + when(shibbolethModuleMock.getAuthorMappingContains()).thenReturn(Arrays.<String>asList("a","b","c","mi","sun")); + + boolean isAuthor = sut.isAuthor(); + + assertThat(isAuthor).isTrue(); + } + + @SuppressWarnings("serial") + private class TestableUser extends UserImpl { + + private Map<String, String> properties = new HashMap<>(); + + @Override + public String getProperty(String propertyName, Locale locale) { + return properties.get(propertyName); + } + + @Override + public void setProperty(String propertyName, String propertyValue) { + properties.put(propertyName, propertyValue); + } + + } + +} diff --git a/src/test/java/org/olat/shibboleth/manager/ShibbolethManagerImplTest.java b/src/test/java/org/olat/shibboleth/manager/ShibbolethManagerImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..660f191b72c2bdc1b23535ec4d515fddea6a4718 --- /dev/null +++ b/src/test/java/org/olat/shibboleth/manager/ShibbolethManagerImplTest.java @@ -0,0 +1,239 @@ +/** + * <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> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.shibboleth.manager; + +import static org.mockito.AdditionalAnswers.returnsFirstArg; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collection; +import java.util.HashSet; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.Constants; +import org.olat.basesecurity.SecurityGroup; +import org.olat.core.id.Identity; +import org.olat.core.id.Preferences; +import org.olat.core.id.User; +import org.olat.resource.accesscontrol.AccessControlModule; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder; +import org.olat.resource.accesscontrol.provider.auto.AutoAccessManager; +import org.olat.shibboleth.ShibbolethDispatcher; +import org.olat.user.UserManager; +import org.springframework.test.util.ReflectionTestUtils; + +/** + * + * Initial date: 19.07.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class ShibbolethManagerImplTest { + + @Mock + private AccessControlModule acModuleMock; + @Mock + private BaseSecurity securityManagerMock; + @Mock + private SecurityGroup securityGroupOlatusersMock; + @Mock + private SecurityGroup securityGroupAuthorMock; + @Mock + private UserManager userManagerMock; + @Mock + private AutoAccessManager autoAccessManagerMock; + @Mock + private ShibbolethAdvanceOrderInput advanceOrderInputMock; + @Mock + private Identity identityMock; + @Mock + private User userMock; + @Mock + private Preferences preferencesMock; + @Mock + private ShibbolethAttributes attributesMock; + + private TestableShibbolethManagerImpl sut = new TestableShibbolethManagerImpl(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + ReflectionTestUtils.setField(sut, "securityManager", securityManagerMock); + ReflectionTestUtils.setField(sut, "acModule", acModuleMock); + ReflectionTestUtils.setField(sut, "autoAccessManager", autoAccessManagerMock); + ReflectionTestUtils.setField(sut, "userManager", userManagerMock); + + when(securityManagerMock.findSecurityGroupByName(Constants.GROUP_OLATUSERS)) + .thenReturn(securityGroupOlatusersMock); + when(securityManagerMock.findSecurityGroupByName(Constants.GROUP_AUTHORS)) + .thenReturn(securityGroupAuthorMock); + when(securityManagerMock.createAndPersistIdentityAndUser(anyString(), isNull(), any(User.class), anyString(), anyString())) + .thenReturn(identityMock); + when(userManagerMock.createUser(null, null, null)).thenReturn(userMock); + when(identityMock.getUser()).thenReturn(userMock); + when(userMock.getPreferences()).thenReturn(preferencesMock); + when(attributesMock.syncUser(any(User.class))).then(returnsFirstArg()); + when(attributesMock.getAcRawValues()).thenReturn("values"); + } + + @Test + public void shouldCreateAndPersistNewUser() { + sut.createUser(anyString(), anyString(), anyString(), attributesMock); + + verify(securityManagerMock).createAndPersistIdentityAndUser( + anyString(), eq(null), eq(userMock), eq(ShibbolethDispatcher.PROVIDER_SHIB), anyString()); + } + + @Test + public void shouldAddNewUserToUsersGroup() { + sut.createUser(anyString(), anyString(), anyString(), attributesMock); + + verify(securityManagerMock).addIdentityToSecurityGroup(identityMock, securityGroupOlatusersMock); + } + + @Test + public void shouldAddUserToAuthorGroupIfIsAuthorWhenCreating() { + when(attributesMock.isAuthor()).thenReturn(true); + + sut.createUser(anyString(), anyString(), anyString(), attributesMock); + + verify(securityManagerMock).addIdentityToSecurityGroup(identityMock, securityGroupAuthorMock); + } + + @Test + public void shouldAddUserToAuthorGroupIfIsAuthorWhenSyncing() { + when(attributesMock.isAuthor()).thenReturn(true); + + sut.syncUser(identityMock, attributesMock); + + verify(securityManagerMock).addIdentityToSecurityGroup(identityMock, securityGroupAuthorMock); + } + + @Test + public void shouldNotRemoveFromAuthorGroupIfIsNotAuthor() { + when(attributesMock.isAuthor()).thenReturn(true); + + sut.syncUser(identityMock, attributesMock); + + verify(securityManagerMock, never()).removeIdentityFromSecurityGroup(identityMock, securityGroupAuthorMock); + } + + @Test + public void shouldCreateAdvanceOrderWhenCreating() { + when(acModuleMock.isAutoEnabled()).thenReturn(true); + + sut.createUser(anyString(), anyString(), anyString(), attributesMock); + + verify(autoAccessManagerMock).createAdvanceOrders(advanceOrderInputMock); + } + + @Test + public void shouldBookAdvanceOrderWhenCreating() { + when(acModuleMock.isAutoEnabled()).thenReturn(true); + + sut.createUser(anyString(), anyString(), anyString(), attributesMock); + + verify(autoAccessManagerMock).grantAccessToCourse(identityMock); + } + + @Test + public void shouldCreateAdvanceOrderWhenSyncing() { + when(acModuleMock.isAutoEnabled()).thenReturn(true); + + sut.syncUser(identityMock, attributesMock); + + verify(autoAccessManagerMock).createAdvanceOrders(advanceOrderInputMock); + } + + @Test + public void shouldBookAdvanceOrderWhenSyncing() { + when(acModuleMock.isAutoEnabled()).thenReturn(true); + + sut.syncUser(identityMock, attributesMock); + + verify(autoAccessManagerMock).grantAccessToCourse(identityMock); + } + + + @Test + public void shouldNotCreateAdvanceOrderWhenDisabled() { + when(acModuleMock.isAutoEnabled()).thenReturn(false); + + sut.syncUser(identityMock, attributesMock); + + verify(autoAccessManagerMock, never()).createAdvanceOrders(null); + } + + @Test + public void shouldNotBookAdvanceOrderWhenDisabled() { + when(acModuleMock.isAutoEnabled()).thenReturn(false); + Collection<AdvanceOrder> advanceOrders = new HashSet<>(); + when(autoAccessManagerMock.loadPendingAdvanceOrders(identityMock)).thenReturn(advanceOrders); + + sut.syncUser(identityMock, attributesMock); + + verify(autoAccessManagerMock, never()).grantAccess(advanceOrders); + } + + @Test + public void shouldSyncUserWhenAttributesChanged() { + when(attributesMock.hasDifference(userMock)).thenReturn(true); + + sut.syncUser(identityMock, attributesMock); + + verify(attributesMock).syncUser(userMock); + } + + @Test + public void shouldUpdateWhenUserAttributesChanged() { + when(attributesMock.hasDifference(userMock)).thenReturn(true); + + sut.syncUser(identityMock, attributesMock); + + verify(userManagerMock).updateUser(userMock); + } + + @Test + public void shouldNotUpdateUserWhenAttributesNotChanged() { + when(attributesMock.hasDifference(userMock)).thenReturn(false); + + sut.syncUser(identityMock, attributesMock); + + verify(userManagerMock, never()).updateUser(userMock); + } + + private class TestableShibbolethManagerImpl extends ShibbolethManagerImpl { + + @Override + protected ShibbolethAdvanceOrderInput getShibbolethAdvanceOrderInput() { + return advanceOrderInputMock; + } + + } +} diff --git a/src/test/java/org/olat/shibboleth/util/ShibbolethAttributeTest.java b/src/test/java/org/olat/shibboleth/util/ShibbolethAttributeTest.java deleted file mode 100644 index 00059e003b0826001e036890bc0a00e2950a9bef..0000000000000000000000000000000000000000 --- a/src/test/java/org/olat/shibboleth/util/ShibbolethAttributeTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ -package org.olat.shibboleth.util; - - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -import java.io.UnsupportedEncodingException; - - -import org.junit.Test; - - -/** - * Description:<br> - * TODO: patrick Class Description for MultivalueAttributeTest - * - * <P> - * Initial Date: Oct 27, 2010 <br> - * @author patrick - */ -public class ShibbolethAttributeTest { - - - private static final String ATTR_NAME = "InstitutionalEmail"; - private static final String LEARNER = "learner.ulrich@test.com"; - private static final String AUTHOR ="author.ernest@mailbox.com"; - private static final String ADMIN = "administrator.system@provider.com"; - private static final String MULTIVALUE_SEP =";"; - - private static final String MULTIVALUE_VALID = createMultivalueString(LEARNER,AUTHOR,ADMIN); - private static final String MULTIVALUE_INVALID_EMPTY = ""; - - private static final String SINGLEVALUE_VALID = LEARNER; - - - - @Test - public void multivalueAttributeWithEmails(){ - ShibbolethAttribute multivalueAttrValid = new ShibbolethAttribute(ATTR_NAME, MULTIVALUE_VALID); - String[] values = multivalueAttrValid.getValues(); - assertNotNull("contains three values", values); - assertEquals(3, values.length); - assertEquals(LEARNER, values[0]); - assertEquals(AUTHOR, values[1]); - assertEquals(ADMIN, values[2]); - - assertEquals(LEARNER, multivalueAttrValid.getFirstValue()); - } - - @Test(expected=IllegalArgumentException.class) - public void multivalueAttributeWithEmptyString(){ - new ShibbolethAttribute(ATTR_NAME, MULTIVALUE_INVALID_EMPTY); - } - - @Test - public void singlevalueAttribute(){ - ShibbolethAttribute singleAttrValid = new ShibbolethAttribute(ATTR_NAME, SINGLEVALUE_VALID); - String[] values = singleAttrValid.getValues(); - assertNotNull("contains one value", values); - assertEquals(1, values.length); - assertEquals(LEARNER, values[0]); - assertEquals(LEARNER, singleAttrValid.getFirstValue()); - } - - - @Test - public void multivalueAttributeWith8859String(){ - try { - String rawRequestValue = new String(MULTIVALUE_VALID.getBytes("ISO-8859-1")); - ShibbolethAttribute fromRequestShibbAttribute = ShibbolethAttribute.createFromUserRequestValue(ATTR_NAME, rawRequestValue); - String[] values = fromRequestShibbAttribute.getValues(); - assertNotNull("contains three values",values); - - assertEquals(3, values.length); - assertEquals(LEARNER, values[0]); - assertEquals(AUTHOR, values[1]); - assertEquals(ADMIN, values[2]); - - assertEquals(LEARNER, fromRequestShibbAttribute.getFirstValue()); - - } catch (UnsupportedEncodingException e) { - fail(e.toString()); - } - } - - private static String createMultivalueString(String... values) { - String retVal = values[0]+ MULTIVALUE_SEP; - for (int i = 1; i < values.length; i++) { - retVal = retVal + values[i] + MULTIVALUE_SEP; - } - return retVal; - } - -} diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index 3885804edc03b3d74deb9fe6f6af691a4ea89672..787bc6b3cfa2a1d4c8c040b3012d082387e2b9cb 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -20,7 +20,7 @@ * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. +* under the Apache 2.0 license as the original file. * <p> */ package org.olat.test; @@ -40,7 +40,7 @@ package org.olat.test; import org.junit.runner.RunWith; import org.junit.runners.Suite; - + @RunWith(Suite.class) @Suite.SuiteClasses({ org.olat.core.util.i18n.I18nTest.class, @@ -181,6 +181,7 @@ import org.junit.runners.Suite; org.olat.modules.lecture.manager.ReasonDAOTest.class, org.olat.modules.lecture.manager.LectureBlockReminderDAOTest.class, org.olat.modules.lecture.manager.RepositoryEntryLectureConfigurationDAOTest.class, + org.olat.modules.lecture.manager.LectureBlockAuditLogDAOTest.class, org.olat.modules.reminder.ReminderModuleTest.class, org.olat.modules.reminder.manager.ReminderDAOTest.class, org.olat.modules.reminder.manager.ReminderRuleEngineTest.class, @@ -223,6 +224,7 @@ import org.junit.runners.Suite; org.olat.ims.qti21.pool.QTI12To21HtmlHandlerTest.class, org.olat.ims.qti21.pool.QTI21QPoolServiceProviderTest.class, org.olat.ims.qti21.repository.handlers.QTI21AssessmentTestHandlerTest.class, + org.olat.ims.qti21.model.xml.Onyx38ToQtiWorksAssessementItemsTest.class, org.olat.ims.qti21.model.xml.OnyxToQtiWorksAssessementItemsTest.class, org.olat.ims.qti21.model.xml.OnyxToQtiWorksAssessementTestsTest.class, org.olat.ims.qti21.model.xml.OpenOLATAssessementItemsTest.class, @@ -244,10 +246,10 @@ import org.junit.runners.Suite; org.olat.core.commons.services.mark.MarksTest.class, org.olat.test.SpringInitDestroyVerficationTest.class, //org.olat.course.statistic.weekly.TestWeeklyStatisticManager_fillGaps.class, don't know what it tests - org.olat.core.commons.services.commentAndRating.UserCommentsTest.class, - org.olat.core.commons.services.commentAndRating.UserRatingsDAOTest.class, + org.olat.core.commons.services.commentAndRating.manager.UserCommentsDAOTest.class, + org.olat.core.commons.services.commentAndRating.manager.UserRatingsDAOTest.class, org.olat.course.auditing.UserNodeAuditManagerTest.class, - org.olat.shibboleth.util.ShibbolethAttributeTest.class, + org.olat.shibboleth.handler.SpringShibbolethAttributeHandlerFactoryTest.class, org.olat.core.CoreSpringFactoryTest.class, org.olat.portfolio.PortfolioModuleTest.class, org.olat.portfolio.EPArtefactManagerTest.class, @@ -289,6 +291,8 @@ import org.junit.runners.Suite; org.olat.restapi.I18nTest.class, org.olat.restapi.MyForumsTest.class, org.olat.restapi.LecturesBlocksTest.class, + org.olat.restapi.LecturesBlocksRootTest.class, + org.olat.restapi.LecturesBlockRollCallTest.class, org.olat.restapi.NotificationsTest.class, org.olat.restapi.NotificationsSubscribersTest.class, org.olat.restapi.RepositoryEntryLifecycleTest.class, @@ -313,22 +317,38 @@ import org.junit.runners.Suite; org.olat.resource.accesscontrol.ACOrderManagerTest.class, org.olat.resource.accesscontrol.ACTransactionManagerTest.class, org.olat.resource.accesscontrol.ACReservationDAOTest.class, + org.olat.resource.accesscontrol.provider.auto.manager.AdvanceOrderDAOTest.class, org.olat.core.util.vfs.version.VersionManagerTest.class, /** * Pure JUnit test without need of framework */ + org.olat.core.commons.services.commentAndRating.manager.CommentAndRatingServiceImplTest.class, + org.olat.core.gui.components.form.flexible.impl.elements.richText.TextModeTest.class, org.olat.core.gui.components.form.flexible.impl.elements.TextElementRendererTest.class, org.olat.modules.card2brain.manager.Card2BrainManagerImplTest.class, org.olat.modules.edubase.manager.EdubaseManagerImplTest.class, org.olat.modules.fo.WordCountTest.class, org.olat.modules.webFeed.manager.FeedManagerImplTest.class, org.olat.modules.webFeed.manager.RomeFeedFetcherTest.class, + org.olat.resource.accesscontrol.provider.auto.manager.AutoAccessManagerImplTest.class, + org.olat.resource.accesscontrol.provider.auto.manager.ExternalIdHandlerTest.class, + org.olat.resource.accesscontrol.provider.auto.manager.ExternalRefHandlerTest.class, + org.olat.resource.accesscontrol.provider.auto.manager.IdentifierHandlerTest.class, + org.olat.resource.accesscontrol.provider.auto.manager.InputValidatorTest.class, + org.olat.resource.accesscontrol.provider.auto.manager.InternalIdHandlerTest.class, + org.olat.resource.accesscontrol.provider.auto.manager.SemicolonSplitterTest.class, + org.olat.shibboleth.manager.DifferenceCheckerTest.class, + org.olat.shibboleth.manager.ShibbolethAttributesTest.class, + org.olat.shibboleth.manager.ShibbolethManagerImplTest.class, + org.olat.shibboleth.handler.DoNothingHandlerTest.class, + org.olat.shibboleth.handler.FirstValueHandlerTest.class, + org.olat.shibboleth.handler.SchacGenderHandlerTest.class, /** - * + * * Place tests which load their own Spring context - * with @ContextConfiguration below the others as they may taint the + * with @ContextConfiguration below the others as they may taint the * cached Spring context - * + * * IMPORTANT: If you create mock spring contexts in the test source tree of olatcore and * you like to use them in olat3 you have to copy them to the test source tree of olat3 * as well as the tests on hudson run agains a jar version of olatcore where the test source diff --git a/src/test/java/org/olat/test/ArquillianDeployments.java b/src/test/java/org/olat/test/ArquillianDeployments.java index 5975d0153013439ef6f23008946ed3719a0405ff..9d1e2ebd0d243a2f1a120499d7e6808d903e75e2 100644 --- a/src/test/java/org/olat/test/ArquillianDeployments.java +++ b/src/test/java/org/olat/test/ArquillianDeployments.java @@ -47,7 +47,7 @@ public class ArquillianDeployments { public static final String WEBINF = "src/main/webapp/WEB-INF"; public static final String WEBINF_TOMCAT = "src/main/webapp-tomcat/WEB-INF"; public static final String TEST_RSRC = "src/test/resources"; - public static final String LIB_DIR = "target/openolat-lms-12.0-SNAPSHOT/WEB-INF/lib"; + public static final String LIB_DIR = "target/openolat-lms-12.2-SNAPSHOT/WEB-INF/lib"; public static WebArchive createDeployment() { return createDeployment("openolat.war", new HashMap<String,String>()); diff --git a/src/test/java/org/olat/test/JunitTestHelper.java b/src/test/java/org/olat/test/JunitTestHelper.java index 54119607a6fd01f0f324fa29fd6af2fda8e7966f..ee9b93f298ba7069a243d29f9239c45aefad4322 100644 --- a/src/test/java/org/olat/test/JunitTestHelper.java +++ b/src/test/java/org/olat/test/JunitTestHelper.java @@ -245,4 +245,26 @@ public class JunitTestHelper { } return re; } + + /** + * Deploy a course with only a single page. + * @param initialAuthor + * @return + */ + public static RepositoryEntry deployCourse(Identity initialAuthor, String displayname, File courseFile) { + String description = "A course"; + + RepositoryEntry re = null; + try { + RepositoryHandler courseHandler = RepositoryHandlerFactory.getInstance() + .getRepositoryHandler(CourseModule.getCourseTypeName()); + re = courseHandler.importResource(initialAuthor, null, displayname, description, true, Locale.ENGLISH, courseFile, null); + + ICourse course = CourseFactory.loadCourse(re); + CourseFactory.publishCourse(course, RepositoryEntry.ACC_USERS, false, initialAuthor, Locale.ENGLISH); + } catch (Exception e) { + log.error("", e); + } + return re; + } } diff --git a/src/test/java/org/olat/test/file_resources/GTA_course.zip b/src/test/java/org/olat/test/file_resources/GTA_course.zip new file mode 100644 index 0000000000000000000000000000000000000000..1e1dadbfb9a55800ba8715461d2d38a86a2f6a92 Binary files /dev/null and b/src/test/java/org/olat/test/file_resources/GTA_course.zip differ diff --git a/src/test/java/org/olat/user/UserManagerTest.java b/src/test/java/org/olat/user/UserManagerTest.java index 4cdb17fc8337f58b1abdc90acc2de4959d6daa45..7a3c3483c0337ea064fcf6beaf471f510f878747 100644 --- a/src/test/java/org/olat/user/UserManagerTest.java +++ b/src/test/java/org/olat/user/UserManagerTest.java @@ -121,6 +121,32 @@ public class UserManagerTest extends OlatTestCase { Assert.assertTrue(identities.contains(id2)); } + @Test + public void findUserKeyWithProperty() { + //create a user + Identity id = createUser(UUID.randomUUID().toString()); + dbInstance.commitAndCloseSession(); + + String institutionalEmail = id.getUser().getProperty(UserConstants.INSTITUTIONALEMAIL, null); + List<Long> identityKeys = userManager.findUserKeyWithProperty(UserConstants.INSTITUTIONALEMAIL, institutionalEmail); + Assert.assertNotNull(identityKeys); + Assert.assertEquals(1, identityKeys.size()); + Assert.assertEquals(id.getUser().getKey(), identityKeys.get(0)); + } + + @Test + public void findIdentitiesWithProperty() { + //create a user + Identity id = createUser(UUID.randomUUID().toString()); + dbInstance.commitAndCloseSession(); + + String institutionalEmail = id.getUser().getProperty(UserConstants.INSTITUTIONALEMAIL, null); + List<Identity> identities = userManager.findIdentitiesWithProperty(UserConstants.INSTITUTIONALEMAIL, institutionalEmail); + Assert.assertNotNull(identities); + Assert.assertEquals(1, identities.size()); + Assert.assertEquals(id, identities.get(0)); + } + private Identity createUser(String uuid) { String username = "createid-" + uuid; String email = username + "@frentix.com"; diff --git a/src/test/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexpTest.java b/src/test/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexpTest.java index c39d3d9230c1070af7f6d0b4c651c4c847ed2d6c..eb6ba5527b085090702c8f11fcdf04431a7477da 100644 --- a/src/test/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexpTest.java +++ b/src/test/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexpTest.java @@ -30,9 +30,11 @@ import org.junit.Test; */ public class UserNameAndPasswordSyntaxCheckerWithRegexpTest { + /** + * Min. 7 characters, one uppercase, one lowercase, one number + */ @Test - public void testCustom() { - //Min. 7 characters, one uppercase, one lowercase, one number + public void testCustomPasswordCheck_upperLowerCase_number() { UserNameAndPasswordSyntaxCheckerWithRegexp checker = new UserNameAndPasswordSyntaxCheckerWithRegexp(); checker.setPasswordRegExp("(?=^.{7,}$)((?=.*\\d)|(?=.*\\W+))(?![.\\n])(?=.*[A-Z])(?=.*[a-z]).*$"); @@ -41,4 +43,21 @@ public class UserNameAndPasswordSyntaxCheckerWithRegexpTest { Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanu#1"));//less than 7 characters Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanuunch"));//no number } + + /** + * Min. 8 characters, one uppercase, one lowercase, one number, one special character + */ + @Test + public void testCustomPasswordCheck_upperLowerCase_number_special() { + UserNameAndPasswordSyntaxCheckerWithRegexp checker = new UserNameAndPasswordSyntaxCheckerWithRegexp(); + checker.setPasswordRegExp("(?=^.{8,}$)((?=.*\\d)|(?=.*\\W+))(?![.\\n])(?=.*[A-Z])(?=.*[a-z])(?=.*[$@$!%*#?&]).*$"); + + Assert.assertTrue(checker.syntaxCheckOlatPassword("Kanu#010")); + Assert.assertTrue(checker.syntaxCheckOlatPassword("?Ryomou#010")); + + Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanuunc1")); + Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanu#10"));//less than 8 characters + Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanuunch"));//no number + Assert.assertFalse(checker.syntaxCheckOlatPassword("kanu8#10")); + } } diff --git a/src/test/profile/mysql/olat.local.properties b/src/test/profile/mysql/olat.local.properties index c022f509132bc3d9b479e00e6ede13fdfc0ec085..8a2a7d6d0383c890c64e3c5ebb9ddc01d091aec3 100644 --- a/src/test/profile/mysql/olat.local.properties +++ b/src/test/profile/mysql/olat.local.properties @@ -73,4 +73,7 @@ group.accept.membership.users=false group.accept.membership.authors=false group.accept.membership.usermanagers=false group.accept.membership.groupmanagers=false -group.accept.membership.administrators=false \ No newline at end of file +group.accept.membership.administrators=false + +#make sure the test for QTI 1.2 works +qti12.create.resources.enabled=true \ No newline at end of file diff --git a/src/test/profile/oracle/olat.local.properties b/src/test/profile/oracle/olat.local.properties index cf453bf3a8bf1c5b7b9a3509330741bbb3b9d021..84074f207532f031c6d94b22cc79ed59b6a541eb 100644 --- a/src/test/profile/oracle/olat.local.properties +++ b/src/test/profile/oracle/olat.local.properties @@ -59,4 +59,7 @@ group.accept.membership.users=false group.accept.membership.authors=false group.accept.membership.usermanagers=false group.accept.membership.groupmanagers=false -group.accept.membership.administrators=false \ No newline at end of file +group.accept.membership.administrators=false + +#make sure the test for QTI 1.2 works +qti12.create.resources.enabled=true \ No newline at end of file diff --git a/src/test/profile/postgresql/olat.local.properties b/src/test/profile/postgresql/olat.local.properties index 6afe2357d840e0c4b612551360c2e858132c43d3..94c154777bfb6bbf2de0515eccf21dc858f23d47 100644 --- a/src/test/profile/postgresql/olat.local.properties +++ b/src/test/profile/postgresql/olat.local.properties @@ -74,4 +74,7 @@ group.accept.membership.users=false group.accept.membership.authors=false group.accept.membership.usermanagers=false group.accept.membership.groupmanagers=false -group.accept.membership.administrators=false \ No newline at end of file +group.accept.membership.administrators=false + +#make sure the test for QTI 1.2 works +qti12.create.resources.enabled=true \ No newline at end of file diff --git a/src/test/resources/arquillian.xml b/src/test/resources/arquillian.xml index 7a01481e7b1580ab1e8b8f14d60fd7eb453b5ba6..43459c8b238c2bac452a7ca7038be478ce6096ec 100644 --- a/src/test/resources/arquillian.xml +++ b/src/test/resources/arquillian.xml @@ -23,9 +23,9 @@ <extension qualifier="webdriver"> <property name="browser">chrome</property> <property name="dimensions">1024x800</property> - <!-- + <!-- <property name="downloadBinaries">no</property> - <property name="chromeDriverBinary">target/drone/e3f9380ecadad5a28982e841b1b31f90/chromedriver</property> + <property name="chromeDriverBinary">target/drone/b77c9c71b52302fcfe6b40dcd143f1d0/chromedriver</property> <property name="firefoxDriverBinary">target/drone/30f3fdc84d76c53de2916008a889d26f/geckodriver</property> --> <property name="firefoxUserPreferences">src/test/profile/firefox/prefs.js</property> diff --git a/src/test/resources/org/olat/commons/calendar/Refresh.ics b/src/test/resources/org/olat/commons/calendar/Refresh.ics new file mode 100644 index 0000000000000000000000000000000000000000..ab25b01e827726b8690db9c21c218f38e69d18ba --- /dev/null +++ b/src/test/resources/org/olat/commons/calendar/Refresh.ics @@ -0,0 +1,18 @@ +BEGIN:VCALENDAR +PRODID:-//Ben Fortuna//iCal4j 1.0//EN +VERSION:2.0 +CALSCALE:GREGORIAN +REFRESH-INTERVAL;VALUE=DURATION:PT6H +BEGIN:VEVENT +DTSTAMP:20170717T125726Z +DTSTART;TZID=Europe/Zurich:20170331T000000 +DTEND;TZID=Europe/Zurich:20170331T000000 +SUMMARY:Ikki lectures 1.1 +UID:2f784cbc-1f19-4b49-971a-a7c14555dc19 +CLASS:PRIVATE +LOCATION: +DESCRIPTION:Second lesson +X-OLAT-MANAGED:all +X-OLAT-EXTERNAL-ID:lecture-block-202604544-6 +END:VEVENT +END:VCALENDAR diff --git a/src/test/resources/org/olat/commons/calendar/manager/Fullday_ical.ics b/src/test/resources/org/olat/commons/calendar/manager/Fullday_ical.ics new file mode 100644 index 0000000000000000000000000000000000000000..1c404b552caadcf6cabeb20bc2ed52033553b01e --- /dev/null +++ b/src/test/resources/org/olat/commons/calendar/manager/Fullday_ical.ics @@ -0,0 +1,68 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +VERSION:2.0 +X-WR-CALNAME:Test +PRODID:-//Apple Inc.//Mac OS X 10.12.6//EN +X-APPLE-CALENDAR-COLOR:#1BADF8 +X-WR-TIMEZONE:Europe/Zurich +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Europe/Zurich +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +DTSTART:19810329T020000 +TZNAME:UTC+2 +TZOFFSETTO:+0200 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +DTSTART:19961027T030000 +TZNAME:UTC+1 +TZOFFSETTO:+0100 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20170921T093443Z +UID:14C0ACCD-AC0B-4B10-A448-0BF129492091 +DTEND;VALUE=DATE:20170919 +TRANSP:TRANSPARENT +X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC +SUMMARY:Fullday +DTSTART;VALUE=DATE:20170918 +DTSTAMP:20170921T134739Z +SEQUENCE:0 +BEGIN:VALARM +X-WR-ALARMUID:1A664771-C654-4662-8E4E-F7ABDC32CBCD +UID:1A664771-C654-4662-8E4E-F7ABDC32CBCD +TRIGGER:-PT15H +ATTACH;VALUE=URI:Basso +X-APPLE-LOCAL-DEFAULT-ALARM:TRUE +ACTION:AUDIO +X-APPLE-DEFAULT-ALARM:TRUE +END:VALARM +END:VEVENT +BEGIN:VEVENT +CREATED:20170921T134346Z +UID:C562E736-DCFF-4002-9E5B-77D891D4A322 +DTEND;TZID=Europe/Zurich:20170919T235900 +TRANSP:OPAQUE +X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC +SUMMARY:Long day +DTSTART;TZID=Europe/Zurich:20170919T000000 +DTSTAMP:20170921T134745Z +SEQUENCE:0 +END:VEVENT +BEGIN:VEVENT +CREATED:20170921T134625Z +UID:EFE10508-15B0-4FCE-A258-37BA642B760D +DTEND;TZID=Europe/Zurich:20170921T010000 +TRANSP:OPAQUE +X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC +SUMMARY:24Hour but 2 days +DTSTART;TZID=Europe/Zurich:20170920T010000 +DTSTAMP:20170921T134754Z +SEQUENCE:0 +END:VEVENT +END:VCALENDAR diff --git a/src/test/resources/org/olat/commons/calendar/manager/Fullday_outlook.ics b/src/test/resources/org/olat/commons/calendar/manager/Fullday_outlook.ics new file mode 100644 index 0000000000000000000000000000000000000000..c9df5c455f9be709bda40b0017f8c4815079510b --- /dev/null +++ b/src/test/resources/org/olat/commons/calendar/manager/Fullday_outlook.ics @@ -0,0 +1,42 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +PRODID:Microsoft Exchange Server 2010 +VERSION:2.0 +X-WR-CALNAME:MFLVFL_17 +BEGIN:VTIMEZONE +TZID:W. Europe Standard Time +BEGIN:STANDARD +DTSTART:16010101T030000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +DESCRIPTION:Werbung_2016\nDistribution_2016\nMarketing_2015_2016\nVerkaufsplanung_2016\nNur AD Rechtskunde_2015_2016\n\n\n +SUMMARY:VFL_17_Abgabetermin +DTSTART;TZID=W. Europe Standard Time:20171004T000000 +DTEND;TZID=W. Europe Standard Time:20171005T000000 +UID:040000008200E00074C5B7101A82E00800000000002428D0D920D301000000000000000010000000858708CB47EBDE45AE4CFBD30388C9B6 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20170921T085012Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +LOCATION: +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:FREE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +END:VCALENDAR \ No newline at end of file