From b80fb2bf65b78b26650169df5ccd08c80a3b56b0 Mon Sep 17 00:00:00 2001 From: uhensler <urs.hensler@frentix.com> Date: Mon, 2 Mar 2020 13:45:36 +0100 Subject: [PATCH] OO-4241: Enable course element "Wiki" in learning path course --- .../collaboration/CollaborationTools.java | 3 +- .../nodes/wiki/WikiAssessmentHandler.java | 40 +++++++++ .../course/nodes/wiki/WikiEditController.java | 4 +- .../wiki/WikiLearningPathNodeHandler.java | 80 +++++++++++++++++ .../course/nodes/wiki/WikiRunController.java | 17 +++- .../run/navigation/NavigationHandler.java | 4 + .../wiki/DryRunAssessmentProvider.java | 52 +++++++++++ .../wiki/PersistingAssessmentProvider.java | 75 ++++++++++++++++ src/main/java/org/olat/modules/wiki/Wiki.java | 86 +++++++------------ .../modules/wiki/WikiAssessmentProvider.java | 36 ++++++++ .../olat/modules/wiki/WikiMainController.java | 61 ++++++++++--- .../org/olat/modules/wiki/WikiManager.java | 19 +--- ...PageChangeOrCreateNotificationHandler.java | 5 +- .../org/olat/modules/wiki/WikiToCPExport.java | 11 ++- .../olat/repository/handlers/WikiHandler.java | 7 +- 15 files changed, 406 insertions(+), 94 deletions(-) create mode 100644 src/main/java/org/olat/course/nodes/wiki/WikiAssessmentHandler.java create mode 100644 src/main/java/org/olat/course/nodes/wiki/WikiLearningPathNodeHandler.java create mode 100644 src/main/java/org/olat/modules/wiki/DryRunAssessmentProvider.java create mode 100644 src/main/java/org/olat/modules/wiki/PersistingAssessmentProvider.java create mode 100644 src/main/java/org/olat/modules/wiki/WikiAssessmentProvider.java diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java index 7bebf36f6c8..d44dc60d21f 100644 --- a/src/main/java/org/olat/collaboration/CollaborationTools.java +++ b/src/main/java/org/olat/collaboration/CollaborationTools.java @@ -110,6 +110,7 @@ import org.olat.modules.portfolio.PortfolioService; import org.olat.modules.portfolio.PortfolioV2Module; import org.olat.modules.portfolio.manager.BinderUserInformationsDAO; import org.olat.modules.portfolio.ui.BinderController; +import org.olat.modules.wiki.DryRunAssessmentProvider; import org.olat.modules.wiki.WikiManager; import org.olat.modules.wiki.WikiSecurityCallback; import org.olat.modules.wiki.WikiSecurityCallbackImpl; @@ -521,7 +522,7 @@ public class CollaborationTools implements Serializable { initialPage = initialPage.substring(0, initialPage.length() - 2); } } - return WikiManager.getInstance().createWikiMainController(ureq, wControl, ores, callback, initialPage); + return WikiManager.getInstance().createWikiMainController(ureq, wControl, ores, callback, DryRunAssessmentProvider.create(), initialPage); } /** diff --git a/src/main/java/org/olat/course/nodes/wiki/WikiAssessmentHandler.java b/src/main/java/org/olat/course/nodes/wiki/WikiAssessmentHandler.java new file mode 100644 index 00000000000..3750ed75997 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/wiki/WikiAssessmentHandler.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.course.nodes.wiki; + +import org.olat.course.learningpath.LearningPathOnlyAssessmentHandler; +import org.olat.course.nodes.WikiCourseNode; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 28.02.2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Service +public class WikiAssessmentHandler extends LearningPathOnlyAssessmentHandler { + + @Override + public String acceptCourseNodeType() { + return WikiCourseNode.TYPE; + } + +} diff --git a/src/main/java/org/olat/course/nodes/wiki/WikiEditController.java b/src/main/java/org/olat/course/nodes/wiki/WikiEditController.java index 3f2ac3d52a4..1a736b7e487 100644 --- a/src/main/java/org/olat/course/nodes/wiki/WikiEditController.java +++ b/src/main/java/org/olat/course/nodes/wiki/WikiEditController.java @@ -56,6 +56,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.tree.CourseEditorTreeModel; import org.olat.fileresource.types.WikiResource; import org.olat.modules.ModuleConfiguration; +import org.olat.modules.wiki.DryRunAssessmentProvider; import org.olat.modules.wiki.WikiMainController; import org.olat.modules.wiki.WikiManager; import org.olat.modules.wiki.WikiSecurityCallback; @@ -252,7 +253,8 @@ public class WikiEditController extends ActivateableTabbableDefaultController im CourseEnvironment cenv = course.getCourseEnvironment(); SubscriptionContext subsContext = WikiManager.createTechnicalSubscriptionContextForCourse(cenv, wikiCourseNode); WikiSecurityCallback callback = new WikiSecurityCallbackImpl(null, isAdministrator, false, false, isResourceOwner, subsContext); - wikiCtr = WikiManager.getInstance().createWikiMainController(ureq, getWindowControl(), re.getOlatResource(), callback, null); + wikiCtr = WikiManager.getInstance().createWikiMainController(ureq, getWindowControl(), re.getOlatResource(), + callback, DryRunAssessmentProvider.create(), null); cmcWikiCtr = new CloseableModalController(getWindowControl(), translate("command.close"), wikiCtr.getInitialComponent()); listenTo(cmcWikiCtr); cmcWikiCtr.activate(); diff --git a/src/main/java/org/olat/course/nodes/wiki/WikiLearningPathNodeHandler.java b/src/main/java/org/olat/course/nodes/wiki/WikiLearningPathNodeHandler.java new file mode 100644 index 00000000000..ab1e8c47053 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/wiki/WikiLearningPathNodeHandler.java @@ -0,0 +1,80 @@ +/** + * <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.wiki; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.course.learningpath.LearningPathConfigs; +import org.olat.course.learningpath.LearningPathEditConfigs; +import org.olat.course.learningpath.LearningPathNodeHandler; +import org.olat.course.learningpath.model.ModuleLearningPathConfigs; +import org.olat.course.learningpath.ui.LearningPathNodeConfigController; +import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.WikiCourseNode; +import org.olat.repository.RepositoryEntry; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 28.02.2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Service +public class WikiLearningPathNodeHandler implements LearningPathNodeHandler { + + private static final LearningPathEditConfigs EDIT_CONFIGS = LearningPathEditConfigs.builder() + .enableNodeVisited() + .enableConfirmed() + .build(); + + @Override + public String acceptCourseNodeType() { + return WikiCourseNode.TYPE; + } + + @Override + public boolean isSupported() { + return true; + } + + @Override + public LearningPathConfigs getConfigs(CourseNode courseNode) { + return new ModuleLearningPathConfigs(courseNode.getModuleConfiguration(), true); + } + + @Override + public Controller createConfigEditController(UserRequest ureq, WindowControl wControl, RepositoryEntry courseEntry, + CourseNode courseNode) { + return new LearningPathNodeConfigController(ureq, wControl, courseEntry, courseNode, EDIT_CONFIGS); + } + + @Override + public LearningPathEditConfigs getEditConfigs() { + return EDIT_CONFIGS; + } + + @Override + public void onMigrated(CourseNode courseNode) { + // + } + +} diff --git a/src/main/java/org/olat/course/nodes/wiki/WikiRunController.java b/src/main/java/org/olat/course/nodes/wiki/WikiRunController.java index 16e5eecb6af..9aa48357146 100644 --- a/src/main/java/org/olat/course/nodes/wiki/WikiRunController.java +++ b/src/main/java/org/olat/course/nodes/wiki/WikiRunController.java @@ -56,7 +56,10 @@ 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.ModuleConfiguration; +import org.olat.modules.wiki.DryRunAssessmentProvider; +import org.olat.modules.wiki.PersistingAssessmentProvider; import org.olat.modules.wiki.Wiki; +import org.olat.modules.wiki.WikiAssessmentProvider; import org.olat.modules.wiki.WikiMainController; import org.olat.modules.wiki.WikiManager; import org.olat.modules.wiki.WikiReadOnlySecurityCallback; @@ -91,13 +94,13 @@ public class WikiRunController extends BasicController implements Activateable2 addLoggingResourceable(LoggingResourceable.wrap(wikiCourseNode)); //get repository entry in "strict" mode - RepositoryEntry re = WikiEditController.getWikiRepoReference(config, true); + RepositoryEntry wikiEntry = WikiEditController.getWikiRepoReference(config, true); //check role UserSession usess = ureq.getUserSession(); boolean isAdmininstrator = userCourseEnv.isAdmin(); boolean isGuestOnly = usess.getRoles().isGuestOnly(); - boolean isResourceOwner = isAdmininstrator || repositoryService.hasRole(getIdentity(), re, GroupRoles.owner.name()); + boolean isResourceOwner = isAdmininstrator || repositoryService.hasRole(getIdentity(), wikiEntry, GroupRoles.owner.name()); // Check for jumping to certain wiki page BusinessControl bc = wControl.getBusinessControl(); @@ -105,12 +108,18 @@ public class WikiRunController extends BasicController implements Activateable2 SubscriptionContext subsContext = WikiManager.createTechnicalSubscriptionContextForCourse(courseEnv, wikiCourseNode); WikiSecurityCallback callback; + WikiAssessmentProvider assessmentProvider; if(userCourseEnv.isCourseReadOnly()) { callback = new WikiReadOnlySecurityCallback(isGuestOnly, (isAdmininstrator || isResourceOwner)); + assessmentProvider = DryRunAssessmentProvider.create(); } else { callback = new WikiSecurityCallbackImpl(ne, isAdmininstrator, isGuestOnly, false, isResourceOwner, subsContext); + assessmentProvider = userCourseEnv.isParticipant() + ? PersistingAssessmentProvider.create(wikiEntry, getIdentity()) + : DryRunAssessmentProvider.create(); } + if ( ce != null ) { //jump to a certain context OLATResourceable ores = ce.getOLATResourceable(); String typeName = ores.getResourceableTypeName(); @@ -118,9 +127,9 @@ public class WikiRunController extends BasicController implements Activateable2 if(page.endsWith(":0")) { page = page.substring(0, page.length() - 2); } - wikiCtr = WikiManager.getInstance().createWikiMainController(ureq, wControl, re.getOlatResource(), callback, page); + wikiCtr = WikiManager.getInstance().createWikiMainController(ureq, wControl, wikiEntry.getOlatResource(), callback, assessmentProvider, page); } else { - wikiCtr = WikiManager.getInstance().createWikiMainController(ureq, wControl, re.getOlatResource(), callback, null); + wikiCtr = WikiManager.getInstance().createWikiMainController(ureq, wControl, wikiEntry.getOlatResource(), callback, assessmentProvider, null); } listenTo(wikiCtr); diff --git a/src/main/java/org/olat/course/run/navigation/NavigationHandler.java b/src/main/java/org/olat/course/run/navigation/NavigationHandler.java index 52328bee697..d5368bf3906 100644 --- a/src/main/java/org/olat/course/run/navigation/NavigationHandler.java +++ b/src/main/java/org/olat/course/run/navigation/NavigationHandler.java @@ -68,6 +68,7 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.CourseNodeFactory; import org.olat.course.nodes.STCourseNode; import org.olat.course.nodes.cp.CPRunController; +import org.olat.course.nodes.wiki.WikiRunController; import org.olat.course.run.userview.CourseTreeNode; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.VisibilityFilter; @@ -227,6 +228,9 @@ public class NavigationHandler implements Disposable { if(subtreemodelListener != currentNodeController) { if(subtreemodelListener instanceof CPRunController) { nrcr = ((CPRunController)subtreemodelListener).createNodeRunConstructionResult(ureq, selTN.getIdent()); + } else + if(subtreemodelListener instanceof WikiRunController) { + nrcr = ((WikiRunController)subtreemodelListener).createNodeRunConstructionResult(); } else { nrcr = new NodeRunConstructionResult((Controller)subtreemodelListener); } diff --git a/src/main/java/org/olat/modules/wiki/DryRunAssessmentProvider.java b/src/main/java/org/olat/modules/wiki/DryRunAssessmentProvider.java new file mode 100644 index 00000000000..9f4c0b04631 --- /dev/null +++ b/src/main/java/org/olat/modules/wiki/DryRunAssessmentProvider.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.modules.wiki; + +import org.olat.modules.assessment.model.AssessmentEntryStatus; + +/** + * + * Initial date: 2 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class DryRunAssessmentProvider implements WikiAssessmentProvider { + + private static final WikiAssessmentProvider INSTANCE = new DryRunAssessmentProvider(); + + public static final WikiAssessmentProvider create() { + return INSTANCE; + } + + private DryRunAssessmentProvider() { + // + } + + @Override + public void setStatusDone(String pageId) { + // + } + + @Override + public AssessmentEntryStatus getStatus(String pageId) { + return null; + } + +} diff --git a/src/main/java/org/olat/modules/wiki/PersistingAssessmentProvider.java b/src/main/java/org/olat/modules/wiki/PersistingAssessmentProvider.java new file mode 100644 index 00000000000..8330bdef120 --- /dev/null +++ b/src/main/java/org/olat/modules/wiki/PersistingAssessmentProvider.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.modules.wiki; + +import java.util.Map; +import java.util.stream.Collectors; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.id.Identity; +import org.olat.modules.assessment.AssessmentEntry; +import org.olat.modules.assessment.AssessmentService; +import org.olat.modules.assessment.model.AssessmentEntryStatus; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 28 Feb 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class PersistingAssessmentProvider implements WikiAssessmentProvider { + + private final Identity identity; + private final RepositoryEntry wikiEntry; + + private Map<String, AssessmentEntryStatus> pageIdToStatus; + + private AssessmentService assessmentService; + + public static final WikiAssessmentProvider create(RepositoryEntry wikiEntry, Identity identity) { + return new PersistingAssessmentProvider(wikiEntry, identity); + } + + private PersistingAssessmentProvider(RepositoryEntry wikiEntry, Identity identity) { + this.identity = identity; + this.wikiEntry = wikiEntry; + this.assessmentService = CoreSpringFactory.getImpl(AssessmentService.class); + this.pageIdToStatus = assessmentService.loadAssessmentEntriesByAssessedIdentity(identity, wikiEntry).stream() + .filter(ae -> ae.getSubIdent() != null && ae.getAssessmentStatus() != null) + .collect(Collectors.toMap(AssessmentEntry::getSubIdent, AssessmentEntry::getAssessmentStatus)); + } + + @Override + public void setStatusDone(String pageId) { + AssessmentEntry assessmentEntry = assessmentService.getOrCreateAssessmentEntry(identity, null, wikiEntry, pageId, false, null); + if (!AssessmentEntryStatus.done.equals(assessmentEntry.getAssessmentStatus())) { + assessmentEntry.setAssessmentStatus(AssessmentEntryStatus.done); + assessmentService.updateAssessmentEntry(assessmentEntry); + pageIdToStatus.put(pageId, assessmentEntry.getAssessmentStatus()); + } + } + + @Override + public AssessmentEntryStatus getStatus(String pageId) { + return pageIdToStatus.get(pageId); + } + +} diff --git a/src/main/java/org/olat/modules/wiki/Wiki.java b/src/main/java/org/olat/modules/wiki/Wiki.java index 684fb357496..d35af5ae3a0 100644 --- a/src/main/java/org/olat/modules/wiki/Wiki.java +++ b/src/main/java/org/olat/modules/wiki/Wiki.java @@ -38,12 +38,13 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; +import java.util.function.Predicate; +import org.apache.logging.log4j.Logger; import org.jamwiki.utils.Utilities; import org.olat.core.CoreSpringFactory; import org.olat.core.logging.AssertException; import org.olat.core.logging.OLATRuntimeException; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.util.FileUtils; import org.olat.core.util.Formatter; @@ -378,74 +379,49 @@ public class Wiki implements WikiContainer, Serializable { return page; } - /** - * @see org.olat.core.commons.modules.wiki.WikiContainer#generatePageId(java.lang.String) - */ @Override public String generatePageId(String pageName) { if(log.isDebugEnabled()) log.debug("Generating page id from page name: "+pageName +" to id: "+WikiManager.generatePageId(pageName)); return WikiManager.generatePageId(pageName); } - /** - * @return a List of all pages in a wiki ordered by date - */ - protected List<WikiPage> getPagesByDate() { - ArrayList<WikiPage> pages = new ArrayList<>(wikiPages.values()); - Collections.sort(pages, WikiPageSort.MODTIME_ORDER); - return pages; + public List<WikiPage> getAllPages() { + return new ArrayList<>(wikiPages.values()); } - - /** - * @return a List containing all pages names of the wiki sorted alphabetically - */ - protected List<String> getListOfAllPageNames() { - ArrayList<WikiPage> pages = new ArrayList<>(wikiPages.values()); - ArrayList<String> pageNames = new ArrayList<>(pages.size()); - Collections.sort(pages, WikiPageSort.PAGENAME_ORDER); - for (Iterator<WikiPage> iter = pages.iterator(); iter.hasNext();) { - WikiPage page = iter.next(); - if (!page.getPageName().startsWith("O_")) { - pageNames.add(page.getPageName()); - } - } - return pageNames; + + public final static Predicate<WikiPage> REGULAR_PAGE_FILTER = + page -> !page.getPageName().startsWith("O_"); + + public List<WikiPage> getAllPagesWithContent() { + return getAllPagesWithContent(false); } - - /** - * - * @return a List of all pages in a wiki - */ - public List<WikiPage> getAllPagesWithContent() { - return getAllPagesWithContent(false); - } - - public List<WikiPage> getAllPagesWithContent(boolean includeSpecialPages) { - ArrayList<WikiPage> pages = new ArrayList<>(); - for (Iterator<String> keyes = wikiPages.keySet().iterator(); keyes.hasNext();) { - String pageId = keyes.next(); - WikiPage wikiPage = getPage(pageId); - // check if the page is a content page - if (includeSpecialPages) { + + public List<WikiPage> getAllPagesWithContent(boolean includeSpecialPages) { + ArrayList<WikiPage> pages = new ArrayList<>(); + for (Iterator<String> keyes = wikiPages.keySet().iterator(); keyes.hasNext();) { + String pageId = keyes.next(); + WikiPage wikiPage = getPage(pageId); + // check if the page is a content page + if (includeSpecialPages) { + if (wikiPage.getContent().equals("") ) { + // wikiPage has empty content => try to load content + if (!wikiPage.getPageName().startsWith("O_")) { + wikiPage = getPage(pageId, true); + } + } + pages.add(wikiPage); + } else { + if (!wikiPage.getPageName().startsWith("O_")) { if (wikiPage.getContent().equals("") ) { // wikiPage has empty content => try to load content - if (!wikiPage.getPageName().startsWith("O_")) { - wikiPage = getPage(pageId, true); - } - } - pages.add(wikiPage); - } else { - if (!wikiPage.getPageName().startsWith("O_")) { - if (wikiPage.getContent().equals("") ) { - // wikiPage has empty content => try to load content - wikiPage = getPage(pageId, true); - } - pages.add(wikiPage); + wikiPage = getPage(pageId, true); } + pages.add(wikiPage); } } - return pages; } + return pages; + } /** * FIXME:gs increase performance diff --git a/src/main/java/org/olat/modules/wiki/WikiAssessmentProvider.java b/src/main/java/org/olat/modules/wiki/WikiAssessmentProvider.java new file mode 100644 index 00000000000..0457946b328 --- /dev/null +++ b/src/main/java/org/olat/modules/wiki/WikiAssessmentProvider.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.wiki; + +import org.olat.modules.assessment.model.AssessmentEntryStatus; + +/** + * + * Initial date: 28 Feb 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface WikiAssessmentProvider { + + void setStatusDone(String pageId); + + public AssessmentEntryStatus getStatus(String pageId); + +} diff --git a/src/main/java/org/olat/modules/wiki/WikiMainController.java b/src/main/java/org/olat/modules/wiki/WikiMainController.java index e1984250c98..756fb037b51 100644 --- a/src/main/java/org/olat/modules/wiki/WikiMainController.java +++ b/src/main/java/org/olat/modules/wiki/WikiMainController.java @@ -28,14 +28,15 @@ package org.olat.modules.wiki; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.stream.Collectors; +import org.apache.logging.log4j.Logger; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.FolderEvent; import org.olat.core.commons.services.notifications.NotificationsManager; @@ -78,7 +79,6 @@ 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.logging.OLATRuntimeException; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.logging.activity.LearningResourceLoggingAction; import org.olat.core.logging.activity.OlatResourceableType; @@ -92,6 +92,7 @@ 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.assessment.model.AssessmentEntryStatus; import org.olat.modules.fo.Forum; import org.olat.modules.fo.ForumCallback; import org.olat.modules.fo.manager.ForumManager; @@ -167,6 +168,7 @@ public class WikiMainController extends BasicController implements CloneableCont private Dropdown wikiMenuDropdown, navigationDropdown, breadcrumpDropdown; private GenericTreeNode navMainPageNode, navAZNode, navChangesNode, wikiMenuNode; + private WikiAssessmentProvider assessmentProvider; public static final String ACTION_COMPARE = "compare"; public static final String ACTION_SHOW = "view.version"; @@ -196,13 +198,14 @@ public class WikiMainController extends BasicController implements CloneableCont private NotificationsManager notificationsManager; public WikiMainController(UserRequest ureq, WindowControl wControl, OLATResourceable ores, - WikiSecurityCallback securityCallback, String initialPageName) { + WikiSecurityCallback securityCallback, WikiAssessmentProvider assessmentProvider, String initialPageName) { super(ureq, wControl); this.wikiContainer = WikiManager.getInstance().getWikiRootContainer(ores); this.ores = ores; this.securityCallback = securityCallback; this.subsContext = securityCallback.getSubscriptionContext(); + this.assessmentProvider = assessmentProvider; WikiPage page = null; Wiki wiki = getWiki(); @@ -376,24 +379,35 @@ public class WikiMainController extends BasicController implements CloneableCont 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); + List<String> linkList = wiki.getAllPages().stream() + .filter(Wiki.REGULAR_PAGE_FILTER) + .map(WikiPage::getPageName) + .sorted(new WikiPageNameComparator(getLocale())) + .collect(Collectors.toList()); + editContent.contextPut("linkList", linkList); } private void updateWikiMenu(Wiki wiki) { - Collection<String> links = wiki.getListOfAllPageNames(); + List<WikiPage> pages = wiki.getAllPages().stream() + .filter(Wiki.REGULAR_PAGE_FILTER) + .sorted(WikiPageSort.PAGENAME_ORDER) + .collect(Collectors.toList()); + if (wikiMenuNode != null) { wikiMenuNode.removeAllChildren(); - for (String link : links) { + for (WikiPage page : pages) { + String link = page.getPageName(); String ident = "w" + Encoder.md5hash(link); GenericTreeNode menuItemNode = new GenericTreeNode(ident, link, link); + String cssClass = getNodeCssClass(page.getPageId()); + menuItemNode.setCssClass(cssClass); wikiMenuNode.addChild(menuItemNode); } } - + wikiMenuDropdown.removeAllComponents(); - for (String link : links) { + for (WikiPage page : pages) { + String link = page.getPageName(); Link menuLink = LinkFactory.createToolLink(link, "select-page", link, this); wikiMenuDropdown.addComponent(menuLink); } @@ -415,20 +429,24 @@ public class WikiMainController extends BasicController implements CloneableCont // Index String navMainItem = "nav-main-item-" + resId; navMainPageNode = new GenericTreeNode(navMainItem, translate("navigation.mainpage"), navMainItem); + navMainPageNode.setCssClass(getNodeDoneCssClass()); rootNode.addChild(navMainPageNode); // Wiki-Menu String wikiMenuTitle = translate("navigation.menu"); String wikiMenuItem = "menu-item-" + resId; wikiMenuNode = new GenericTreeNode(wikiMenuItem, wikiMenuTitle, wikiMenuItem); + wikiMenuNode.setCssClass(getNodeDoneCssClass()); rootNode.addChild(wikiMenuNode); String navAZItem = "nav-az-item-" + resId; navAZNode = new GenericTreeNode(navAZItem, translate("navigation.a-z"), navAZItem); + navAZNode.setCssClass(getNodeDoneCssClass()); rootNode.addChild(navAZNode); String navChangesItem = "nav-changes-item-" + resId; navChangesNode = new GenericTreeNode(navChangesItem, translate("navigation.changes"), navChangesItem); + navChangesNode.setCssClass(getNodeDoneCssClass()); rootNode.addChild(navChangesNode); updateWikiMenu(wiki); @@ -439,6 +457,22 @@ public class WikiMainController extends BasicController implements CloneableCont navigationContent.contextPut("navigationEnabled", Boolean.FALSE); return wikiMenuModel; } + + private String getNodeCssClass(String pageId) { + AssessmentEntryStatus status = assessmentProvider.getStatus(pageId); + return getNodeCssClass(status); + } + + private String getNodeCssClass(AssessmentEntryStatus status) { + if (AssessmentEntryStatus.done.equals(status)) { + return getNodeDoneCssClass(); + } + return "o_lp_ready o_lp_not_in_sequence o_lp_contains_no_sequence"; + } + + private String getNodeDoneCssClass() { + return "o_lp_done o_lp_not_in_sequence o_lp_contains_no_sequence"; + } @Override public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { @@ -1169,7 +1203,7 @@ public class WikiMainController extends BasicController implements CloneableCont @Override public Controller cloneController(UserRequest ureq, WindowControl wControl) { - return WikiManager.getInstance().createWikiMainController(ureq, wControl, ores, securityCallback, null); + return WikiManager.getInstance().createWikiMainController(ureq, wControl, ores, securityCallback, null, null); } private void doReleaseEditLock() { @@ -1243,8 +1277,11 @@ public class WikiMainController extends BasicController implements CloneableCont OLATResourceable pageRes = OresHelper.createOLATResourceableInstanceWithoutCheck("path=" + page.getPageName(), 0l); addToHistory(ureq, pageRes, null); + + assessmentProvider.setStatusDone(page.getPageId()); + updateWikiMenu(getWiki()); } - + private void clearPortfolioLink() { navigationContent.put("portfolio-link", new Panel("empty")); } diff --git a/src/main/java/org/olat/modules/wiki/WikiManager.java b/src/main/java/org/olat/modules/wiki/WikiManager.java index 0fd33027076..208a0129550 100644 --- a/src/main/java/org/olat/modules/wiki/WikiManager.java +++ b/src/main/java/org/olat/modules/wiki/WikiManager.java @@ -42,13 +42,13 @@ import java.util.List; import java.util.Properties; import org.apache.commons.codec.binary.Base64; +import org.apache.logging.log4j.Logger; import org.olat.core.commons.services.notifications.SubscriptionContext; import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.WindowControl; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.AssertException; import org.olat.core.logging.OLATRuntimeException; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.logging.activity.LearningResourceLoggingAction; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; @@ -131,22 +131,11 @@ public class WikiManager { return instance; } - - // ---- begin controller factory ----- - /** @param ureq - * @param wControl - * @param ores either an OlatResourcable of an repository entry or of an BusinessGroup - * @param securityCallback a callback to evaluate the permissions - * @param initialPageName opens the wiki with an certain page, default is the index page if null is passed - * @param courseContext - a course context or null if used outside a course - * @param courseNodeContext - a courseNode context or null if used outside a course - */ - public WikiMainController createWikiMainController(UserRequest ureq, WindowControl wControl, OLATResourceable ores, WikiSecurityCallback securityCallback, String initialPageName) { - return new WikiMainController(ureq, wControl, ores, securityCallback, initialPageName); + public WikiMainController createWikiMainController(UserRequest ureq, WindowControl wControl, OLATResourceable ores, + WikiSecurityCallback securityCallback, WikiAssessmentProvider assessmentProvider, String initialPageName) { + return new WikiMainController(ureq, wControl, ores, securityCallback, assessmentProvider, initialPageName); } - // ---- end controller factory ----- - /** * @return the new created resource */ diff --git a/src/main/java/org/olat/modules/wiki/WikiPageChangeOrCreateNotificationHandler.java b/src/main/java/org/olat/modules/wiki/WikiPageChangeOrCreateNotificationHandler.java index 04c90c3cbca..6225d9288ce 100644 --- a/src/main/java/org/olat/modules/wiki/WikiPageChangeOrCreateNotificationHandler.java +++ b/src/main/java/org/olat/modules/wiki/WikiPageChangeOrCreateNotificationHandler.java @@ -29,6 +29,7 @@ import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.stream.Collectors; import org.apache.logging.log4j.Logger; import org.olat.basesecurity.BaseSecurityManager; @@ -137,7 +138,9 @@ public class WikiPageChangeOrCreateNotificationHandler implements NotificationsH } Wiki wiki = WikiManager.getInstance().getOrLoadWiki(ores); - final List<WikiPage> pages = wiki.getPagesByDate(); + List<WikiPage> pages = wiki.getAllPages().stream() + .sorted(WikiPageSort.MODTIME_ORDER) + .collect(Collectors.toList()); Translator translator = Util.createPackageTranslator(WikiPageChangeOrCreateNotificationHandler.class, locale); Translator forumTranslator = Util.createPackageTranslator(ForumNotificationsHandler.class, locale); diff --git a/src/main/java/org/olat/modules/wiki/WikiToCPExport.java b/src/main/java/org/olat/modules/wiki/WikiToCPExport.java index 368020e5160..eb0633017f8 100644 --- a/src/main/java/org/olat/modules/wiki/WikiToCPExport.java +++ b/src/main/java/org/olat/modules/wiki/WikiToCPExport.java @@ -31,6 +31,7 @@ import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.stream.Collectors; import org.jamwiki.parser.ParserDocument; import org.jamwiki.parser.ParserInput; @@ -97,7 +98,9 @@ public class WikiToCPExport { protected String createJsMappingContent(Wiki wiki) { StringBuilder sb = new StringBuilder(); - List<WikiPage> pages = wiki.getPagesByDate(); + List<WikiPage> pages = wiki.getAllPages().stream() + .sorted(WikiPageSort.MODTIME_ORDER) + .collect(Collectors.toList()); // create javascript assoz. array sb.append("var mappings = new Array();\n"); @@ -273,8 +276,10 @@ public class WikiToCPExport { // href="einleitung.html"> // <file href="einleitung.html" /> // </resource> - List<WikiPage> pageNames = wiki.getPagesByDate(); - for (WikiPage page :pageNames) { + List<WikiPage> pages = wiki.getAllPages().stream() + .sorted(WikiPageSort.MODTIME_ORDER) + .collect(Collectors.toList()); + for (WikiPage page : pages) { sb.append("<resource identifier=\"res_").append(page.getPageId()).append("\" type=\"text/html\" ").append("href=\""); sb.append(page.getPageId()).append(".html\">"); sb.append("<file href=\"").append(page.getPageId()).append(".html\" />"); diff --git a/src/main/java/org/olat/repository/handlers/WikiHandler.java b/src/main/java/org/olat/repository/handlers/WikiHandler.java index cf305098e72..6a582080b0a 100644 --- a/src/main/java/org/olat/repository/handlers/WikiHandler.java +++ b/src/main/java/org/olat/repository/handlers/WikiHandler.java @@ -60,6 +60,8 @@ import org.olat.course.assessment.manager.UserCourseInformationsManager; import org.olat.fileresource.FileResourceManager; import org.olat.fileresource.types.ResourceEvaluation; import org.olat.fileresource.types.WikiResource; +import org.olat.modules.wiki.PersistingAssessmentProvider; +import org.olat.modules.wiki.WikiAssessmentProvider; import org.olat.modules.wiki.WikiMainController; import org.olat.modules.wiki.WikiManager; import org.olat.modules.wiki.WikiModule; @@ -221,6 +223,7 @@ public class WikiHandler implements RepositoryHandler { final ContextEntry ce = bc.popLauncherContextEntry(); SubscriptionContext subsContext = new SubscriptionContext(res, WikiManager.WIKI_RESOURCE_FOLDER_NAME); final WikiSecurityCallback callback = new WikiSecurityCallbackImpl(null, isOLatAdmin, isGuestOnly, false, isResourceOwner, subsContext); + WikiAssessmentProvider assessmentProvider = PersistingAssessmentProvider.create(re, ureq.getIdentity()); return new RepositoryEntryRuntimeController(ureq, wControl, re, reSecurity, new RuntimeControllerCreator() { @@ -234,9 +237,9 @@ public class WikiHandler implements RepositoryHandler { OLATResourceable ores = ce.getOLATResourceable(); String typeName = ores.getResourceableTypeName(); String page = typeName.substring("page=".length()); - controller = new WikiMainController(uureq, wwControl, entry.getOlatResource(), callback, page); + controller = new WikiMainController(uureq, wwControl, entry.getOlatResource(), callback, assessmentProvider, page); } else { - controller = new WikiMainController(uureq, wwControl, entry.getOlatResource(), callback, null); + controller = new WikiMainController(uureq, wwControl, entry.getOlatResource(), callback, assessmentProvider, null); } return new OLATResourceableListeningWrapperController(uureq, wwControl, entry.getOlatResource(), controller, null, uureq.getIdentity()); } -- GitLab